webpack-with-common-libs icon indicating copy to clipboard operation
webpack-with-common-libs copied to clipboard

Gulp example ignores Gulp!

Open indolering opened this issue 10 years ago • 18 comments

The webpage "plugins" for gulp state, "No need for a gulp plugin. Just use webpack directly." but your examples don't just use WebPack directly, they miss out on the point of Gulp entirely.

For example, this is how I use Browserify:

  gulp.src('./scripts/index.js', {read: false})
    .pipe(browserify({
      insertGlobals: false,
      debug: true,
      transform: ['uglifyify'],
      'global-transform': true
    }))
    .pipe(rename('speech.js'))
    .pipe(gulp.dest('./spx/meta/'));

This is how I setup Google Closure:

  gulp.src('./babel/babel.js')
    .pipe(closure({compilation_level: 'ADVANCED_OPTIMIZATIONS'}))
    .pipe(rename('babel.mini.js'))
    .pipe(gulp.dest(location));

  gulp.src('./babel/babel.js')
    .pipe(closure({compilation_level: 'ADVANCED_OPTIMIZATIONS'}))
    .pipe(zip())
    .pipe(rename('babel.mini.js.gz'))
    .pipe(gulp.dest(location));

Here is how I am supposed to use Web Pack with Gulp:

gulp.task("webpack", function(callback) {
    // run webpack
    webpack({
        // configuration
    }, function(err, stats) {
        if(err) throw new gutil.PluginError("webpack", err);
        gutil.log("[webpack]", stats.toString({
            // output options
        }));
        callback();
    });
});

The // configuration shows that you are missing the point of Gulp: code over configuration. If you are asking me to write a bunch of foreign config then you obviously "need a plugin" because I don't want to "use Web Pack directly". I want to pass it files using a pipe and I want to direct the output to files but your examples don't tell me how to do that.

If I just wanted a task runner, I could use Grunt or WebPack directly. I choose Gulp because it makes it easier for me to iteratively build up a large number of tasks.

indolering avatar May 31 '14 03:05 indolering

I'm not really into gulp and gulps philosophy. When you know a better way how to use webpack with gulp I really want to hear it.

@sindresorhus wrote this https://github.com/sindresorhus/gulp-webpack before I even heared about gulp. So I didn't wrote a gulp plugin. But this issue and webpack/webpack#280 make me think that you may need one.

@sindresorhus I would like to hear your optinion.

sokra avatar May 31 '14 09:05 sokra

Webpack is inherently incompatible with gulp because AFAIK it doesn't accept an array of file buffers, which is required for gulp plugins. A gulpfile is just node. This is more of a general Webpack API issue.

sindresorhus avatar May 31 '14 12:05 sindresorhus

@sokra It should at processes at the pipe level, similar to the Browserify and Google Closure plugins:


var customPlugin =  new webpack.DefinePlugin({
    "process.env": {
        "NODE_ENV": JSON.stringify("production")
 }});

gulp.src('./dir/file.js')
  .pipe(webpack({
    plugins: [
      webpack.optimize.DedupePlugin({config:options}),
      webpack.optimize.UglifyJsPlugin({config:options}),
      customPlugin
  ]})
  .pipe(gulp.dest('./dist/file.js'));

@sindresorhus I think some plugins use a .tmp directory....

Whatever the backend reasons for all of this, your non-plugin-plugin is discouraging others from attempting to fix the problem and that makes me a very sad panda.

indolering avatar May 31 '14 18:05 indolering

+1 for properly supporting gulp

khaled avatar Jun 02 '14 02:06 khaled

:+1: here too

nervo avatar Jun 19 '14 12:06 nervo

I think it might be impossible for webpack to have a generic node stream interface like browserify and closure. Since webpack can output multiple files and needs to know a bit about the destination, right?

// This wont work
gulp.src('entry.js')
  .pipe(webpack())
  .pipe(rename('output.js'))
  // What about [hash].js? 1.output.js, 2.output.js?
  .pipe(gulp.dest('./dist/file.js'));

Although a stream interface might be possible by outputting virtual files using vinyl which gulp uses (and later Grunt will too).

@sokra Are you open to a PR implementing a vinyl based stream implementation?

shama avatar Jun 29 '14 04:06 shama

@shama A PR to webpack or this repo or gulp-webpack?

sokra avatar Jun 29 '14 07:06 sokra

I see two options:

  1. A PR to webpack that implements a stream interface where one could pipe in a single or multiple entry points. Then stream out virtual files using vinyl that webpack would normally write to the file system.
  2. Modify the webpack node API to emit the contents of the files instead of writing them (unless an option for this already exists?) Then a PR to gulp-webpack that uses that API to write the contents to vinyl based streams.

Or some other option I'm completely missing. I think the main issue is some users just want the contents of the outputted files instead of being first written to the file system.

shama avatar Jun 29 '14 15:06 shama

This way you can stream out webpacks assets:

var File = require('vinyl');
var MemoryFileSystem = require("memory-fs");

var compiler = webpack({...});

var stream = new Stream.Readable();
var fs = compiler.outputFileSystem = new MemoryFileSystem();
compiler.plugin("after-emit", function(compilation, callback) {
  compilation.assets.forEach(function(asset) {
    var path = fs.join(compiler.outputPath, asset.name);
    var contents = fs.readFileSync(path);
    stream.push(new File({
      base: compiler.outputPath,
      path: path,
      contents: contents
    });
  });
  callback();
});
compiler.watch(200, ...);
// or: compiler.run(...);

sokra avatar Jul 02 '14 06:07 sokra

Wow thanks @sokra! I didn't know compiler.outputFileSystem was a thing.

@sindresorhus Would you mind if I gave you a PR for this implementation on gulp-webpack?

shama avatar Jul 02 '14 07:07 shama

@shama it's yours now.

sindresorhus avatar Jul 02 '14 07:07 sindresorhus

Thanks @sindresorhus!

Using https://github.com/shama/gulp-webpack you can now do:

var gulp = require('gulp');
var webpack = require('gulp-webpack');
gulp.task('default', function() {
  return gulp.src('src/entry.js')
    .pipe(webpack())
    .pipe(gulp.dest('dist/'));
});

Let me know of any issues!

shama avatar Jul 02 '14 22:07 shama

@shama We didn't discussed the streaming in part. There are two options to do it:

a) stream -> multi entry point (you implemented this one)

b) stream -> multiple entry points


