Search code examples
javascriptangularjsnode.jsstreamgulp

How can I insert content into a file during a Gulp build?


I managed to accomplish my task using a Gulp plugin called gulp-insert like this:

gulp.task('compile-js', function () {
  // Minify and bundle client scripts.
  var scripts = gulp.src([
    srcDir + '/routes/**/*.js',
    srcDir + '/shared/js/**/*.js'
  ])
    // Sort angular files so the module definition appears
    // first in the bundle.
    .pipe(gulpAngularFilesort())
    // Add angular dependency injection annotations before
    // minifying the bundle.
    .pipe(gulpNgAnnotate())
    // Begin building source maps for easy debugging of the
    // bundled code.
    .pipe(gulpSourcemaps.init())
    .pipe(gulpConcat('bundle.js'))
    // Buffer the bundle.js file and replace the appConfig
    // placeholder string with a stringified config object.
    .pipe(gulpInsert.transform(function (contents) {
      return contents.replace("'{{{appConfigObj}}}'", JSON.stringify(config));
    }))
    .pipe(gulpUglify())
    // Finish off sourcemap tracking and write the map to the
    // bottom of the bundle file.
    .pipe(gulpSourcemaps.write())
    .pipe(gulp.dest(buildDir + '/shared/js'));

  return scripts.pipe(gulpLivereload());
});

What I'm doing is reading our app's configuration file which is managed by the config module on npm. Getting our config file from server-side code is a snap using var config = require('config');, but we're a single-page app and frequently need access to the configuration settings on the client-side. To do that I stuff the config object into an Angular service.

Here's the Angular service before gulp build.

angular.module('app')
  .factory('appConfig', function () {
    return '{{{appConfigObj}}}';
  });

The placeholder is in a string so that it's valid JavaScript for some of the other Gulp plugins that process the file first. The gulpInsert utility lets me insert the config like this.

.pipe(gulpInsert.transform(function (contents) {
  return contents.replace("'{{{appConfigObj}}}'", JSON.stringify(config));
}))

This works but feels a little hacky. Not to mention that it has to buffer the whole bundled file just so I can perform the operation. Is there a more elegant way to accomplish the same thing? Preferably one that allows the stream to keep flowing smoothly without buffering the whole bundle at the end?


Solution

  • Have you checked gulp-replace-task?

    Something like

    [...]
    .pipe(gulpSourcemaps.init())
    .pipe(replace({
      patterns: [{
        match: '{{{appConfigObj}}}',
        replacement: config
      }],
      usePrefix: false
    })
    .pipe(gulpUglify())
    [...]