31

I am using Browserify within gulp. I am trying to compile down my tests to a single file as well. But unlike my main app, which I have working just fine, I am having trouble getting the tests to compile. The major difference is the tests have multiple entry points, there isn't one single entry point like that app. But I am getting errors fro Browserify that it can't find the entry point.

browserify   = require 'browserify'
gulp         = require 'gulp'
source       = require 'vinyl-source-stream'

gulp.task 'tests', ->
    browserify
        entries: ['./app/js/**/*Spec.coffee']
        extensions: ['.coffee']
    .bundle 
        debug: true
    .pipe source('specs.js') 
    .pipe gulp.dest('./specs/')
Jake Wilson
  • 88,616
  • 93
  • 252
  • 370
Matt
  • 2,795
  • 2
  • 29
  • 47

4 Answers4

40

Below is a task I was able to build that seems to solve the problem. Basically I use an outside library to gather the files names as an array. And then pass that array as the entry points

'use strict;'

var config = require('../config');
var gulp = require('gulp');
var plumber = require('gulp-plumber');
var glob = require('glob');
var browserify  = require('browserify');
var source = require('vinyl-source-stream');

gulp.task('tests', function(){
  var testFiles = glob.sync('./spec/**/*.js');
  return browserify({
      entries: testFiles,
      extensions: ['.jsx']
    })
    .bundle({debug: true})
    .pipe(source('app.js'))
    .pipe(plumber())
    .pipe(gulp.dest(config.dest.development));
});
Matt
  • 2,795
  • 2
  • 29
  • 47
  • 1
    `var testFiles = glob.sync('./spec/**/*.js');` did the trick for me instead of using `glob(paths.js+'/**.js', function(err, widgetFiles) {...`. +1 – Aamir Afridi Dec 16 '15 at 17:43
  • and if you have an array of patterns, use `globs` instead of `glob`: https://www.npmjs.com/package/globs – user2226755 May 12 '20 at 02:50
19

Here's an alternate recipe that fits more with the gulp paradigm using gulp.src()

var gulp = require('gulp');
var browserify = require('browserify');
var transform = require('vinyl-transform');
var concat = require('gulp-concat');

gulp.task('browserify', function () {

  // use `vinyl-transform` to wrap around the regular ReadableStream returned by b.bundle();
  // so that we can use it down a vinyl pipeline as a vinyl file object.
  // `vinyl-transform` takes care of creating both streaming and buffered vinyl file objects.
  var browserified = transform(function(filename) {
    var b = browserify(filename, {
      debug: true,
      extensions: ['.coffee']
    });
    // you can now further configure/manipulate your bundle
    // you can perform transforms, for e.g.: 'coffeeify'
    // b.transform('coffeeify');
    // or even use browserify plugins, for e.g. 'minifyiy'
    // b.plugins('minifyify');
    // consult browserify documentation at: https://github.com/substack/node-browserify#methods for more available APIs
    return b.bundle();
  });

  return gulp.src(['./app/js/**/*Spec.coffee'])
    .pipe(browserified)/
    .pipe(concat('spec.js'))
    .pipe(gulp.dest('./specs'));
});

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

For more details about how this work, this article that I wrote goes more in-depth: http://medium.com/@sogko/gulp-browserify-the-gulp-y-way-bb359b3f9623

