SPA Development
for the
Server-Side Developer
By Abram Adams
@Abram_Adams
aadams@cfxchange.com
https://github.com/abramadams
http://cfml-slack.herokuapp.com/
Who Am I?
Overview
- Define what a SPA is (and when to build one)
-
Contrast traditional server-side vs client side concerns
- Session/State management
- Security - Client side vs server side security
- Downloading files
- Delivering static assets
- Development environments/Deployment
- SEO
What this talk is NOT
- Deep dive into a particular SPA framework
- Complete guide to building SPAs - we just cover specific areas that I've had gotchas
What is a SPA?
"...a web application or web site that fits on a single web page with the goal of providing a more fluid user experience akin to a desktop application" - Wikipedia
This is in contrast to traditional web apps that rely on the Request/Response paradigm in which every page is requested from the server.
Should I SPA?
When Should I?
- Boss/Client says you have to
- Building application vs content site
- Building desktop applications (i.e. via Electron)
- Building offline-first applications
- JS heavy websites that share common functionality across much of the site
- Real-time persistence
- Long-lived user interaction
The Old Way
Request/Response
The SPA Way
SPA Request/Response (Request 1)
SPA Request/Response (Request ++)
RESTFul API
WTF?
What is a RESTFul API?
“REST, or REpresentational State Transfer, is a method for computer programs to talk to each other over networks.” -- Adam Tuttle, REST Assured: A Pragmatic Approach to API Design
“It is a set of generalized conventions that make it easier for API-client developers to understand how to manage data over network protocols —like HTTP— with very little additional context and documentation” -- Adam Tuttle, REST Assured: A Pragmatic Approach to API Design
State
- Shopping Cart Contents
- User Profile
- Stored Actions
- Form State
- etc...
Request/Response
HTTP:/1.1 200 OK Set-Cookie: cfid=1803 Set-Cookie: cftoken=c95c2c0f0e62813d-39..
SPA Request/Response (Request ++)
So, how do we manage state?
Client-Side
- Memory (JavaScript variables)
- $rootScope, $scope, etc...
- window.myGlobalVar, etc...
- this.state.myVar, etc...
- LocalStorage
- SessionStorage
- IndexDB
- SQLite, etc...
- Cookies (though why?)
So... no server state?
Server-Side
- NOT IN SESSION SCOPE!!!
- Every request is a new "session", disable SessionManagement!
- Authentication/Authorization must happen every request
- Be careful to make sure this is fast!
- Every request must not rely on previous request(s)
- XHR calls can/will happen in random order!
Authentication
&&
Authorization
- Each Request is a New Session
- Cookies aren't passed on XHR requests
- Authentication Must Happen Each Request
- Authorization Must Happen Each Request
Authentication
"Authentication is the process of verifying who you are. When you log on to an PC with a user name and password you are authenticating." - ServerFault
"Authorization is the process of verifying that you have access to something. Gaining access to a resource (e.g. directory on a hard disk) because the permissions configured on it allow you access is authorization." - ServerFault
Authorization
Types of Authentication
-
Basic Authentication
Username/Password sent on every request- OK if over SSL
- Cannot invalidate session without changing password
- Cannot restrict/permit multiple devices
-
Token-Based Authentication
Username/Password sent on initial request, authorization token set on subsequent requests- More secure (tokens change often and are difficult to guess)
- Full control over session
- Full control over devices/multiple logins
Demo!
Demo!
Downloading Files
This used to be so easy
<cfheader name=“Content-disposition” value=“attachment;filename=#dafile#”>
<cfcontent file=“#dafile#” type=“application/pdf”>
function download(filename, text) {
var element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
element.setAttribute('download', filename);
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
// Start file download.
document.getElementById("dwn-btn").addEventListener("click", function(){
// Generate download of hello.txt file with some content
var text = document.getElementById("text-val").value;
var filename = "hello.txt";
download(filename, text);
}, false);
<a href="/assets/cf.pdf" download target="_self">
Download cf.Objective() Schedule
</a>
OR
<a href="http://myrestendpoint.com/download?filename=server.pdf"
download="server.pdf"
target="_self">
Download Server Details
</a>
// download photo using FileSaver.js
// https://github.com/eligrey/FileSaver.js/
photoService.downloadPhoto( formData ).then( function( data ) {
var blob = new Blob( [ data.data ], { 'type': "image/jpeg" } );
saveAs( blob, formData.fileName + '.jpg' );
} );
Static Assets
Your App is now a static asset
Development Environment
- Local Node.js server
- Gulp/Grunt/Webpack + Live Reload, BrowserSync, etc...
- Sublime, VS Code, Atom + Some Shell/Terminal
- App should have Prod/Dev environment variables (i.e. api urls, etc...)
Deployment
Deployment Considerations
- SERVER LAND: you change the code, deploy and your users instantly get the changes
- SPA LAND: your changes can get pushed, but the browser may decide not to download it. YOU HAVE TO EMPLOY A CACHE BUSTING STRATEGY
Deployment Considerations
- SERVER LAND: scaling horizontally meant duplicating complex server environments
- SPA LAND: easily deploy to many different servers or CDNs without the need for complex/expensive servers
Deployment Considerations
- SERVER LAND: frequent deployments can be snuck in without user noticing
- SPA LAND: every deploy requires a full app download/reload (unless using hot module or other lazy loading)
SEO
It doesn't just happen
- Meta data
- Descriptions
- Titles
- Keywords
- Images, etc..
- Indexing
https://prerender.io/
The End
@Abram_Adams
aadams@cfxchange.com
https://github.com/abramadams
http://cfml-slack.herokuapp.com/
SPA Development for the Server-Side Developer
By Abram Adams
SPA Development for the Server-Side Developer
- 813