Example: streamed in files a.js, b.js, dir/c.js

a)

entry: ["/abs/path/a.js", "/abs/path/b.js", "/abs/path/dir/c.js"]

b)

entry {
  a: "/abs/path/a.js",
  b: "/abs/path/b.js",
  "dir/c": "/abs/path/dir/c.js"
}

I would favor b) because I think this is more common.


In addition to this there need to be a way to manually provide a entry option without streaming in files:

var webpack = require("gulp-webpack");

webpack({
  entry: "./manual"
}).pipe(gulp.dest("dist/"));

So depending of the existance of the entry option, gulp-webpack need to be a transform stream or a readable-stream.


Support watch via watch option. This means you cannot end the stream when a single compilation finished in watch mode.


Any optinions on this?

@mnichols @lmartins @jhnns

sokra avatar Jul 03 '14 07:07 sokra

@sokra Both a and b should be possible now with https://github.com/shama/gulp-webpack/commit/d4289086ef6f18ed499ccd58e009c43d52c733ea. It will preference the entry given in the config over the entry files piped in. See https://github.com/shama/gulp-webpack/blob/master/index.js#L41

So the following is now possible (I'll update the readme adding this example too):

gulp.task('webpack', function() {
  return webpack({
      entry: {
        a: "/abs/path/a.js",
        b: "/abs/path/b.js",
        "dir/c": "/abs/path/dir/c.js"
      }
    }))
    .pipe(gulp.dest('tmp/'));
});

I'll look into support for watch mode. FWIW, the current seems to work great used in tandem with gulp's watch: https://github.com/shama/gulp-webpack/blob/master/gulpfile.js

shama avatar Jul 03 '14 15:07 shama

@shama I assume this is broken now. I just tried something like your code above and gulp-webpack returns undefined:

[14:42:15] TypeError: Cannot set property 'outputFileSystem' of undefined
at Stream.<anonymous> (e:\node_modules\gulp-webpack\index.js:127:40)
at _end (e:\node_modules\gulp-webpack\node_modules\through\index.js:65:9)
at Stream.stream.end (e:\node_modules\gulp-webpack\node_modules\through\index.js:74:5)
at module.exports (e:\node_modules\gulp-webpack\index.js:146:12)
at Gulp.<anonymous> (e:\gulpfile.js:21:9)

Since I have this on a gulp watch, it's silently failing. The only way I got something back was to add an error callback on webpack:

gulp.task('default', function() {
    gulp.watch(paths.scripts, ['webpack']);
});
gulp.task('webpack', function() {
return webpack(
        {
            entry: 'simulation/Simulation.js',
            output: {
                filename: "app.js"
            },
            resolve: {
                modulesDirectories: ['node_modules']
            }
        }, function(err, stats) {
            console.log(arguments);
        }
    )
    .pipe(gulp.dest('/js'));
});

nschubach avatar Feb 16 '15 19:02 nschubach

@nschubach Feel free to open an issue on gulp-webpack. Although I can't duplicate your issue. That error hints towards something strange happening to your copy of webpack or gulp. compiler should definitely be defined. I recommend rm -rf node_modules && npm cache clean && npm i and make sure you're using latest versions of things.

@sokra This issue could probably be closed now.

shama avatar Feb 16 '15 20:02 shama

@shama getting the same issue as @nschubach - it took me 2 days to realize theres an error cb, and I get the same error.

jeffijoe avatar Feb 19 '15 09:02 jeffijoe

@shama @nschubach overlooked something.

Second parameter to webpack() is the webpack instance, we gave it the callback, instead of webpack(opts, null, function(..){});

jeffijoe avatar Feb 19 '15 10:02 jeffijoe