Skip to content

richard-still-ft/ft-frontend-build

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

61 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ft-frontend-build

Configurable and (fairly) infrastructure-agnostic build for a responsive front-end using origami components.

Dependencies

The below will probably need to be run as superuser

  • Node & npm - download or upgrade. Not sure which version is the minimal requirement - try it and see.
  • grunt-cli - npm install -g grunt-cli
  • karma-cli and phantomjs (if your project has javascript unit tests) - npm install -g karma-cli phantomjs

Installation

If your project does not already have a package.json run npm init in the project root.

Then run npm install -D ft-frontend-build=git+https://github.com/Financial-Times/ft-frontend-build.git

Finally your GruntFile.js should have the following content

module.exports = require('ft-frontend-build');

... ok, so while that is fantastically minimal, it's also scarily magical, so you can take back control of your GruntFile by having

module.exports = function (grunt) {

  // your stuff here ...

  require('ft-frontend-build')(grunt, load-config);

  // ... and here

  // ... and, for good measure, a bit more here
}

ft-frontend-build uses the excellent load-get-config plugin which should load any npm grunt-tasks for you. load-config can optionally be used to pass in additional config to it.

App structure

ft-frontend-build, where possible, favours convention over configuration so it's important your front-end src code adheres to one of the following directory structures (if for some reason your app cannot meet these requirements please contact Rhys Evans).

Non-modular

Where your app will only ever build a single css file and a single js file. You should set isModular: false in your config.

Note that it's recommended to store yuor templates with your other source code. This unusual approach is partly for code organisation reasons, but will allow you to use a planned build step that will make it easier to consume origami components' templates.

root
  \_ js
      \_head
        main.js
      |  // If you need to output mustache variables into a your js e.g. domain specific config
      |  // putting it in this file will mean ft-frontend-build minifies it for you
      \_ inlineScript.mustache 
    // each main.js must use commonjs to require any other js files
    main.js
  \_ sass
    |  // must use sass @import to include any other sass files
    \_ main.scss 
  \_ tpl
    \_ a-template.mustache

Modular

For more complex apps with multiple js and style bundles (for e.g. lazy-loaded features or core vs primary browser experiences) You should set isModular: true in your config.

Even if your app only requires a single bundle at present it's worth cosidering adopting this structure as it will mean there is zero refactoring work to do if your app increases in complexity.

Only the app directory and its contents are required. The remaining directories are suggestions for making your code more reusable; in particular, if you write as much of your code as possible in the components directory it will be relatively easy to convert into reusable origami modules in future.

root
  \_ app
  |   \_ main
  |     \_js
  |     \_scss
  |     \_tpl
  |       a-template.mustache
  |     main.js
  |     main.scss
  |   \_ head
  |     main.js
  |     inlineScript.mustache 
  |   \_ moduleB
  |     \_js
  |     \_scss
  |     \_tpl
  |       a-template.mustache
  |     main.js
  |     main.scss
  |
  |  // sass, js and templates for definining the appearance and behaviour of self-contained features of your app
  |  // A good idea to keep the [origami spec](http://origami.ft.com) in mind while writing these
  \_ components
  |   \_ component1
  |       \_ scss
  |       \_ js
  |       \_ tpl
  |        main.js
  |        main.scss
  |        main.mustache
  |
  |  // A home for third party resources (mostly js, but could also be css/sass) which, for whichever reason, cannot be @imported/required directly after a bower install. 
  |  // e.g. the es6-promises polyfill requires npm and a transpiler to make it consumable by browserify, so a built version could be stored here
  \_ vendor

Where possible it's a good idea to keep your front-end src code away from any directories your server framework expects your static assets to be as this may result in it executing some 'magic' which conflicts with what ft-frontend-build is trying to do e.g. dropwizard will copy ./src/main/resources directly into your public root.

Configuration

These should all be set in ft-frontend-config.js, which exports a javascript object defining each property (at the top-level) it needs to override. Default values are in italics.

Paths

All the paths below should begin with ./ and end in /

  • bowerPath './bower_components/': Path to where your bower components are installed (as set in your .bowerrc file). Even though it may seem counterintuitive it's best to keep this outside where your source code resides as it'll make your build quicker
  • srcPath './src/': Location of your front-end source files
  • stagingPath './tmp/': Location for temporary build files
  • inlineHeadScriptDestinations []: Location(s) to copy your inline head script to
  • builtAssetsPath './static/': Directory to place all your app's built static assets (including css and js) in. To include an assets version in the path use {{version}} and this will be replaced at build time with teh asset parameter pased in (see Running -> parameters below)

