From ff117b7ed660408b67a410c101c73aa0f85932d3 Mon Sep 17 00:00:00 2001 From: Naoyuki Kanezawa Date: Thu, 29 Dec 2016 03:16:52 +0900 Subject: [PATCH] Webpack 2 (#449) * upgrade webpack * fix WatchRemoveEventPlugin for webpack2 * use webpack2 for building for files * bump webpack * bump webpack * monkeypatch watchpack --- gulpfile.js | 24 ++--- package.json | 2 +- .../plugins/watch-remove-event-plugin.js | 93 +++++++++++++++---- server/build/webpack.js | 32 ++++--- 4 files changed, 108 insertions(+), 43 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 2325e05a..f4acef00 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -5,7 +5,8 @@ const cache = require('gulp-cached') const notify_ = require('gulp-notify') const benchmark = require('gulp-benchmark') const sequence = require('run-sequence') -const webpack = require('webpack-stream') +const webpack = require('webpack') +const webpackStream = require('webpack-stream') const del = require('del') const jest = require('gulp-jest') @@ -88,29 +89,28 @@ gulp.task('build', [ gulp.task('build-prefetcher', ['compile-lib', 'compile-client'], () => { return gulp .src('client/next-prefetcher.js') - .pipe(webpack({ - quiet: true, + .pipe(webpackStream({ output: { filename: 'next-prefetcher-bundle.js' }, plugins: [ - new webpack.webpack.DefinePlugin({ + new webpack.DefinePlugin({ 'process.env': { NODE_ENV: JSON.stringify('production') } }) ], module: { - loaders: [ + rules: [ { test: /\.js$/, exclude: /node_modules/, - loader: 'babel', - query: { - 'babelrc': false, - 'presets': [ + loader: 'babel-loader', + options: { + babelrc: false, + presets: [ ['env', { - 'targets': { + targets: { // All browsers which supports service workers - 'browsers': ['chrome 49', 'firefox 49', 'opera 41'] + browsers: ['chrome 49', 'firefox 49', 'opera 41'] } }] ] @@ -118,7 +118,7 @@ gulp.task('build-prefetcher', ['compile-lib', 'compile-client'], () => { } ] } - })) + }, webpack)) .pipe(gulp.dest('dist/client')) .pipe(notify('Built release prefetcher')) }) diff --git a/package.json b/package.json index 4f4f0987..8196c6e9 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "strip-ansi": "3.0.1", "styled-jsx": "0.3.0", "url": "0.11.0", - "webpack": "1.14.0", + "webpack": "2.2.0-rc.3", "webpack-dev-middleware": "1.9.0", "webpack-hot-middleware": "2.14.0", "write-file-webpack-plugin": "3.4.2" diff --git a/server/build/plugins/watch-remove-event-plugin.js b/server/build/plugins/watch-remove-event-plugin.js index c4a237dc..f0b30e3a 100644 --- a/server/build/plugins/watch-remove-event-plugin.js +++ b/server/build/plugins/watch-remove-event-plugin.js @@ -10,26 +10,24 @@ export default class WatchRemoveEventPlugin { apply (compiler) { compiler.removedFiles = [] - compiler.plugin('environment', () => { - if (!compiler.watchFileSystem) return + if (!compiler.watchFileSystem) return - const { watchFileSystem } = compiler - const { watch } = watchFileSystem + const { watchFileSystem } = compiler + const { watch } = watchFileSystem - watchFileSystem.watch = (files, dirs, missing, startTime, options, callback, callbackUndelayed) => { - const result = watch.call(watchFileSystem, files, dirs, missing, startTime, options, (...args) => { - compiler.removedFiles = this.removedFiles - this.removedFiles = [] - callback(...args) - }, callbackUndelayed) + watchFileSystem.watch = (files, dirs, missing, startTime, options, callback, callbackUndelayed) => { + const result = watch.call(watchFileSystem, files, dirs, missing, startTime, options, (...args) => { + compiler.removedFiles = this.removedFiles + this.removedFiles = [] + callback(...args) + }, callbackUndelayed) - const watchpack = watchFileSystem.watcher - watchpack.fileWatchers.forEach((w) => { - w.on('remove', this.onRemove.bind(this, watchpack, w.path)) - }) - return result - } - }) + const watchpack = watchFileSystem.watcher + watchpack.fileWatchers.forEach((w) => { + w.on('remove', this.onRemove.bind(this, watchpack, w.path)) + }) + return result + } } onRemove (watchpack, file) { @@ -38,3 +36,64 @@ export default class WatchRemoveEventPlugin { watchpack._onChange(file) } } + +// monkeypatching watchpack module to fix +// https://github.com/webpack/watchpack/pull/33 + +let DirectoryWatcher +try { + DirectoryWatcher = require('webpack/node_modules/watchpack/lib/DirectoryWatcher') +} catch (err) { + DirectoryWatcher = require('watchpack/lib/DirectoryWatcher') +} + +/* eslint-disable */ +var FS_ACCURENCY = 10000; + +function withoutCase(str) { + return str.toLowerCase(); +} + +DirectoryWatcher.prototype.setFileTime = function setFileTime(filePath, mtime, initial, type) { + var now = Date.now(); + var old = this.files[filePath]; + + this.files[filePath] = [initial ? Math.min(now, mtime) : now, mtime]; + + // we add the fs accurency to reach the maximum possible mtime + if(mtime) + mtime = mtime + FS_ACCURENCY; + + if(!old) { + if(mtime) { + if(this.watchers[withoutCase(filePath)]) { + this.watchers[withoutCase(filePath)].forEach(function(w) { + if(!initial || w.checkStartTime(mtime, initial)) { + w.emit("change", mtime); + } + }); + } + } + } else if(!initial && mtime && type !== "add") { + if(this.watchers[withoutCase(filePath)]) { + this.watchers[withoutCase(filePath)].forEach(function(w) { + w.emit("change", mtime); + }); + } + } else if(!initial && !mtime) { + delete this.files[filePath]; + if(this.watchers[withoutCase(filePath)]) { + this.watchers[withoutCase(filePath)].forEach(function(w) { + w.emit("remove"); + }); + } + } + if(this.watchers[withoutCase(this.path)]) { + this.watchers[withoutCase(this.path)].forEach(function(w) { + if(!initial || w.checkStartTime(mtime, initial)) { + w.emit("change", filePath, mtime); + } + }); + } +}; +/* eslint-enable */ diff --git a/server/build/webpack.js b/server/build/webpack.js index 2a599778..7623e08f 100644 --- a/server/build/webpack.js +++ b/server/build/webpack.js @@ -51,6 +51,14 @@ export default async function createCompiler (dir, { dev = false, quiet = false const minChunks = pages.filter((p) => p !== documentPage).length const plugins = [ + new webpack.LoaderOptionsPlugin({ + options: { + context: dir, + customInterpolateName (url, name, opts) { + return interpolateNames.get(this.resourcePath) || url + } + } + }), new WriteFilePlugin({ exitOnErrors: false, log: false, @@ -66,7 +74,6 @@ export default async function createCompiler (dir, { dev = false, quiet = false if (dev) { plugins.push( - new webpack.optimize.OccurrenceOrderPlugin(), new webpack.HotModuleReplacementPlugin(), new webpack.NoErrorsPlugin(), new DetachPlugin(), @@ -104,7 +111,7 @@ export default async function createCompiler (dir, { dev = false, quiet = false mainBabelOptions.presets.push(require.resolve('./babel/preset')) } - const loaders = (dev ? [{ + const rules = (dev ? [{ test: /\.js(\?[^?]*)?$/, loader: 'hot-self-accept-loader', include: [ @@ -126,13 +133,13 @@ export default async function createCompiler (dir, { dev = false, quiet = false exclude (str) { return /node_modules/.test(str) && str.indexOf(nextPagesDir) !== 0 }, - query: { + options: { name: 'dist/[path][name].[ext]' } }, { - loader: 'babel', + loader: 'babel-loader', include: nextPagesDir, - query: { + options: { babelrc: false, cacheDirectory: true, sourceMaps: dev ? 'both' : false, @@ -150,7 +157,7 @@ export default async function createCompiler (dir, { dev = false, quiet = false } }, { test: /\.js(\?[^?]*)?$/, - loader: 'babel', + loader: 'babel-loader', include: [dir, nextPagesDir], exclude (str) { return /node_modules/.test(str) && str.indexOf(nextPagesDir) !== 0 @@ -165,7 +172,7 @@ export default async function createCompiler (dir, { dev = false, quiet = false path: join(dir, '.next'), filename: '[name]', libraryTarget: 'commonjs2', - publicPath: dev ? '/_webpack/' : null, + publicPath: '/_webpack/', devtoolModuleFilenameTemplate ({ resourcePath }) { const hash = createHash('sha1') hash.update(Date.now() + '') @@ -176,28 +183,27 @@ export default async function createCompiler (dir, { dev = false, quiet = false } }, resolve: { - root: [ + modules: [ nodeModulesDir, join(dir, 'node_modules') ].concat( (process.env.NODE_PATH || '') .split(process.platform === 'win32' ? ';' : ':') + .filter((p) => !!p) ) }, resolveLoader: { - root: [ + modules: [ nodeModulesDir, join(__dirname, 'loaders') ] }, plugins, module: { - loaders + rules }, devtool: dev ? 'inline-source-map' : false, - customInterpolateName: function (url, name, opts) { - return interpolateNames.get(this.resourcePath) || url - } + performance: { hints: false } } if (config.webpack) {