Skip to content

Commit fddb41b

Browse files
frenzzyokendoken
authored andcommitted
Update webpack to v3 (#1329)
1 parent 9b64871 commit fddb41b

File tree

4 files changed

+267
-121
lines changed

4 files changed

+267
-121
lines changed

package.json

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
"babel-cli": "^6.24.1",
6060
"babel-core": "^6.25.0",
6161
"babel-eslint": "^7.2.3",
62-
"babel-loader": "^7.0.0",
62+
"babel-loader": "^7.1.0",
6363
"babel-plugin-istanbul": "^4.1.4",
6464
"babel-plugin-rewire": "^1.1.0",
6565
"babel-preset-env": "^1.5.2",
@@ -75,20 +75,19 @@
7575
"cross-env": "^5.0.1",
7676
"css-loader": "^0.28.4",
7777
"editorconfig-tools": "^0.1.1",
78-
"enzyme": "^2.8.2",
78+
"enzyme": "^2.9.1",
7979
"eslint": "^3.19.0",
8080
"eslint-config-airbnb": "^15.0.1",
81-
"eslint-import-resolver-node": "^0.3.0",
82-
"eslint-loader": "^1.7.1",
81+
"eslint-import-resolver-node": "^0.3.1",
82+
"eslint-loader": "^1.8.0",
8383
"eslint-plugin-css-modules": "^2.7.1",
84-
"eslint-plugin-import": "^2.3.0",
84+
"eslint-plugin-import": "^2.6.0",
8585
"eslint-plugin-jsx-a11y": "^5.0.3",
8686
"eslint-plugin-react": "^7.0.1",
8787
"file-loader": "^0.11.2",
8888
"front-matter": "^2.1.2",
8989
"glob": "^7.1.2",
90-
"json-loader": "^0.5.4",
91-
"lint-staged": "^3.6.1",
90+
"lint-staged": "^4.0.0",
9291
"markdown-it": "^8.3.1",
9392
"mkdirp": "^0.5.1",
9493
"mocha": "^3.4.2",
@@ -98,15 +97,15 @@
9897
"node-sass": "4.5.0",
9998
"pixrem": "^3.0.2",
10099
"pleeease-filters": "^4.0.0",
101-
"postcss": "^6.0.1",
100+
"postcss": "^6.0.3",
102101
"postcss-calc": "^6.0.0",
103102
"postcss-color-function": "^4.0.0",
104103
"postcss-custom-media": "^6.0.0",
105104
"postcss-custom-properties": "^6.0.1",
106105
"postcss-custom-selectors": "^4.0.1",
107106
"postcss-flexbugs-fixes": "^3.0.0",
108107
"postcss-import": "^10.0.0",
109-
"postcss-loader": "^2.0.5",
108+
"postcss-loader": "^2.0.6",
110109
"postcss-media-minmax": "^3.0.0",
111110
"postcss-nested": "^2.0.2",
112111
"postcss-nesting": "^4.0.1",
@@ -126,10 +125,11 @@
126125
"stylelint": "^7.11.0",
127126
"stylelint-config-standard": "^16.0.0",
128127
"stylelint-order": "^0.5.0",
129-
"url-loader": "^0.5.8",
130-
"webpack": "^2.6.1",
128+
"svg-url-loader": "^2.0.2",
129+
"url-loader": "^0.5.9",
130+
"webpack": "^3.0.0",
131131
"webpack-bundle-analyzer": "^2.8.2",
132-
"webpack-dev-middleware": "^1.10.2",
132+
"webpack-dev-middleware": "^1.11.0",
133133
"webpack-hot-middleware": "^2.18.0",
134134
"webpack-node-externals": "^1.6.0"
135135
},
@@ -153,7 +153,14 @@
153153
"rewire"
154154
]
155155
}
156-
}
156+
},
157+
"ignore": [
158+
"/node_modules/",
159+
"/build/chunks/",
160+
"/build/public/",
161+
"/build/updates/",
162+
"/build/server.js"
163+
]
157164
},
158165
"lint-staged": {
159166
"*.{cmd,html,json,md,sh,txt,xml,yml}": [

tools/start.js

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import path from 'path';
1111
import express from 'express';
1212
import browserSync from 'browser-sync';
1313
import webpack from 'webpack';
14-
import logApplyResult from 'webpack/hot/log-apply-result';
1514
import webpackDevMiddleware from 'webpack-dev-middleware';
1615
import webpackHotMiddleware from 'webpack-hot-middleware';
1716
import createLaunchEditorMiddleware from 'react-error-overlay/middleware';
@@ -24,7 +23,7 @@ const isDebug = !process.argv.includes('--release');
2423
// https://webpack.js.org/configuration/watch/#watchoptions
2524
const watchOptions = {
2625
// Watching may not work with NFS and machines in VirtualBox
27-
// Uncomment next line if it's your case (use true or interval in milliseconds)
26+
// Uncomment next line if it is your case (use true or interval in milliseconds)
2827
// poll: true,
2928

3029
// Decrease CPU or memory usage in some file systems
@@ -75,11 +74,12 @@ async function start() {
7574
clientConfig.output.filename = clientConfig.output.filename.replace('chunkhash', 'hash');
7675
clientConfig.output.chunkFilename = clientConfig.output.chunkFilename.replace('chunkhash', 'hash');
7776
clientConfig.module.rules = clientConfig.module.rules.filter(x => x.loader !== 'null-loader');
78-
const { query } = clientConfig.module.rules.find(x => x.loader === 'babel-loader');
79-
query.plugins = ['react-hot-loader/babel'].concat(query.plugins || []);
77+
const { options } = clientConfig.module.rules.find(x => x.loader === 'babel-loader');
78+
options.plugins = ['react-hot-loader/babel'].concat(options.plugins || []);
8079
clientConfig.plugins.push(
8180
new webpack.HotModuleReplacementPlugin(),
8281
new webpack.NoEmitOnErrorsPlugin(),
82+
new webpack.NamedModulesPlugin(),
8383
);
8484

8585
// Configure server-side hot module replacement
@@ -126,26 +126,36 @@ async function start() {
126126
});
127127

128128
function checkForUpdate(fromUpdate) {
129-
return app.hot.check().then((updatedModules) => {
130-
if (updatedModules) {
131-
return app.hot.apply().then((renewedModules) => {
132-
logApplyResult(updatedModules, renewedModules);
133-
checkForUpdate(true);
134-
});
129+
const hmrPrefix = '[\x1b[35mHMR\x1b[0m] ';
130+
if (!app.hot) {
131+
throw new Error(`${hmrPrefix}Hot Module Replacement is disabled.`);
132+
}
133+
if (app.hot.status() !== 'idle') {
134+
return Promise.resolve();
135+
}
136+
return app.hot.check(true).then((updatedModules) => {
137+
if (!updatedModules) {
138+
if (fromUpdate) {
139+
console.info(`${hmrPrefix}Update applied.`);
140+
}
141+
return;
135142
}
136-
if (fromUpdate) {
137-
return console.info('[HMR] Update applied.');
143+
if (updatedModules.length === 0) {
144+
console.info(`${hmrPrefix}Nothing hot updated.`);
145+
} else {
146+
console.info(`${hmrPrefix}Updated modules:`);
147+
updatedModules.forEach(moduleId => console.info(`${hmrPrefix} - ${moduleId}`));
148+
checkForUpdate(true);
138149
}
139-
return console.warn('[HMR] Cannot find update.');
140150
}).catch((error) => {
141151
if (['abort', 'fail'].includes(app.hot.status())) {
142-
console.warn('[HMR] Cannot apply update.');
152+
console.warn(`${hmrPrefix}Cannot apply update.`);
143153
delete require.cache[require.resolve('../build/server')];
144154
// eslint-disable-next-line global-require, import/no-unresolved
145155
app = require('../build/server').default;
146-
console.warn('[HMR] App has been reloaded.');
156+
console.warn(`${hmrPrefix}App has been reloaded.`);
147157
} else {
148-
console.warn(`[HMR] Update failed: ${error.stack || error.message}`);
158+
console.warn(`${hmrPrefix}Update failed: ${error.stack || error.message}`);
149159
}
150160
});
151161
}

tools/webpack.config.js

Lines changed: 92 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ const isDebug = !process.argv.includes('--release');
1818
const isVerbose = process.argv.includes('--verbose');
1919
const isAnalyze = process.argv.includes('--analyze') || process.argv.includes('--analyse');
2020

21+
const stylesRegExp = /\.(css|less|scss|sss)$/;
22+
const staticAssetName = isDebug ? '[path][name].[ext]?[hash:8]' : '[hash:8].[ext]';
23+
2124
//
2225
// Common configuration chunk to be used for both
2326
// client-side (client.js) and server-side (server.js) bundles
@@ -42,14 +45,17 @@ const config = {
4245
},
4346

4447
module: {
48+
// Make missing exports an error instead of warning
49+
strictExportPresence: true,
50+
4551
rules: [
4652
{
4753
test: /\.jsx?$/,
4854
loader: 'babel-loader',
4955
include: [
5056
path.resolve(__dirname, '../src'),
5157
],
52-
query: {
58+
options: {
5359
// https://github.com/babel/babel-loader#options
5460
cacheDirectory: isDebug,
5561

@@ -87,8 +93,14 @@ const config = {
8793
],
8894
},
8995
},
96+
97+
// Handle internal/project styles (from src folder)
9098
{
91-
test: /\.css/,
99+
// Internal Styles
100+
test: stylesRegExp,
101+
include: [
102+
path.resolve(__dirname, '../src'),
103+
],
92104
use: [
93105
{
94106
loader: 'isomorphic-style-loader',
@@ -109,6 +121,8 @@ const config = {
109121
},
110122
],
111123
},
124+
125+
// Handle external/third-party styles (from node_modules)
112126
{
113127
test: /theme.scss$/,
114128
loaders: [
@@ -118,7 +132,7 @@ const config = {
118132
],
119133
},
120134
{
121-
test: /\.scss$/,
135+
test: stylesRegExp,
122136
exclude: [/theme.scss$/],
123137
use: [
124138
'isomorphic-style-loader',
@@ -128,26 +142,62 @@ const config = {
128142
],
129143
},
130144
{
131-
test: /\.md$/,
132-
loader: path.resolve(__dirname, './lib/markdown-loader.js'),
145+
test: /\.(bmp|gif|jpe?g|png)$/,
146+
issuer: stylesRegExp,
147+
loader: 'url-loader',
148+
options: {
149+
name: staticAssetName,
150+
limit: 4096, // 4kb
151+
},
133152
},
153+
154+
// Inline small SVGs into CSS as UTF-8 encoded DataUrl string
134155
{
135-
test: /\.txt$/,
136-
loader: 'raw-loader',
156+
test: /\.svg$/,
157+
issuer: stylesRegExp,
158+
loader: 'svg-url-loader',
159+
options: {
160+
name: staticAssetName,
161+
limit: 4096, // 4kb
162+
},
137163
},
164+
165+
// Return public URL to large images otherwise
138166
{
139-
test: /\.(ico|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2)(\?.*)?$/,
167+
test: /\.(bmp|gif|jpe?g|png|svg)$/,
168+
issuer: { not: [stylesRegExp] },
140169
loader: 'file-loader',
141-
query: {
142-
name: isDebug ? '[path][name].[ext]?[hash:8]' : '[hash:8].[ext]',
170+
options: {
171+
name: staticAssetName,
143172
},
144173
},
174+
175+
// Convert plain text into module
145176
{
146-
test: /\.(mp4|webm|wav|mp3|m4a|aac|oga)(\?.*)?$/,
147-
loader: 'url-loader',
148-
query: {
149-
name: isDebug ? '[path][name].[ext]?[hash:8]' : '[hash:8].[ext]',
150-
limit: 10000,
177+
test: /\.txt$/,
178+
loader: 'raw-loader',
179+
},
180+
181+
// Convert markdown into html
182+
{
183+
test: /\.md$/,
184+
loader: path.resolve(__dirname, './lib/markdown-loader.js'),
185+
},
186+
187+
// Return public URL for all assets unless explicitly excluded
188+
// DO NOT FORGET to update `exclude` list when you adding a new loader
189+
{
190+
exclude: [
191+
/\.jsx?$/,
192+
/\.json$/,
193+
stylesRegExp,
194+
/\.(bmp|gif|jpe?g|png|svg)$/,
195+
/\.txt$/,
196+
/\.md$/,
197+
],
198+
loader: 'file-loader',
199+
options: {
200+
name: staticAssetName,
151201
},
152202
},
153203

@@ -166,16 +216,19 @@ const config = {
166216

167217
cache: isDebug,
168218

219+
// Specify what bundle information gets displayed
220+
// https://webpack.js.org/configuration/stats/
169221
stats: {
222+
cached: isVerbose,
223+
cachedAssets: isVerbose,
224+
chunks: isVerbose,
225+
chunkModules: isVerbose,
170226
colors: true,
171-
reasons: isDebug,
172227
hash: isVerbose,
173-
version: isVerbose,
228+
modules: isVerbose,
229+
reasons: isDebug,
174230
timings: true,
175-
chunks: isVerbose,
176-
chunkModules: isVerbose,
177-
cached: isVerbose,
178-
cachedAssets: isVerbose,
231+
version: isVerbose,
179232
},
180233

181234
// Choose a developer tool to enhance debugging
@@ -222,6 +275,10 @@ const clientConfig = {
222275
}),
223276

224277
...isDebug ? [] : [
278+
// Decrease script evaluation time
279+
// https://github.com/webpack/webpack/blob/master/examples/scope-hoisting/README.md
280+
new webpack.optimize.ModuleConcatenationPlugin(),
281+
225282
// Minimize all JavaScript output of chunks
226283
// https://github.com/mishoo/UglifyJS2#compressor-options
227284
new webpack.optimize.UglifyJsPlugin({
@@ -280,6 +337,12 @@ const serverConfig = {
280337
libraryTarget: 'commonjs2',
281338
},
282339

340+
// Webpack mutates resolve object, so clone it to avoid issues
341+
// https://github.com/webpack/webpack/issues/4817
342+
resolve: {
343+
...config.resolve,
344+
},
345+
283346
module: {
284347
...config.module,
285348

@@ -288,9 +351,9 @@ const serverConfig = {
288351
if (rule.loader === 'babel-loader') {
289352
return {
290353
...rule,
291-
query: {
292-
...rule.query,
293-
presets: rule.query.presets.map(preset => (preset[0] !== 'env' ? preset : ['env', {
354+
options: {
355+
...rule.options,
356+
presets: rule.options.presets.map(preset => (preset[0] !== 'env' ? preset : ['env', {
294357
targets: {
295358
node: pkg.engines.node.match(/(\d+\.?)+/)[0],
296359
},
@@ -302,12 +365,12 @@ const serverConfig = {
302365
};
303366
}
304367

305-
if (rule.loader === 'file-loader' || rule.loader === 'url-loader') {
368+
if (rule.loader === 'file-loader' || rule.loader === 'url-loader' || rule.loader === 'svg-url-loader') {
306369
return {
307370
...rule,
308-
query: {
309-
...rule.query,
310-
name: `public/assets/${rule.query.name}`,
371+
options: {
372+
...rule.options,
373+
name: `public/assets/${rule.options.name}`,
311374
publicPath: url => url.replace(/^public/, ''),
312375
},
313376
};
@@ -321,7 +384,7 @@ const serverConfig = {
321384
'./assets.json',
322385
nodeExternals({
323386
whitelist: [
324-
/\.(css|less|scss|sss)$/i,
387+
stylesRegExp,
325388
],
326389
}),
327390
],

0 commit comments

Comments
 (0)