Hafiz Ismail
  • 3,195
  • 1
  • 25
  • 21
  • 2
    Just a quick note, the downside to this method is that you can't swap in watchify. As your builds get longer the native watch of gulp isn't well suited to the big compiled browserify form in my experience. – Matt Aug 25 '14 at 04:54
  • I agree, you would need a different approach for projects with bigger build: - one approach is to use watchify to perform small incremental builds (but as you mentioned, browserify+watchify requires a change in the recipe; i might consider writing one for that) - another approach that I personally prefer is to separate your codebase into bundles. most project tend to have application code and vendor code (react, angular etc). I've [outlined the approach here](https://github.com/sogko/gulp-recipes/tree/master/browserify-separating-app-and-vendor-bundles) (Warning: the writing is still raw) – Hafiz Ismail Aug 27 '14 at 05:10
  • Note also that this approach may not be compatible with some browserify plugins, like [minifyify](https://www.npmjs.org/package/minifyify). In that case, you're pretty much forced to take Matt's approach. – superEb Sep 04 '14 at 16:57
  • @superEb: well, thats not exactly true. this approach uses the browserify original library directly, so you can still perform transforms and use browserify plugins as originally intended. Updated the answer with more information on how to use plugins like ```minifyify``` – Hafiz Ismail Sep 05 '14 at 06:06
  • 1
    Yes, obviously you can call `b.plugin("minifyify", opts)` within the transform, but when I tried this, it resulted in a stream error like `TypeError: Object # has no method 'write'`. The transform works _without_ the plugin, so I assume there's an incompatibility between minifyify and vinyl-transform. – superEb Sep 05 '14 at 15:08
  • I do not think this solution is working properly any longer: https://github.com/substack/node-browserify/issues/1217 – Con Antonakos May 15 '15 at 19:32
  • I having errors using this solution: `_stream_readable.js:540` `var ret = dest.write(chunk);` `TypeError: undefined is not a function` – carloscarcamo Jan 12 '16 at 05:39
1

For start, you can write a suite.js to require all the tests which you want to run and browserify them.

You can see two examples from my project https://github.com/mallim/sbangular.

One example for grunt-mocha-phantomjs

https://github.com/mallim/sbangular/blob/master/src/main/resources/js/suite.js

One example for protractor

https://github.com/mallim/sbangular/blob/master/src/main/resources/js/suite.js

This is just a start and I am sure there are more fancy ways available.

Ian Lim
  • 4,164
  • 3
  • 29
  • 43
  • 1
    I know that I can use a suite, but I was trying to avoid doing so. To avoid problems with having to remember to add new files. – Matt Jun 19 '14 at 01:49
1

A little more complicated example to build files by glob pattern into many files with watching and rebuilding separated files. Not for .coffee, for es2015, but not a big difference:

var gulp = require("gulp");
var babelify = require("babelify");
var sourcemaps = require("gulp-sourcemaps");
var gutil = require("gulp-util");
var handleErrors = require("../utils/handleErrors.js");
var browserify = require("browserify");
var eventStream = require("event-stream");
var glob = require("glob");
var source = require("vinyl-source-stream");
var buffer = require("vinyl-buffer");
var watchify = require("watchify");

var SRC_PATH = "./src";
var BUILD_PATH = "./build";

var bundle = function (bundler, entryFilepath) {
  console.log(`Build: ${entryFilepath}`);

  return bundler.bundle()
    .on("error", handleErrors)
    .pipe(source(entryFilepath.replace(SRC_PATH, BUILD_PATH)))
    .pipe(buffer())
    .on("error", handleErrors)
    .pipe(
      process.env.TYPE === "development" ?
        sourcemaps.init({loadMaps: true}) :
        gutil.noop()
    )
    .on("error", handleErrors)
    .pipe(
      process.env.TYPE === "development" ?
        sourcemaps.write() :
        gutil.noop()
    )
    .on("error", handleErrors)
    .pipe(gulp.dest("."))
    .on("error", handleErrors);
};

var buildScripts = function (done, watch) {
  glob(`${SRC_PATH}/**/[A-Z]*.js`, function (err, files) {
    if (err) {
      done(err);
    }

    var tasks = files.map(function (entryFilepath) {
      var bundler = browserify({
        entries: [entryFilepath],
        debug: process.env.TYPE === "development",
        plugin: watch ? [watchify] : undefined
      })
        .transform(
          babelify,
          {
            presets: ["es2015"]
          });

      var build = bundle.bind(this, bundler, entryFilepath);

      if (watch) {
        bundler.on("update", build);
      }

      return build();
    });

    return eventStream
      .merge(tasks)
      .on("end", done);
  });
};

gulp.task("scripts-build", function (done) {
  buildScripts(done);
});

gulp.task("scripts-watch", function (done) {
  buildScripts(done, true);
});

Complete code here https://github.com/BigBadAlien/browserify-multy-build

BigBadAlien
  • 236
  • 3
  • 8