webpack在2018年2月25号发布最新的4.0版本, 更新了以下内容:

  • 性能大幅提升(没感觉..)
  • 新增mode配置, 可选择设置为development和production, 实现零配置启动(意义不大…)
  • 废弃CommonsChunkPlugin, 使用optimize.splitChunks和optimization.runtimeChunk替代
  • 支持WebAssembly
  • 支持CommonJS, AMD, ESM等模块系统, 可以直接导入.mjs扩展名的模块文件, 对wasm模块也有实验性的支持

今天我将自己维护的React脚手架从webpack2升级到了4, 记录一下需要改动的地方. 本篇是”不完全指南”, 欢迎补充更多内容

升级依赖版本

  • webpack: 2.2.1 -> 4.1.1
  • webpack-dev-middleware: 1.10.0 -> 3.0.1
  • html-webpack-plugin: 2.28.0 -> 3.0.6
  • extract-text-webpack-plugin: 2.0.0 -> 4.0.0-beta.0
  • copy-webpack-plugin: 4.0.1 -> 4.5.1
  • react-hot-loader: 3.0.0-beta.7 -> 4.0.0

webpack config添加mode字段

// webpack.config.js
module.exports = {
    mode: 'development' // 或者 production
}

删除UglifyJsPlugin插件

在mode: production下, 会自动进行代码压缩. 可以修改配置项 optimization.minimize: 'on'/'off' 控制是否启用, 修改配置项 optimization.minimizer: {} 调整默认行为

删除CommonsChunkPlugin插件

替代为配置项 optimization.splitChunks, 可配置内容如下:

最简单的配置

optimization: {
    splitChunks: {
        chunks: 'all',
    },
}

手动定制vendor内容

module.exports = {
    entry: {
        vendor: ['react', 'react-dom', 'redux']
    },
    optimization: {
        splitChunks: {
            cacheGroups: {
                vendor: {
                    chunks: 'initial',
                    name: 'vendor',
                    test: 'vendor',
                    enforce: true,
                },
            },
        },
    },
}

字符串或者正则匹配控制vendor内容

module.exports = {
    entry: {
        vendor: ['react', 'react-dom', 'redux']
    },
    optimization: {
        splitChunks: {
            cacheGroups: {
                vendor: {
                    chunks: 'initial',
                    name: 'vendor',
                    test: path.resolve(__dirname, '../node_modules'), // 或者 test: /node_modules/
                    enforce: true,
                },
            },
        },
    },
}

函数控制vendor内容

module.exports = {
    entry: {
        vendor: ['react', 'react-dom', 'redux']
    },
    optimization: {
        splitChunks: {
            cacheGroups: {
                vendor: {
                    chunks: 'initial',
                    name: 'vendor',
                    test: module => /node_modules/.test(module.context),
                    enforce: true,
                },
            },
        },
    },
}

react-hot-loader

原来的写法是:

// index.js
import React from 'react';
import ReactDom from 'react-dom';
import { AppContainer } from 'react-hot-loader';
import App from './App';
const render = (Component) => {
    ReactDom.render(
        <AppContainer>
            <Component />
        </AppContainer>,
        document.getElementById('app'),
    );
};
render(App);
if (module.hot) {
    module.hot.accept('./App', () => { render(App); });
}
// App.jsx
import React, { Component } from 'react';
export default class App extends Component {
    render() {
        return <div>App</div>
    }
}

现在改为:

// index.js
import React from 'react';
import ReactDom from 'react-dom';
import App from './App';
ReactDom.render(
    <App />,
    document.getElementById('app'),
);
// App.jsx
import React, { Component } from 'react';
import { hot } from 'react-hot-loader';
import Hello from './components/Hello';
class App extends Component {
    render() {
        return <div>App</div>
    }
}
export default hot(module)(App);

还有, 在webpack html-webpack-plugin-after-emit事件回调中, 删除 hotMiddleware.publish({ action: 'reload' }); 语句