This document outlines the moving parts that make up how the JS modules are found and run in the app.
Why do this?
- GitHub Pages does not natively support JS bundles and blocks third-party plugins designed for bundling.
- By using the source JS directly without bundling, local development and debugging of the live site is significantly easier, especially for new contributors who want to start hacking on things
- By writing more granular modules we can build up a meaningful set of tests to ensure we don't regress the website over time
This section outlines the runtime steps the app performs to load and process client-side scripts.
RequireJS is a module loader designed for use in the browser, and Up-For-Grabs uses this to compose together the application at runtime without needing additional tools like bundlers.
When loading the website, this script resource is the entry point to loading the additional client-side resources:
<script
src="{{ site.github.url }}javascripts/lib/require.js"
data-main="javascripts/app"
></script>
The data-main
attribute tells RequireJS what script to run after it is
initialized.
The javascripts/app.js
resource configures the application and launches the
main script.
requirejs.config({
// the default directory to use to find and load resources
baseUrl: 'javascripts',
paths: {
// external scripts hosted on CDN
underscore:
'//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min',
jquery: '//cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min',
sammy: '//cdnjs.cloudflare.com/ajax/libs/sammy.js/0.7.6/sammy.min',
chosen: '//cdnjs.cloudflare.com/ajax/libs/chosen/1.8.7/chosen.jquery.min',
},
shim: {
// chosen is not UMD-compatible, so we need to use this hook to ensure
// jquery is loaded as a prerequisite
chosen: {
deps: ['jquery'],
},
},
});
// after configuring require, load the main script
requirejs(['main']);
If you wish to consume a third-party dependency in the Up-For-Grabs client-side scripting, it will need to be added here.
The javascripts/main.js
contains the application-specific logic for the rest
of the application.
define([
'jquery',
'projectsService',
'underscore',
'sammy',
// chosen is listed here as a dependency because it's used from a jQuery
// selector, and needs to be ready before this code runs
'chosen',
], ($, ProjectsService, _, sammy) => {
// application code goes here
});
If you are adding functionality to the site you will need to follow this pattern:
- wrap your module in a
define
function - the first parameter to the function (if needed) is an array of the modules that this module depends on
- the second parameter is a function to run, with each of those dependencies as parameters
- return an object containing functionality that can then be used by others
This means the use of globals is no longer supported in the codebase, and dependencies need to be explicitly defined like the snippet above.
Up-For-Grabs now supports using jest
to run tests inside a NodeJS context.
It uses babel-jest
which automagically transforms AMD modules into CommonJS
modules.
You can run these tests at any time using yarn test
to ensure the
functionality covered by tests is not affected by your local changes.
Because NodeJS only supports CommonJS modules, there's one extra step of setup if you are writing modules that you would like tested.
Ensure your module defines this before it uses a define
:
// required for loading into a NodeJS context
if (typeof define !== 'function') {
var define = require('amdefine')(module);
}