Build steps

  • blocks ['clean', 'tpl', 'js', 'css', 'polyfill', 'assets']: Blocks of build tasks to carry out. The names refer to blocks of tasks that carry out the following

    • clean: removes the files created by the last build
    • tpl: builds templates which correctly include origami modules and their dependencies' templates
    • js: browserifies all your js modules and copies them to your built app. Also minifies your inline head script template
    • css: runs sass on all your css modules and copies them to your built app
    • polyfill: generates a modernizr build and copies any polyfills across to your built app
    • assets: copies other static assets across to your built app

    Any other strings added to the blocks array must be the names of grunt tasks you want to run as part of every build

    In addition to these strings you can also put functions in the array of the form function (sub, env, tasks, grunt) {} where

    • sub: the sub-section of the build which has been called (see section on Running below)
    • env: the environment the build is being run in (dev or prod)
    • tasks: the queue of grunt tasks constructed so far
    • grunt: the current instance of grunt

    These functions may limit themselves to simple operations e.g. setting a dynamic property on the grunt config. If, however, the intention is for it to run some grunt tasks they must not use grunt.task.run; instead they should push/concat these tasks onto the tasks array provided.

  • skipBlocks []: List of named build blocks to skip

  • skipTasks []: List of specific grunt-tasks to skip. e.g. copy:css will skip copying css, whereas copy will skip copy:css, copy:js etc...

Modules

  • isModular false: Whether or not the app follows the directory structure for a more complex modular app
  • cssModules []: names of css modules (in addition to main) that need building into separate stylesheets
  • jsModules []: names of js modules (in addition to main) that need browserifying into separate bundles

Individual task config

  • copyExcludeList []: List of files and directories to exclude when copying static assets to the built app; by default most things in your bower directory will be copied. Adding a \ to the end of an entry here will exclude that directory and its entire contents
  • copyIncludeList []: List of files and directories to include when copying static assets to the built app
  • bowerPolyfills []: Paths to polyfills installed via bower. Note that e.g. event-listeners/EventListener.polyfill.min.js will be copied to js/polyfills/event-listeners.js in the built app
  • srcPolyfills []: Paths to polyfills not installed via bower. Note that e.g. src/path/vendor/es6-promises.js will be copied to js/polyfills/es6-promises.js in the built app
  • watch {}: Configuration to be passed in to grunt-contrib-watch. By default ft-frontend-build's watch task watches for changes in all scss and js files in your bower or src directories
  • templating: Configuration object for constructing your app's templates when they require origami modules' templates. The type property (currently only accepting the value 'hogan-express') specifies the templating system you are using, and the remaining properties specify options for parsing the templates

Hogan-express templating options

Note that after the build has completed a json file ft-frontend-template-map.json will be created in the root of your project and this should be required when registerin gpartials with express.

*srcDirectory './templates/': The directory where your templates are located *overrides {}: Object containing variables in origami templates whose values shoudl be rewritten e.g.

      'o-ft-header': { // will run over all variables in o-ft-header's template
          _namespace: 'header', // will replace 'o-ft-header.' with 'header.' as the namespace for all variables in the template 
          'topbar-items': 'o-ft-legacy-signin' // will replace {{o-ft-header.topbar-items}} with {{> o-ft-legacy-signin}} i.e. allows you to replace a placeholder variable with another module's template
          encodedLocation: 'encodedLocation' // replaces {{o-ft-header.encodedLocation}} with {{encodedLocation}}
          advert: '> promo1' // replaces {{o-ft-header.advert}} with {{> promo1}}
      }

Running using the CLI

Tasks

4 tasks are available

  • default (called using grunt) - runs both test and build
  • test (called using grunt test) - lints js files and runs any unit tests using karma
  • build (called using grunt build) - builds the app
  • watch (called using grunt watch) - watches for source code changes (including changes to bower modules) and runs a sub-build in dev mode

In addition build accepts two optional parameters,

*subbuild: Specifies a subsection of the build to run. The naming convention follows that of blocks *env: Specifies whether to carry out a production (prod) or dev (dev) build - defaults to prod

e.g build:js:dev, build:dev,

Parameters

The asset version to build can be set using --assetVersion=1.2.3 in the cli. This version number (and a '/') will be appended to the built app's static assets path, defaulting to 0.0.1

Tests

By default these shoudl be written in jasmine and will be run using karam, but can be overwritten in its entirety

/* TODO

test paths modernizr + modernizrless versions of tests

*/

About

Configurable and (fairly) infrastructure-agnostic build for a website's front-end using origami components.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors