gulpfile-ninecms documentation

Front-end package management.

Features

The module uses gulp to pack front-end static files.

It offers a number of common tasks which can be included in a gulpfile and used in any project regardless of the tech stack.

It also offers a default gulpfile.js and related dependencies in the package.json.

Installation

Gulp

Gulp is obviously required. Install with:

$ npm install -g gulp-cli

Imagemagick (optional)

Imagemagick is optional for optimizing static images in the relevant task:

$ sudo apt-get install imagemagick

gulpfile-ninecms

Finally, to install the project itself. Change to your project folder and:

$ npm install -D gulpfile-ninecms

How to use

A sample gulpfile.js is included in the project.

You can create new gulpfile or adapt this sample to your needs:

$ cp node_modules/gulpfile-ninecms/gulpfile.js .

Path configuration

The first section of the provided gulpfile is an example of a path configuration object. To customize, edit the gulpfile and the appropriate paths.

There can be multiple path configurations for multiple builds. For instance, the sample gulpfile provides a default path config for the main site and an admin path config for the administration interface. These two have separate builds so that the main site is not getting bloated with scripts and styles that are only needed for another part of the site.

For details on tasks, see tasks. Specify the appropriate paths of the following:

  • assets: any Assets files that need to be copied unchanged, such as fonts or images.
  • less: any LESS files to be compiled.
  • sass: any SASS/SCSS files to be compiled.
  • css: any CSS files to be processed.
  • js: the JS entry file for browserify to be processed.
  • js_watch: any JS files to be watched.
  • mocha: any JS files to be tested.
  • images: any images to be processed.
  • build: the output directory. This is used in most task methods.
  • fonts: the fonts output directory.

For example:

var paths = {
  assets: [],
  ...
};

Requirements

Include in your gulpfile:

var taskMethods = require('gulpfile-ninecms');

This deals with gulp requirements regarding the tasks themselves. Also include any additional requirements such as gulp and argv that gulpfile itself may use.

Alternatively, you can copy/paste the task methods from index.js into the gulpfile.

Task wire-up

Multiple tasks may run many times, each for every path configuration set. Gulp does not provide a way to provide a path parameter to task (relevant issue). Therefore, we need to ‘wire-up’ the task methods we use with the appropriate path into gulp tasks:

var tasks = {
  clean: function () { return taskMethods.clean(paths); },
  ...
};

gulp.task('clean', tasks.clean);

Execute

To build and watch:

$ gulp

To build only once (no watch), run:

$ gulp build

To build for production:

$ gulp build --production

Clean

Syntax

clean(paths)

Description

Delete the output path paths.build.

Dependencies

Should runs before all build tasks.

Example

var paths = {
  build: 'build/'
};

var gulp = require('gulp');
var argv = require('yargs').argv;
var taskMethods = require('gulpfile-ninecms');

var tasks = {
  clean: function () { return taskMethods.clean(paths); }
};

gulp.task('clean', tasks.clean);

// for production we require the clean method on every individual task
var build = argv._.length ? argv._[0] === 'build' : false;
var req = build ? ['clean'] : [];

// individual tasks
gulp.task('...', req, ...);

Assets

Syntax

assets(paths)

Description

Copy the specified files or directories from paths.assets to paths.build.

This is useful when the build path is the same path that offers static files as images, and you wish to clean it entirely with clean.

This is also especially useful to copy static paths that are referred to by css files such as bootstrap. Use the * gulp feature for paths accordingly (see examples).

Example

var paths = {
  assets: [
    'node_modules/bootstrap/dist/*fonts/*',
    'static/*images/*'
  ],
  build: 'build/'
};

var gulp = require('gulp');
var taskMethods = require('gulpfile-ninecms');

var tasks = {
  assets: function () { return taskMethods.assets(paths); }
};

gulp.task('assets', [], tasks.assets);

LESS

Syntax

less(paths)

Description

Compile LESS files from paths.less to paths.build. Maintains the same file names, but replacing the extention .less to .css.

The compilation procedure for --production:

The compilation procedure for non --production:

Dependencies

The CSS concatenate task should run after less has finished, if the output from less is included in the css task.

Example

var paths = {
  less: [
    'private/stylesheets/*.less'
  ],
  build: 'build/'
};

var gulp = require('gulp');
var taskMethods = require('gulpfile-ninecms');

var tasks = {
  less: function () { return taskMethods.less(paths); }
};

gulp.task('less', [], tasks.less);

SASS/SCSS

Syntax

sass(paths)

Description

Compile SASS and SCSS files from paths.sass to paths.build. Maintains the same file names, but replacing the extention .s?ss to .css.

The compilation procedure for --production:

The compilation procedure for non --production:

Dependencies

The CSS concatenate task should run after sass has finished, if the output from sass is included in the css task.

Example

var paths = {
  sass: [
    'private/stylesheets/*.s?ss',
    'private/javascripts/my-angular-app/**/*.s?ss'
  ],
  build: 'build/'
};

var gulp = require('gulp');
var taskMethods = require('gulpfile-ninecms');

var tasks = {
  sass: function () { return taskMethods.sass(paths); }
};

gulp.task('sass', [], tasks.sass);

CSS concatenate

Syntax

css(paths)

Description

Concatenate CSS files from paths.css into paths.build /css/style.min.css.

The concatenation procedure for --production:

The compilation procedure for non --production:

Dependencies

The task should run after LESS/SASS/SCSS has finished, if the output from them is included in the css task.

Example

var paths = {
  css: [
    'node_modules/animate.css/animate.css',
    'build/stylesheets/main.css' // this is the output from LESS/SASS
  ],
  ...
  build: 'build/'
};

var gulp = require('gulp');
var taskMethods = require('gulpfile-ninecms');

var tasks = {
  less: function () { return taskMethods.less(paths); }
  sass: function () { return taskMethods.sass(paths); }
  css: function () { return taskMethods.css(paths); }
};

gulp.task('less', [], tasks.less);
gulp.task('sass', [], tasks.sass);
gulp.task('css', ['less', 'sass'], tasks.css);

Browserify

Syntax

browserify(paths)

Description

Browserifies the specified paths.js file and outputs to paths.build.

If --production is specified it also uglifies the output script.

Use a single js entry point with all requires.

If gulp watch then the task also watches changes in the bundled requires.

Quick reference

Quick reference to browserifying common front-end packages.

Alternatively use the JS concatenate task.

Notation used below:

  • npm package: Install the npm package
  • index.js: Require the package in the entry js using the provided code
  • gulpfile path: Additional paths to include in gulpfile build
jQuery
Bootstrap
  • npm package: bootstrap
  • index.js: require('bootstrap');
  • gulpfile assets path: 'node_modules/bootstrap/dist/*fonts/*'
  • gulpfile css path: 'node_modules/bootstrap/dist/css/bootstrap*(|-theme).css'
  • html5shiv: either ignore or leave as is
  • Browserify with Bootstrap
Angular
Lightbox2
  • npm package: lightbox2
  • index.js: require('lightbox2');
  • gulpfile css path: 'node_modules/lightbox2/dist/css/lightbox.css'
animate.css
  • npm package: animate.css
  • gulpfile css path: 'node_modules/animate.css/animate.css'
  • No js file
wow.js
  • dependencies: animate.css

  • npm package: wow.js

  • Browserify-shim

    • package.json:

      "browserify": {"transform": [ "browserify-shim" ]},
      "browser": {
        "wow": "./node_modules/wow.js/dist/wow.js"
      },
      "browserify-shim": {
        "wow": {"exports": "WOW"}
      }
      
    • index.js:

      var WOW = require('wow');
      new WOW().init();
      
Font awesome
  • npm: font-awesome
  • gulpfile assets path: 'node_modules/font-awesome/*fonts/*'
  • gulpfile css path: 'node_modules/font-awesome/css/font-awesome.css'
  • No js file
Normalize.css
  • npm: normalize.css
  • gulpfile css path: 'node_modules/normalize.css/normalize.css'
  • No js file
Swiper
  • npm: swiper
  • js: require('swiper');
  • gulpfile css path: 'node_modules/swiper/dist/css/swiper.css'
Puse icons
  • npm: puse-icons-feather
  • gulpfile asset path: 'node_modules/puse-icons-feather/*fonts/*'
  • No js file

Browserify-shim

Packages that are not CommonJS compatible require a relative entry in package.json, as described above. The following entry is also required:

"browserify": {
  "transform": ["browserify-shim"]
},

The browserify-shim package is already included in gulpfile-ninecms dependencies.

Example

var paths = {
  js: 'private/javascripts/index.js',
  build: 'build/'
};

var gulp = require('gulp');
var taskMethods = require('gulpfile-ninecms');

var tasks = {
  browserify: function () { return taskMethods.browserify(paths); }
};

gulp.task('browserify', [], tasks.browserify);

JS concatenate

Syntax

concatJs(paths)

Description

Concatenate JS files from paths.js_watch into paths.build /js/index.min.js.

The concatenation procedure for --production:

The concatenation procedure for non --production:

Dependencies

The task should run after Preload Angular HTML has finished, if the output from it is included in the js task.

Example

