An SPA template using best-in-class libraries, assets, and architecture as found in Single Page Web Applications - JavaScript end-to-end.
$ git clone [email protected]:mmikowski/hi_score.git
$ cd hi_score
$ npm install && npm run prep-libs
<!doctype html>
<html>
<head>
<script src="js/vendor/jquery-3.1.1.js"></script>
<script src="js/vendor/pcss-1.3.5.js"></script>
<script src="js/vendor/pcss.cfg-1.3.5.js"></script>
<script src="js/vendor/jquery.event.gevent-1.1.6.js"></script>
<script src="js/vendor/jquery.event.ue-1.3.2.js"></script>
<script src="js/xhi/00.js"></script>
<script src="js/xhi/01.util.js"></script>
<script src="js/xhi/02.data.js"></script>
<script src="js/xhi/03.model.js"></script>
<script src="js/xhi/04.utilb.js"></script>
<script src="js/xhi/05.css_base.js"></script>
<script src="js/xhi/05.css_lb.js"></script>
<script src="js/xhi/05.css_shell.js"></script>
<script src="js/xhi/06.css.js"></script>
<script src="js/xhi/06.lb.js"></script>
<script src="js/xhi/07.shell.js"></script>
<script src="js/xhi/08.app.js"></script>
<script>
$(function () {
xhi._makeApp_( 'ex01' );
ex01._shell_._initModule_( $('body') );
ex01._lb_._showLb_({
_title_html_ : 'Hello World',
_content_html_ : '<p>Grab the title bar to drag.</p>'
});
});
</script>
</head>
<body></body>
</html>
There it is again. The new hot SPA framework that makes our current one obsolete. Now we have to unlearn everything from the old and reinvest in the new hotness. Some of us have spent far more time learning intricate framework DSLs than the JavaScript we need. Are we ready to get off that treadmill?
Do we really want an SPA framework? If not, then hi_score
is here to help. We provide an ever improving set of
best-in-class libraries that we manage instead of having a framework
that controls us. We thought of calling it low-score
or under-dash
but decided to aim higher.
Provide an SPA starter project that installs best-in-class assets and tools to save time and guide best code practices.
- Download and management of best-in-class JS libs and fonts [npm run prep-libs]
- A commit hook which checks for whitespace, JSLint, and tests [npm run prep-libs]
- Regression tests (1270+ assertions) [npm run test]
- Code coverage reports (currently 98.9%) [npm run cover]
- Integration to Coveralls [npm run covera]
- Compressed, deployment-ready code in seconds [npm run buildify]
hi_score also features fractal MVC architecture, type safety with typecasting, best practice style (including style guides and a cheat sheet), and two simple example applications.
We use the code style presented in Single Page Web Applications - JavaScript end-to-end (see reviews on Amazon). The quick reference and the full code standard are available online.
The xhi
libraries are structured to facilitate loose coupling but strict call
precidence. For example the 00.js
library must be loaded to the JavaScript
environment before any other xhi
code, and it may not call any library with
a higher precidence number. The 08.app.js
, in comparison, must be loaded
after all the 00-07
libraries, but it may call any library of the
same or lower precidence:
/| //////
+ ======================== API CALLS =========================
\| \\\\\\
+---------+ +----------+ +----------+
| 02.data | | 03.model |<--+-------------------| Shell |
| Data |<---| Model | ..... events .....))) | 07.shell |
| Fetch | +----------+ : +----------+
+---------+ | : |
| | : +---------+ |
| | : | 06.lb | |
| | :..))) | litebox |<--+
| | +----------+ : | feature | |
v | | Browser |<--+----------+---------+ |
+---------+ | | Utils | | : |
| 01.util | | | 04.utilb | | : +---------+ |
| Utils |<-----+--+----------+ | : | 06.* | |
+---------+ | ...))) | feature |<--+
| | | modules | |
v +----------+---------+ |
+-----------+ | |
| 00.js | | +-------------+ |
| namespace | | | 05.css_* | |
+-----------+ | | 06.css |<--+
| | feature css |
+------+-------------+
\\\\\\ |\
========================== DATA FLOW =======================| +
////// |/
We use model events to broadcast changes to the Shell and Feature modules, and we keep our feature modules isolated from each other. This enhances portability and quality.
Our baseline compatibility is IE9+. If you are targeting IE 8, you have our sympathy.
Everything should just work on Ubuntu 16.10 as that is the development OS for hi_score. There are a few prerequisites that many developers may already have installed:
sudo apt-get install build-essential openssh-server git pandoc
curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
sudo apt-get install -y nodejs
Other modern distros generally work as long as the same tools can be installed as for Ubuntu 16.10 server. It works fine on CentOS 6.5, for example.
See this guide for NodeJS package installation on other Linux distros. Here is a more generic guide for (k)Ubuntu.
Use AWS or a Virtual Box image using Ubuntu 16.10 server using the the same steps as Ubuntu 16.10 server, above.
This is probably the best way to get familiar with the code if you are not already running Linux.
We recommend using a virtual machine if possible. However we should be able to develop natively on Mac. At the very least we'll need Bash 4+ and GNU Core utilities installed// along with NodeJS, Git, PanDoc, and SSH. This guide should help with installation of the GNU Core utilities.
We recommend using a virtual machine as detailed below. Installation may work with the new Linux subsystemw on Windows 10 but we wouldn't bet on it.
If you have set the code on a platform other than Ubuntu 16.10 we would appreciate your help documenting it for the benefit of others.
Install hi_score dependencies and then copy vendor libraries.
home$ git clone [email protected]:mmikowski/hi_score.git
home$ cd hi_score
hi_score$ npm install
hi_score$ npm run prep-libs
One can also use npm install hi_score
but the git method is preferred.
No errors should be reported.
Run the regression tests through npm.
hi_score$ npm test
The tests for the xhi
libraries currently cover the
root namespace (00.js
), the utilities (01.util.js
),
the browser utilities (04.utilb.js
) and the litebox feature module
(06.lb.js
). We plan to expand coverage to include data and models
in subsequent releases.
Check the code coverage by running the cover
script.
hi_score$ npm run cover
hi_score$ google-chrome coverage/lcov-report/index.html
We use the excellent Istanbul
code coverage tool along with the JSDOM
package. Previously we had used nodeunitb
for testing but was unsuccessful
in getting usable coverage reports. We see 98.9% coverage for the four modules
tested as of version 0.9.0.
If you create a new fork you may send a coveralls report as shown in the master
branch site. The process to set up coveralls is described in
hi_score/COVERALLS.md
.
hi_score$ npm run covera
We employ buildify
and superpack
to prepare the code for production.
As of version 0.9.0 our first full build system is in place. This is a
generalization of a build system that has been in use on many production
systems and is currently in-use on some very high-volume sites
(100m views per day). We continue to improve feedback and usability.
hi_score$ npm run buildify
hi_score$ cd build/dist
dist$ google-chrome ex01.html ex02.html
The build process creates two isolated applications that share resources like fonts, vendor libraries, and other assets. This is generally the preferred approach.
One may update all the npm libraries, npm assets, and the package.json
file
with npm update -D
. If we want these changes to propagate, we must run
npm run prep-libs
again to update the vendor libraries, and update the
index.html
file to point to the updated versions. We expect to automate
the last step in future updates.
After installation we can control-click the following links to inspect the uncompressed example applicaitons.
Yes we know the examples are lame. We're working on that.
Both of the applications use the xhi
libraries and provide nearly
identical features yet they have completely separate namespaces.
We can use the Chrome developer tools to inspect these differences.
Press <shift>-<ctrl>-i
(or <shift>-<cmd>-i
on a Mac) to open these tools.
When we view the Example 1 tab we can type ex01
into the JavaScript console
and press return and see that this single variable points to all our unique
code in this application. However, if we type ex02
we see that this
variable is undefined
, as it should be. If we visit the Example 2 tab we
can see that the opposite is true - ex01
is undefined
and ex02
contains
all our application code. This namespacing allows us to provide a suite of
web applications that share the same UX without interferring with each other.
This name spacing extends to CSS as well. If we inspect the HTML in the
Example 1 tab, we can see that nearly all classes start with an ex01-
prefix,
whereas the Example 2 tab uses ex02-
.
All vendor assets are listed in the devDependencies
map in the
package.json
file. If you want to add a vendor asset, the best method is to
add the npm package there and then update the bin/prep-libs
script
to copy the asset to the correct directory: js/vendor/
,
css/vendor
, font/vendor
, or img/vendor
.
Client libraries are copied to the js/vendor
directory with their
version number appended to their names. These include:
- jQuery DOM manipulation
- PowerCSS JS-powered CSS
- jQuery Plugin: event.dragscroll Inertia scroll
- jQuery Plugin: event.gevent Global events
- jQuery Plugin: event.ue Touch and desktop gestures
- jQuery Plugin: scrolli Scroll indicators
- jQuery Plugin: urianchor SPA routing
- TaffyDB
Libraries used for development and testing are not copied:
- coveralls Code coverage reporting
- istanbul Code coverage
- jsdom DOM mock for testing
- jslint Linting for commit hook
- nodeunit Unit testing
- node-inspector Debugging
- uglifycss Minification
- uglifyjs Minification
CSS libraries are copied to the css/vendor
directory with their
version number appended to their names. We currently include
the Font Awesome library.
Font files are copied to the font/vendor
directory with their
version number appended to their names. We currently include
the open-sans-webfont and Font Awesome files.
This is where it all comes together. Everything you do not want to distribute to the public is removed from the distribution, which is further compressed and minified. The result is an application that can easily load 10x faster and take only 5-10% of the space of the code.
The results of a build are found in build/dist
. Take a look at how few files
and little disk space is used in our distribution:
hi_score$ cd build/dist
dist$ tree
Superpack analyzes symbol use and replaces them with the smallest keys available prioritized by frequency. It reports this frequency which makes further optimizations by pruning code easier. On larger code projects with many object properities Superpack has been shown to reduce minimized code by an additional 50%.
Reducing a dozen or so HTTP requests to one for a single, highly compressed JS file can reduce load time to 10% of prior values. The table below shows some of the results:
Attribute | Original (%) | Minified (%) | Superpack (%) |
---|---|---|---|
Size | 601,027 (100.0%) | 215,400 ( 35.8%) | 162,494 ( 27.1%) |
Gzipped | 151,716 ( 25.2%) | 62,895 ( 10.4%) | 57,275 ( 09.5%) |
Attribute | Original | Minified (%) | Superpack (%) |
---|---|---|---|
HTTP reqs | 27 (100.0%) | 4 ( 15.4%) | 4 ( 15.4%) |
Local ms | 231 (100.0%) | 166 ( 71.2%) | 144 ( 62.3%) |
Deploy Size | 121 MB | 8 MB ( 6.6%) | 8 MB ( 6.5%) |
The load time measurements were made using a local HTTP server which is almost certainly a best-case scenario. We hope to add results for a remote server soon.
Any improvements or suggestions are welcome through the issues tracker. Pull requests are especially appreciated.
2016 Michael S. Mikowski (mike[dot]mikowski[at]gmail[dotcom])
MIT
- (x) Initial preparation
- (x) Library updates
- (x) Regression and integration testing
- (x) Rudimentary sample application
- (x) Add code coverage
- (x) Replace
getDeepMapVal
andsetDeepMapVal
with much more powerful and testedgetStructData
andsetStructData
which empowers you with transversal and creation of arbitrary mixed list and map structures. - (x) Updates to
xhi/01.util.js
- (x) Replace
jscoverage
with much more complete and recentistanbul
- (x) Added
cast
routines and detail their use - (x) Consolidate utilities to increase coverage
- (x) Update lite-box using
cast
methods
- (x) Add
jsdom
to expand testing to modules that use jQuery - (x) Continue regression test expansion
- (x) Rationalize libraries
- (x) Add lite-box regression tests
- (x) Remove vendor code from repo and auto-copy on install
- (x) Add native utils
makeThrottleFn
andmakeDebounceFn
- (x) Add links to updated code style guides
- (x) Replace
install
script withprep-libs
(v0.6.17+)
- (x) Move to consturctor approach to easily create multiple concurrent namespaced apps using the common xhi core
- (x) Update index page to illustrate
- (x) Make example app less trivial
- (x) Number code library level
- Work on build system
- Unify shell scripts nomenclature
- Add constructor where only selected components are added
- Add dependency graph for above
- Initial full-stack build system
npm run buildify