2018-01-10 更新
Webpacket 已到3了, 这里增添更新申明,并申明连系babel-loader
运用的扼要步骤
参考资料
#0. 环境
node: v9.0.0
webpack: ^3.10.0
webpack-dev-server: ^2.10.1
react-hot-loader": ^3.1.3
babel-core: ^6.26.0
babel-loader: ^7.1.2
babel-plugin-import: ^1.6.3
babel-preset-env: ^1.6.1
babel-preset-react: ^6.24.1
#1. 在.babelrc
中增添 react-hot-loader
// .babelrc
{
"plugins": [
"react-hot-loader/babel"
]
}
#2. webpacket.confg.js 中的设置
const path = require('path');
const webpack = require('webpack');
const moment = require('moment')
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const WriteFilePlugin = require('write-file-webpack-plugin');
const publish_date = moment().format("YYYYMMDD")
let config = {
devtool: 'eval-source-map',
resolve: {
extensions: ['.js', '.jsx', '.json']
},
entry: {
app: [
'react-hot-loader/patch',
'./src/index'
]
},
module: {
rules: [
{
test: /\.jsx$/,
exclude: /node_modules/,
use: [{
loader: 'babel-loader'
}]
},
{
test: /\.css$/,
use: [
{ loader: 'style-loader' },
{ loader: 'css-loader' }
]
},
{
test: /\.less$/,
use: [
{ loader: 'style-loader' },
{ loader: "css-loader", },
{ loader: "less-loader" }
]
},
]
},
output: {
path: path.resolve(__dirname, 'dist', publish_date),
filename: '[name].[hash].js',
sourceMapFilename: '[name].[hash].map',
publicPath: '/' + publish_date
},
plugins: [
new WriteFilePlugin(),
new HtmlWebpackPlugin({
title: 'RBAC',
inject: true,
template: './index.html',
filename: 'index.html',
chunksSortMode: 'auto',
minify: false,
hash: false,
xhtml: true,
chunks: ['app'],
cache: true,
showErrors: true,
}),
new CopyWebpackPlugin([
{ from: 'src/assets', to: 'assets' }
]),
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin()
],
devServer: {
contentBase: path.join(__dirname, 'dist', publish_date),
hot: true,
host: '0.0.0.0',
port: 8000,
publicPath: '/' + publish_date,
}
}
module.exports = config;
devServer
的 hot
要设置为true
#3. 要在你的应用程序进口之前增添 react-hot-loader/patch
, 以下:
let config = {
devtool: 'eval-source-map',
resolve: {
extensions: ['.js', '.jsx', '.json']
},
entry: {
app: [
'react-hot-loader/patch',
'./src/index'
]
},
...
...
...
}
在 #2 有完全的设置
#4. 进口文件要如许
// index.js
import React from 'react'
import ReactDOM from 'react-dom'
// 导入HMR
import { AppContainer } from 'react-hot-loader'
import App from './containers/App'
// 定义一个热加载回调函数用于从新衬着进口组件
const render = Component => {
ReactDOM.render(
<AppContainer>
<Component />
</AppContainer>,
document.getElementById('root'),
)
}
// 启动时挪用
render(App)
// 当发送热加载时挪用, Webpack打包的临盆环境不会有 `module.hot`, 因而这块代码在开辟环境
// 下面的if块内里的代码不会实行
if (module.hot) {
module.hot.accept('./containers/App', () => {
render(App)
})
}
#5. .babelrc
中的 modules
属性
modules
属性必须要设置为 false
, 不然HMR无效
{
"presets": [
["env", { "modules": false }],
"react"
],
"plugins": [
["import", { "libraryName": "antd", "libraryDirectory": "es", "style": "css" }],
"react-hot-loader/babel"
]
}
#6. 最新假如你不必babel, 直接在设置文件中设置 react-hot-loader/webpack
加载器
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.jsx?$/,
use: ['react-hot-loader/webpack'],
},
],
},
}
更新终了
命令行
命令行体式格局是最简朴的体式格局, 假如项目只是纯Web前端, 运用这类体式格局是最便利的. 只须要在package.json
文件中的scripts
内里增添下面一行就能够了.
直接命令行:
webpack-dev-server --content-base=www --inline --watch --hot --progress --config webpack.config.js
经由过程 npm run dev
或 yarn run dev
:
// package.json
"scripts": {
"dev": "webpack-dev-server --content-base=www --inline --watch --hot --progress --config webpack.config.js",
...
},
参数申明:
--content-base
: 静态资本的目次, 为output.path
设置的目次.output: { path: path.resolve(__dirname, 'dist'), },
--watch
: 看管情势, Web实行完打包后不退出, 一向监听文件变化,Ctrl + S
后自动构建变化的模块, 及其依靠模块.--hot
: 开启模块热替代.--progress
: 显现进度--config
: 指定设置文件webpack.config.js
为默许文件名.
Webpack API
API的体式格局须要对webpack.config.js
设置文件举行修正, 增添HotModuleReplacementPlugin
插件.
Webpack 1.x
const path = require('path');
const webpack = require('webpack');
module.exports = {
context: path.join(__dirname, 'js'),
entry: [
'./index.js',
'webpack/hot/dev-server',
'webpack-dev-server/client?http://localhost:8080/',
],
output: {
path: path.join(__dirname, 'www'),
filename: 'bundle.js',
publicPath: '/',
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
],
};
Webpack 2.x
Webpack 2.x 须要一个分外设置 .babelrc
, 增添 react-hot-loader/babel
:
{
"presets": [
"es2015",
"react",
"stage-0"
],
"plugins": [
"react-hot-loader/babel"
]
}
webpack.config.js
模块加载器的设置, 和Webpack 1.x是差别的:
rules: [
// Javascript模块加载器
{
test: /\.js|jsx$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
cacheDirectory : true,
presets: [
['es2015', {modules: false}]
],
// ES7
plugins: [
// 模块动态导入
'syntax-dynamic-import',
'transform-async-to-generator',
'transform-regenerator',
// 运行时转换
'transform-runtime'
]
}
}
},
中间件
须要编写一个Express服务器, 而且把 webpack-dev-middleware
集成到本身的服务器中. 多用于须要高度定制的场景, 实际上之前的webpack-dev-server
就是运用的 webpack-dev-middleware
来完成的, 这里能够证实.
const express = require('express');
const webpackDevMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware');
const webpack = require('webpack');
const webpackConfig = require('./webpack.config.js');
const app = express();
const compiler = webpack(webpackConfig);
app.use(webpackDevMiddleware(compiler, {
// 启用热更
hot: true,
filename: 'bundle.js',
publicPath: '/assets/',
stats: {
colors: true,
},
// 路由须要的
historyApiFallback: true,
}));
app.use(webpackHotMiddleware(compiler, {
log: console.log,
path: '/__webpack_hmr',
heartbeat: 10 * 1000,
}));
app.get('/', function(req, res) {
res.send('<body>Hello World<script src=\'assets/bundle.js\'></script></body>');
});
const server = app.listen(3000, function() {
const host = server.address().address;
const port = server.address().port;
console.log('Example app listening at http://%s:%s', host, port);
});
关于这类情势的热更, 须要合营运用 webpack-hot-middleware
.
Javascript 模块的热替代
须要在进口文件内里增添 module.hot.accept
设置, 下面给出进口文件的完全代码:
import React from 'react';
import ReactDOM from 'react-dom';
import {
BrowserRouter as Router
Route,
Link
} from 'react-router-dom'; // React Router v4 版本.
import App from './App';
import { AppContainer } from 'react-hot-loader';
const render = (Component) => {
ReactDOM.render(
<AppContainer>
<Component />
</AppContainer>,
document.getElementById('App')
);
}
render(App);
if (module.hot) {
module.hot.accept('./App', () => { render(App) });
}
本来直接挂载App
, 要运用HMR, 须要在外层包一个<AppContainer>
容器.
多端同步革新
这个视频, 是Chrome, Safari, Firefox 三端同步操作的示例.
关于须要支撑全平台(挪动, 桌面, Web)的开辟, 能够运用 BrowerSync 这个神器. 它经由过程 Websocket 同步事宜.
起首, 把模块包括进来:
const BrowserSyncPlugin = require('browser-sync-webpack-plugin');
其次, 设置插件:
new BrowserSyncPlugin({
host: 'localhost',
port: 3000,
// server: { // 自力服务器情势, 这里我运用的代办情势, 解释掉了
// baseDir: ['dist'] // 看管的目次, 个中假如文件发生变化, 革新页面
// },
proxy: 'http://localhost:8080/'
}, {
name: 'dev',
reload: false // 不让 BrowerSync 革新页面, 让 webpack-dev-server 治理页面是不是须要革新.
}),
这里我运用代办情势, 由于除了 BrowerSync 的功用外, 我还要运用 webpack-dev-server
HMR功用. 详细设置参考: https://github.com/Va1/browse…
参考:
https://github.com/search?utf…
https://github.com/webpack/we…
https://github.com/glenjamin/…
http://acgtofe.com/posts/2016…
https://github.com/Va1/browse…