基本用法
webpack dev server 是 webpack 提供的用于本地開發(fā)的工具浪藻,它支持代碼熱更新留晚,能迅速將更改后的代碼更新到瀏覽器中疚宇。在這個(gè)模式下客冈,構(gòu)建后的代碼在內(nèi)存中旭从,不會(huì)寫入硬盤,所以讀寫速度快了很多场仲。
要使用 dev server和悦,首先需要安裝:yarn add webpack-dev-server -D
,然后在 package.json
中配置運(yùn)行命令:
{
"scripts": {
"start": "NODE_ENV=development webpack-dev-server --progress"
}
}
或者在命令行執(zhí)行 NODE_ENV=development ./node_modules/.bin/webpack-dev-server --progress
渠缕。
--progress
只能在命令行中生效鸽素,表示展示構(gòu)建過程的進(jìn)度。前面當(dāng)然還需要指定 NODE_ENV 用來(lái)處理環(huán)境相關(guān)的邏輯亦鳞。
除了使用命令行啟動(dòng) dev server 之外馍忽,還有一種更可控的方式,用 node 啟動(dòng):
const open = require('open');
const webpack = require('webpack');
const WebpackDevServer = require('webpack-dev-server');
const webpackConfig = require('../webpack.config');
const compiler = webpack(webpackConfig);
const server = new WebpackDevServer(compiler, {
contentBase: [
'release', // webpackConfig.RELEASE_PATH
'mock-server' // webpackConfig.MOCK_SERVER_BASE
],
hot: true,
historyApiFallback: true,
stats: {
colors: true
}
});
server.listen('8080'/* webpackConfig.DEVELOPMENT_PORT */, '0.0.0.0'/* webpackConfig.DEVELOPMENT_IP */, function(err) {
if (err) {
console.log(err);
} else {
const address = server.listeningApp.address();
const url = 'http://' + address.address + ':' + address.port;
console.log('server started: ' + url);
open(url + '/html/index.html');
}
});
listen 中傳入 ip 和 port燕差,為了能夠同時(shí)開發(fā)多個(gè)項(xiàng)目遭笋,我試用了 Math.floor(Math.random() * 65536)
,但是 webpack-dev-server@2.x 可以指定端口號(hào)為 0 來(lái)使用一個(gè)可用端口徒探。
在啟動(dòng)服務(wù)器后瓦呼,我們使用 open
模塊打開了一個(gè)頁(yè)面,這是用命令行方式啟動(dòng)的時(shí)候做不到的刹帕。
開啟代碼熱更新
熱更新需要每個(gè)模塊都支持吵血。
常見的 js 模塊的更新策略是重新執(zhí)行,并且尋找依賴自己的那些模塊偷溺,每個(gè)模塊都重新執(zhí)行一遍蹋辅,直到所有相關(guān)模塊都重新執(zhí)行為止。webpack dev server 中有現(xiàn)成的插件能實(shí)現(xiàn)這個(gè)邏輯挫掏。因?yàn)椴恍枰覀優(yōu)槊總€(gè) js 文件編寫更新邏輯侦另。
使用下面的配置可以支持默認(rèn)的熱更新:
在 dev server 配置中添加
hot: true
和inline: true
在 plugins 中添加 HotModuleReplacementPlugin
const webpack = require('webpack');
module.exports = {
// ...
plugins: [
// ...
new webpack.HotModuleReplacementPlugin()
]
// ...
}
- 在每個(gè) entry 的頂部添加文件
webpack/hot/dev-server
和webpack-dev-server/client?http://${DEVELOPMENT_IP}:${DEVELOPMENT_PORT}
module.exports = {
entry: {
page1: [
'webpack/hot/dev-server', // 或者 webpack/hot/only-dev-server
'webpack-dev-server/client?http://' + DEVELOPMENT_IP + ':' + DEVELOPMENT_PORT
// ... 其他 entry
]
// ...
}
// ...
}
webpack/hot/dev-server
和 webpack/hot/only-dev-server
的區(qū)別是在某些模塊不支持熱更新的情況下,前者會(huì)自動(dòng)刷新頁(yè)面尉共,后者不會(huì)刷新頁(yè)面褒傅,而是在控制臺(tái)輸出熱更新失敗。
針對(duì) react 模塊的熱更新
使用 react-hot-loader 模塊能夠更新 react 組件袄友,并且保留 state殿托。比如可以做到在 react 彈窗組件出現(xiàn)的情況下,調(diào)整彈窗內(nèi)的元素剧蚣,彈窗不關(guān)閉而看到最新的結(jié)果支竹,當(dāng)然彈窗是否出現(xiàn)需要維護(hù)在 state 或者 store 中旋廷。
這需要額外進(jìn)行一些配置。react-hot-loader 目前最新版本是 1.3.1礼搁,支持上述特性的是 3.x 版本饶碘,作者已經(jīng)完成了 3.x 的開發(fā),但是由于文檔不完善等原因遲遲沒有發(fā)布正式版本馒吴。
為了使用 react-hot-loader@3.x 你需要這樣修改配置:
安裝 react-hot-loader@next扎运。
yarn add react-hot-loader@next -D
在 react 主入口的頂部添加
<AppContainer>{/* */}</AppContainer>
。從原先的render(<App/>)
修改為
import { render } from 'react-dom';
import { AppContainer } from 'react-hot-loader';
import App from '../entry/App';
render(
<AppContainer>
<App/>
</AppContainer>,
document.getElementById('root')
);
- 添加
react-hot-loader/webpack
loader
module.exports = {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loaders: [
'babel-loader',
'react-hot-loader/webpack'
]
}
]
}
- 在每個(gè) entry 的最前面添加
react-hot-loader/patch
module.exports = {
entry: {
page1: [
'react-hot-loader/patch',
'webpack/hot/dev-server', // 或者 webpack/hot/only-dev-server
'webpack-dev-server/client?http://' + DEVELOPMENT_IP + ':' + DEVELOPMENT_PORT
// ... 其他 entry
]
// ...
}
// ...
}
- 在 react 主入口 js 文件中實(shí)現(xiàn)
module.hot.accept
// page/index.js
import { render } from 'react-dom';
import { AppContainer } from 'react-hot-loader';
import App from '../entry/App';
render(
<AppContainer>
<App/>
</AppContainer>,
document.getElementById('root')
);
if (module.hot) {
module.hot.accept('./page/index', () => {
const RootContainer = require('../entry/App').default;
render(
<AppContainer>
<App/>
</AppContainer>,
document.getElementById('root')
);
});
}
注意 react-hot-loader 不支持 decorate 過的組件饮戳,比如不能使用 @connect
豪治。