webpack / webpack-with-common-libs

webpack with some common libraries
MIT License
339 stars 104 forks source link

Gulp example ignores Gulp! #5

Open indolering opened 10 years ago

indolering commented 10 years ago

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.

sokra commented 10 years ago

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.

sindresorhus commented 10 years ago

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.

indolering commented 10 years ago

@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.

khaled commented 10 years ago

+1 for properly supporting gulp

nervo commented 10 years ago

:+1: here too

shama commented 10 years ago

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?

sokra commented 10 years ago

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

shama commented 10 years ago

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.

sokra commented 10 years ago

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(...);
shama commented 10 years ago

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?

sindresorhus commented 10 years ago

@shama it's yours now.

shama commented 10 years ago

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!

sokra commented 10 years ago

@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

shama commented 10 years ago

@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

nschubach commented 9 years ago

@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'));
});
shama commented 9 years ago

@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.

jeffijoe commented 9 years ago

@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 commented 9 years ago

@shama @nschubach overlooked something.

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