FORSMILE
JA
開発記事2016/01/28

How to Use Gulp: An Explanation Based on Aurelia's Gulp Setup

Running Aurelia.js in a Node.js and Express Environment - Part 4

Back to Blog

Running Aurelia.js in a Node.js and Express environment - Part 4

Running Aurelia.js in a Node.js and Express environment - Part 1

Running Aurelia.js in a Node.js and Express environment - Part 2

Running Aurelia.js in a Node.js and Express environment - Part 3

Aurelia-Skeleton-Navigation uses Gulp as its build tool.

The environment is also set up to use Browsersync, allowing file changes to be reflected immediately in the browser.

⇒Reference: https://www.browsersync.io/

If you're already familiar with Gulp, that's great, but I believe many people stumble if they don't understand it. So, I'll try to unravel Gulp by looking at how it's used in Aurelia.js.

About gulpfile.js

Basic Gulp settings are configured in `gulpfile.js`. Let's look at Aurelia.js's `gulpfile.js`, which is set up as follows:

text
require('require-dir')('build/tasks');

It uses a Node helper called `require-dir` to reference the contents of the `build/tasks` folder.

If you check `package.json`, you'll find it listed under `devDependencies`.

Normally, tasks would be configured directly here, but it seems they've separated them for easier management.

First, let's look at `watch.js`, which is executed by `gulp watch`.

javascript
var gulp = require('gulp');
var paths = require('../paths');
var browserSync = require('browser-sync');

// outputs changes to files to the console
function reportChange(event) {
  console.log('File ' + event.path + ' was ' + event.type + ', running tasks...');
}

// this task wil watch for changes
// to js, html, and css files and call the
// reportChange method. Also, by depending on the
// serve task, it will instantiate a browserSync session
gulp.task('watch', ['serve'], function() {
  gulp.watch(paths.source, ['build-system', browserSync.reload]).on('change', reportChange);
  gulp.watch(paths.html, ['build-html', browserSync.reload]).on('change', reportChange);
  gulp.watch(paths.css, ['build-css']).on('change', reportChange);
  gulp.watch(paths.style, function() {
    return gulp.src(paths.style)
      .pipe(browserSync.stream());
  }).on('change', reportChange);
});

Since Gulp is Node.js-based, you specify necessary plugins and modules using `require`.

Each path is configured as a Node module in `paths.js`.

This is a package that synchronizes file changes with browser updates. Since source changes are immediately reflected in the browser, it improves work efficiency.

About gulp.task

text
gulp.task('watch', ['a', 'b']);

If configured as shown above, three tasks—`watch`, `a`, and `b`—will be executed.

In the case of `watch.js`, the `serve` task is executed, and then `watch` runs.

If you simply want to define the execution order, using the `run-sequence` package is easier. It's actually used in `build.js`, which I'll explain later.

About gulp.watch

text
gulp.watch(paths.source, ['build-system', browserSync.reload]).on('change', reportChange);

To explain the above: when the target files in `paths.source` are changed, the `build-system` task and `browserSync.reload` are executed. At that time, the `reportChange` function is called.

As mentioned earlier, `paths` are defined in `paths.js`.

About the serve task

Let's look at the `serve` task, which runs before the `watch` task.

javascript
var gulp = require('gulp');
var browserSync = require('browser-sync');

// this task utilizes the browsersync plugin
// to create a dev server instance
// at http://localhost:9000
gulp.task('serve', ['build'], function(done) {
  browserSync({
    online: false,
    open: false,
    port: 9000,
    server: {
      baseDir: ['.'],
      middleware: function(req, res, next) {
        res.setHeader('Access-Control-Allow-Origin', '*');
        next();
      }
    }
  }, done);
});

This time, the `build` task is executed before `serve`.

Once the `build` task completes, a local server is launched using BrowserSync.

With the settings above, you can access `http://localhost:9000`.

I'll delve a bit deeper into BrowserSync next time.

Access-Control-Allow-Origin

This is used to prevent issues with the Same-Origin Policy (cross-domain restrictions) when fetching data from a domain different from the one displayed in the browser's address bar.

About the build task

javascript
var gulp = require('gulp');
var runSequence = require('run-sequence');
var changed = require('gulp-changed');
var plumber = require('gulp-plumber');
var to5 = require('gulp-babel');
var sourcemaps = require('gulp-sourcemaps');
var paths = require('../paths');
var compilerOptions = require('../babel-options');
var assign = Object.assign || require('object.assign');
var notify = require("gulp-notify");
var browserSync = require('browser-sync');

// transpiles changed es6 files to SystemJS format
// the plumber() call prevents 'pipe breaking' caused
// by errors from other gulp plugins
// https://www.npmjs.com/package/gulp-plumber
gulp.task('build-system', function() {
  return gulp.src(paths.source)
    .pipe(plumber({errorHandler: notify.onError('Error: <%= error.message %>')}))
    .pipe(changed(paths.output, {extension: '.js'}))
    .pipe(sourcemaps.init({loadMaps: true}))
    .pipe(to5(assign({}, compilerOptions, {modules: 'system'})))
    .pipe(sourcemaps.write({includeContent: true}))
    .pipe(gulp.dest(paths.output));
});

// copies changed html files to the output directory
gulp.task('build-html', function() {
  return gulp.src(paths.html)
    .pipe(changed(paths.output, {extension: '.html'}))
    .pipe(gulp.dest(paths.output));
});

// copies changed css files to the output directory
gulp.task('build-css', function() {
  return gulp.src(paths.css)
    .pipe(changed(paths.output, {extension: '.css'}))
    .pipe(gulp.dest(paths.output))
    .pipe(browserSync.stream());
});

// this task calls the clean task (located
// in ./clean.js), then runs the build-system
// and build-html tasks in parallel
// https://www.npmjs.com/package/gulp-run-sequence
gulp.task('build', function(callback) {
  return runSequence(
    'clean',
    ['build-system', 'build-html', 'build-css'],
    callback
  );
});

About Packages and Modules

This prevents the watch process from terminating due to errors while monitoring file changes.

It's used in conjunction with `plumber`. Instead of terminating the task, it sends a notification.

A SourceMap is a file containing mapping information that indicates which line of the original file corresponds to compiled, compressed, or obfuscated code. Here, SourceMaps are being created for code generated by Babel.

It loads a module that specifies Babel options.

This is used when loading `gulp-babel`, combining multiple objects into a single object.

Let's look at the `build-system` task within `build.js`.

javascript
gulp.task('build-system', function() {
  return gulp.src(paths.source)
    .pipe(plumber({errorHandler: notify.onError('Error: <%= error.message %>')}))
    .pipe(changed(paths.output, {extension: '.js'}))
    .pipe(sourcemaps.init({loadMaps: true}))
    .pipe(to5(assign({}, compilerOptions, {modules: 'system'})))
    .pipe(sourcemaps.write({includeContent: true}))
    .pipe(gulp.dest(paths.output));
});

The source files to be processed are defined by `paths.source`, which in this case refers to JavaScript files under `src/` (as specified in `paths.js`).

When the `build` task, called from the `serve` task, is executed, `runSequence` defines the execution order. After `clean` is run, the `build-system`, `build-html`, and `build-css` tasks are executed in parallel.

javascript
gulp.task('build', function(callback) {
  return runSequence(
    'clean',
    ['build-system', 'build-html', 'build-css'],
    callback
  );
});

We've traced the tasks executed when `gulp watch` is run, and I think a very good environment has been set up in conjunction with BrowserSync.

📦
Amazon で関連書籍・ツールを検索
web development programming book
Amazonで探す →(アソシエイトリンク)