var paths = {
  js_watch: [
    'node_modules/jquery/dist/jquery.js',
    'node_modules/bootstrap/dist/js/bootstrap.js',
    // angular
    'node_modules/angular/angular.js',
    'node_modules/angular-resource/angular-resource.js',
    'node_modules/angular-animate/angular-animate.js',
    'node_modules/angular-sanitize/angular-sanitize.js',
    // angular app
    'private/javascripts/my-angular-app/*.module.js',
    'private/javascripts/my-angular-app/*.animations.js',
    'private/javascripts/my-angular-app/core/*.module.js',
    'private/javascripts/my-angular-app/core/*.filter.js',
    'private/javascripts/my-angular-app/core/**/*.module.js',
    'private/javascripts/my-angular-app/core/**/*.service.js',
    'private/javascripts/my-angular-app/my-angular-app*/*.module.js',
    'private/javascripts/my-angular-app/my-angular-app*/*.component.js',
    // other
    'private/javascripts/jquery.main.js',
    'build/partials.js'
  ],
  partials: [
    'private/*javascripts/my-angular-app/**/*.html'
  ],
  build: 'build/'
};

var gulp = require('gulp');
var taskMethods = require('gulpfile-ninecms');

var tasks = {
  concatJs: function () { return taskMethods.concatJs(paths); },
  preloadNgHtml: function () { return taskMethods.preloadNgHtml(paths); }
};

gulp.task('preloadNgHtml', req, tasks.preloadNgHtml);
gulp.task('concatJs', req.concat(['preloadNgHtml']), tasks.concatJs);

Preload Angular HTML

Syntax

preloadNgHtml(paths)

Description

Preloads Angular HTML templates specified in paths.partials into a generated partial JS file paths.build /partials.js.

Procedure:

Please note that the task extracts the Angular module name from the template directory name. Eg. for a template file:

private/javascripts/my-admin-app/my-admin-module/my-admin-module.template.html

the module name will be parsed as myAdminModule.

Dependencies

Run the task JS concatenate after this task has finished.

Example

var paths = {
  js_watch: [
    ...
    'build/partials.js'
  ],
  partials: [
    'private/*javascripts/my-angular-app/**/*.html'
  ],
  build: 'build/'
};

var gulp = require('gulp');
var taskMethods = require('gulpfile-ninecms');

var tasks = {
  concatJs: function () { return taskMethods.concatJs(paths); },
  preloadNgHtml: function () { return taskMethods.preloadNgHtml(paths); },
};

gulp.task('preloadNgHtml', req, tasks.preloadNgHtml);
gulp.task('concatJs', req.concat(['preloadNgHtml']), tasks.concatJs);

Lint JS

Syntax

lintJs(paths)

Description

Analyze paths.js_lint and output report to stdout.

Uses the ESlint library:

Code linting is a type of static analysis that is frequently used to find problematic patterns or code that doesn’t adhere to certain style guidelines.

It uses the default rules except:

  • control characters (eg \n) are not required for file appends:

    'no-control-regex': 'off'
    
  • allow double quotes to avoid escaping single:

    'quotes': ['error', 'single', {avoidEscape: true}]
    
  • relax curly braces:

    'curly': ['error', 'multi-line']
    

Dependencies

The task should run after Preload Angular HTML has finished, if the output from it is included in the js task.

Example

var paths = {
  js_lint: [
    'private/javascripts/*.js',
    '*.js'
  ],
  build: 'build/'
};

var gulp = require('gulp');
var taskMethods = require('gulpfile-ninecms');

var tasks = {
  lintJs: function () { return taskMethods.lintJs(paths); },
};

gulp.task('lintjs', tasks.lintjs);

Nsp security

Syntax

nsp()

Description

Run Node Security (nsp) to help identify known vulnerabilities by npm packages that are used in the project’s package.json. Outputs to stdout.

Example

var gulp = require('gulp');
var taskMethods = require('gulpfile-ninecms');
gulp.task('nsp', tasksMethods.nsp);

Mocha tests

Syntax

preTest(paths)
mocha(paths)

Description

Run mocha tests for the files specified in paths.mocha.

Optionally run preTest before mocha to add istanbul coverage to the files specified in paths.js_cover.

This is mostly useful for Node.js projects and can be otherwise ignored.

The task outputs the results on stdout and also creates a coverage directory with HTML report.

Dependencies

preTest should have finished before mocha is run.

Example

var paths = {
  js_cover: [
    'models/*.js',
    'routes/**/*.js',
    'app.js'
  ],
  mocha: [
    'spec/*.js',
    'spec/api/contact.stub.js',
    'spec/api/dashboard.js'
  ],
};

var gulp = require('gulp');
var taskMethods = require('gulpfile-ninecms');

