Single-page applications builder with continuous integration, granular updates and loader.
S ingle P age A pplications builder with continuous integration, granular updates and loader.
The general idea is to calculate dependencies offline and then eagerly cache/load modules in predefined order. Also we can detect which files are changed and do partial updates.
Preferred module format is
- no async dependency resolution
- no AMD wrappers
- less moving parts and mutable state
- less data duplication and possible conflicts
- loader code is separate from application code
- loading progress is easy to visualize
All options are stored in config file. So the only command line parameter is a config file path.
spa -c spa.yaml
Config file is a
dict in YAML or JSON format with the following keys:
root(required) - path where the file search will start, may be relative to config file itself.
extensions(optional) - files to consider as modules,
[".js"] by default.
excludes(optional) - files to ignore, empty by default.
List may contains wildcards/globs, eg.
./something/**/test/*.js. Paths are relative to root path.
paths(optional) - path aliases to use during module name resolution.
root: "/testimonial/"paths:vendor: "./lib/contrib"
This allows to use module
/testimonial/lib/contrib/b.js from file
grab(optional) - do try grab all dependencies suppressing ExternalDependencyErrors.
Can walk inside
commonjs rules recursively. Default value is
hosting(required for web usage) - similar dict which specifies how to remap paths to URLs.
Keys - rules as in
excludes, where you can select path fragments in brackets,
values - URI format where selected fragments will be substitutes.
If you want files to be included in cache manifest, they need to match at least one pattern in
hosting as well.
./lib/app/main.js will be loaded
hosting_map(optional) - relative path to output hosting map file. Can be omitted.
Hosting map format:
loaders(optional) - rules which describe what module formats JS files use.
Keys - rules as in
excludes, values - format types. Available formats:
- cjs -
- amd -
- junk - module needs to mutate
- raw - local variables from module needs to be in
default_loader(optional) - loader for files not matched by loaders. Default value is
manifest(optional) - relative path to loader manifest. Can be omitted.
bundle(optional) - relative path where bundle will be stored. Bundle used at first run to speed up downloading. Can be omitted.
hash_func(optional) - has function to be used in
appcache generation process. Value may be
sha512. Default value is
md5. New hash function could be easily added as assets to builder. Hack into
Cakefile for mere information.
randomize_urls(optional) - this parameter to be transletad into loader thru
true loader will add some random characters to URLs for manifest and application files to suppress caching.
pretty(optional) - pretty-print manifest and other json files. Default is
print_roots(optional) - output list of root modules no one depends on. Default is
print_stats(optional) - output statistics about analyzed modules. Default is
index(optional) - relative path to bootstrap html file. Loader and its dependencies (but not app dependencies) will be baked into this file. Can be omitted.
appcache(optional) - relative path to HTML5 AppCache Manifest.
cached(optional) - paths to other files to include in appcache. URLs are remapped according to hosting dict.
assets(optional) - path to customizable builder templates
- appcache_template - template to generate
appcache. Can include
- index_template - template to generate
index. You can use
assetsto include them, except the
coding_func(optional) - dictionary that defines parameters of encoding function. Viable parameters depends on particular function. The only necessary parameter is
name which value may be
coding_func:name: aes-gcmpassword: babukaiter: 1000ks: 128ts: 128
coding_func) - same set of rules as in
hosting but used together with
coding_func to store encoded files.
Enabling encryption could possibly overwrite your source files if copying rules was not properly specified. Use this feature with caution. Ensure that you've commited changes into restorable repository before you build.
cache_file(optional) - path to cache-file. This option is also necessary for using some of
coding_func. To preserve incremental updates feature we have to query some data from previous builds. Default value is
.spacache. This path is relative to
root: "./testimonial/"index: index.htmlappcache: main.appcachemanifest: manifest.jsonpaths:vendor: "./lib/contrib"assets:index_template: /assets/index.tmplappcache_template: /assets/appcache.tmplhash_func: sha256cached:- /a.jshosting:"./(**/*.*)": "$1"hosting_map: hosting.jsonbundle: "./bundle.js"coding_func:name: aes-gcmpassword: babukaiter: 1000ks: 128ts: 128copying:"./lib/(**/*.js)": "./build/$1"grab: true
Read this book Single page apps in depth!
Other modules you should definitely look at:
Report new issues. I'm open for collaboration.
npm install git://github.com/Evgenus/spa.git#stable
spa├───bin executable builder file├───bower_components loader dependencies; installs with `bower`├───lib compiled builder files│ └───assets builder assets (templates, compiled loader, loader assets)│ ├───decode prepared decoding functions for using in loader│ ├───encode prepared encoding functions for using in builder│ └───hash wrapped and prepared hash-functions code├───node_modules builder dependencies; installs with `npm`├───src coffee-script source code│ ├───assets various assets templates and helpers sources│ ├───builder source code of builder│ ├───bootstrap source code of bootstrap code with default callbacks and UI visualization│ └───loader source code of loader└───tests tests for builder and loader
npm installbower install
Tests require devDependencies to be installed! Tests require
Selenium Standalone Server.
To subscribe for event you simply need to assign handler into loader instance.
loaderonEventName = /*....*/
load() - starts loading current version of hosted application.
Possible generated events:
NoManifest(error)- this event fires when there is no current version of application. Either the application is being started for the first time or previous download was unsuccessful. Usually
checkUpdatemethod should be called in the handler.
EvaluationStarted(manifest)- event fires when current version was found and about to be loaded. If handler returns
falsethen loaded will not perform any further actions and halts. Parameters:
manifest- manifest of current version as an object.
ModuleEvaluated(module)- event fires for each successfully loaded module. Parameters:
module- loaded module descriptor (as inside of manifest).
EvaluationError(module, error)- fires if there was an error during module loading. All further loading could not be performed and loader halts. Event
ApplicationReadywill not be fired. Parameters:
module- problem module descriptor (some fields may be absent);
error- occurred error(some frequent errors are strictly typed).
ApplicationReady(manifest)- event notifies host application about its successfully loading. Inside handler application could start working and intercept control. Parameters:
manifest- current manifest.
checkUpdate() - checks server for newer version of application.
false if process of checking or updating already has been started, otherwise
UpToDate(event, manifest)- event fires if latest version of application was already downloaded. Parameters:
manifest- cuurent manifest.
UpdateFound(event, manifest)- event occurs if a newer version of the application was found. Usually
startUpdateshould be called inside handler or user asked for confirmation before downloading new version files. Current version is assumed to be working at this time. Parameters:
event- the event object passed by browser as a result of the request;
manifest- the manifest of a new version.
UpdateFailed(event, error)- event occurs if for some of the reason a newer version could not be found or manifest of newer version is incorrect. It also occurs if current loader is outdated and not compatible with the new format of the manifest. Parameters:
event- the event object passed by browser as a result of the query (you can obtain network errors from it);
error- error arose during the analysis of the manifest of the newer version or downloading bundle (may be
startUpdate() - initialize downloading of the newer version of the application accordingly to previously downloaded manifest.
false if process of updating already has been started, otherwise
ModuleBeginDownload(module)- event fires when each module is about to be downloaded. Parameters:
module- module descriptor object from newer version manifest.
ModuleDownloadProgress(event, module)- fires when individual module download progress changed. Parameters:
event- browser event (downloaded bytes, etc);
module- descriptor of module being downloaded (contains total length).
TotalDownloadProgress(progress)- total download progress.
progressis a hash with these fields:
loaded_count- number of modules already downloaded,
total_count- total number of modules,
loaded_size- amount of bytes downloaded,
total_size- total size of modules in bytes.
ModuleDownloadFailed(event, module, error)- event fires when module downloading was aborted, interrupted, or data checksum did not match. Parameters:
event- browser event,
module- module which failed to download,
error- contains error occured during module checking.
ModuleDownloaded(module)- occurs when module was successfully downloaded. Parameters:
event- browser event,
module- downloaded module.
UpdateCompleted(manifest)- occurs when all modules of the new version were successfully downloaded. The handler must return
true, if loader should accept new version, or
falseif update should be postponed. You can inform user about update and request application restart at this point. If update is accepted it will be loaded at next application run (next
manifest- new version manifest.
dropData - remove current version and force data to be downloaded again. Useful in case of critical failures.
Code and documentation copyright 2014 Eugene Chernyshov. Code released under the MIT license.