var tasks = {
  preTest: function () { return taskMethods.preTest(paths); },
  mocha: function () { return taskMethods.mocha(paths); }
};

gulp.task('preTest', tasks.preTest);
gulp.task('mocha', tasks.mocha);
gulp.task('test', ['preTest'], tasks.mocha);

Karma tests

Syntax

karma()

Description

Run karma tests based on a /karma.conf.js file.

This is mostly useful for front-end JS such as Angular apps.

The output is configured in the above conf file.

Example

var gulp = require('gulp');
var taskMethods = require('gulpfile-ninecms');
gulp.task('karma', tasksMethods.karma);

Google web fonts

Syntax

fonts(paths)

Description

Download Google fonts specified in paths.fonts /fonts.list to paths.build /fonts and generate a stylesheet for them.

Uses gulp-google-webfonts.

New in v0.4.0: Now the fonts.list location needs to be specified in paths.fonts.

Example

In gulpile.js:

var paths = {
  build: 'build/'
};

var gulp = require('gulp');
var taskMethods = require('gulpfile-ninecms');

var tasks = {
  fonts: function () { return taskMethods.fonts(paths); }
};

gulp.task('fonts', [], tasks.fonts);

In index.html:

<link rel="stylesheet" href="/build/fonts/fonts.css">

Base64 images

Syntax

base64(paths)

Description

Convert all files in url() in provided stylesheets from paths.base64 into base64-encoded data URI strings. The output is concatenated into a paths.build/css/base64.css file.

Uses gulp-base64.

Please note that this is useful only for minor performance gains. Not useful for embedding images into emails as most clients do not accept data uri.

Example

var paths = {
  base64: ['build/css/built_from_sass.css'],
  build: 'build/'
};

var gulp = require('gulp');
var taskMethods = require('gulpfile-ninecms');

var tasks = {
  base64: function () { return taskMethods.base64(paths); },
};

gulp.task('base64', req.concat(['sass']), tasks.base64);

Inline CSS in HTML

Syntax

inlineCss(paths)

Description

Convert all css styles of an HTML file specified in paths.inlineCss.html into inline styles. Outputs to paths.inlineCss.build. Useful for emails.

Uses gulp-inline-css.

Example

var paths = {
  inlineCss: {
    html: 'private/html/email_body.html',
    build: 'templates/envelope/'
  }
};

var gulp = require('gulp');
var taskMethods = require('gulpfile-ninecms');

var tasks = {
  inlineCss: function () { return taskMethods.inlineCss(paths); }
};

gulp.task('inlineCss', req.concat(['sass']), tasks.inlineCss);

Image optimisation

Syntax

images(paths, images)
clean_image_opts(paths)

Description

Create optimized images as specified in images object into paths.images.

Use clean_image_opts to delete previously created image styles in paths.images. Be careful that paths specified are correct before running.

Uses gulp_image_resize to create the images into a specified sub-directory of the original path.

Example

var paths = {
  images: 'media/'
};
var images = [
  {
    build: '/thumbnail',
    src: ['media/*/image/*.+(jpg|png)'],
    width: 150
  }, {
    build: '/thumbnail_crop',
    src: ['media/*/image/*.+(jpg|png)'],
    width: 150,
    height: 150,
    crop: true
  }, {
    build: '/thumbnail_upscale',
    src: ['media/*/image/*.+(jpg|png)'],
    width: 150,
    height: 150,
    upscale: true
  }, {
    build: '/gallery_style',
    src: ['media/*/image/*.+(jpg|png)'],
    width: 400,
    height: 1000
  }, {
    build: '/blog_style',
    src: ['media/*/image/*.+(jpg|png)'],
    width: 350,
    height: 226,
    crop: true
  }, {
    build: '/large',
    src: ['media/*/image/*.+(jpg|png)'],
    width: 1280,
    height: 1280
  }
];

var gulp = require('gulp');
var taskMethods = require('gulpfile-ninecms');

var tasks = {
  images: function () { return taskMethods.images(paths, images); },
};

gulp.task('images', [], tasks.images);

Other information

Background

Initially developed for sites built with NineCMS. As of v0.6.0 the previous (totally basic) package management was removed. Relevant issue: django-ninecms#56.

Several other possibilities have been evaluated and rejected:

  • django-bower
  • django-pipeline
  • django-compressor
  • django-webpacks
  • django-require
  • django-grunt

ENOSPC

In case that gulp watch fails with ENOSPC, increase the inotify watch limit:

$ echo fs.inotify.max_user_watches=16384 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p  # bash
> echo fs.inotify.max_user_watches=16384 | sudo tee -a /etc/sysctl.conf; and sudo sysctl -p  # fish

IDEs

PyCharm has a gulp plugin.