简介
鉴于webpack更新太快,总结下基础配置方法,理解有限,仅做抛砖引玉之用。
起步
初始化配置文件 package.json
并安装webpack
mkdir webpack-demo && cd webpack-demo
npm init -y //-y 初始化选项默认为 yes
npm i webpack webpack-cli -D // -D 即 -save-dev 版本4.x以上需要安装webpack-cli
创建以下目录结构、文件和内容:
webpack-demo
|- package.json
+ |- /src
+ |- index.js
//index.js
document.write("Hello webpack4!");
创建webpack配置文件
编写开发环境和生产环境彼此独立的webpack配置文件
先添加三个文件
webpack-demo
|- package.json
+ |- webpack.common.js
+ |- webpack.dev.js
+ |- webpack.prod.js
|- /src
|- index.js
|- /node_modules
1.webpack.common.js
用到两个基本的插件
npm i clean-webpack-plugin html-webpack-plugin -D
clean-webpack-plugin
:打包时自动清除输出文件夹中未用到的文件;html-webpack-plugin
:打包时会自动生成index.html
并替换已有的index.html
,bundle.js也会自行添加到 html 中。
//webpack.common.js
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: 'index'
})
],
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist') //定义输出文件夹dist路径
}
};
2.webpack.dev.js
先安装webpack-merge,用以合并通用配置文件与开发环境配置文件
npm i webpack-merge -D
安装开发服务器devServer
,作用是修改代码后实时重新加载(刷新浏览器)
npm i webpack-dev-server -D
//webpack.dev.js
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
const webpack = require('webpack');
module.exports = merge(common,{
devServer: { //启用开发服务器
contentBase: './dist', //告诉服务器从哪提供内容,只有在想要提供静态文件时才需要
compress: true, //一切服务都启用gzip 压缩
host: '0.0.0.0', //指定使用一个host,可用ip地址访问,没有的话如果别人访问会被禁止。默认localhost。
port: '9999', //指定端口号,如省略,默认为”8080“
hot: true, //启用模块热替换特性
inline: true, //启用内联模式,一段处理实时重载的脚本被插入到bundle中,并且构建消息会出现在浏览器控制台
historyApiFallback: true,//开发单页应用时有用,依赖于HTML5 history API,设为true时所有跳转将指向index.html
},
plugins: [
new webpack.HotModuleReplacementPlugin(), //webpack内置的热更新插件
],
mode: 'development'
});
devServer的更多可选参数-https://www.webpackjs.com/con...
HotModuleReplacementPlugin
模块热替换(Hot Module Replacement)插件,用以在运行时更新发生改变的模块,从而无需进行完全刷新。
3.webpack.prod.js
同样用'webpack-merge'合并通用配置文件与生产环境配置文件
//webpack.prod.js
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common,{
mode: "production"
});
关于mode
此时你可能会注意到配置文件中有个mode项,webpack4中新加,作用如下:
-
--mode production 生产环境
不需要像旧版本一样定义node环境变量
new webpack.DefinePlugin({"process.env.NODE_ENV":JSON.stringify("production") })
ps:许多 library 将通过与 process.env.NODE_ENV 环境变量关联,以决定 library 中应该引用哪些内容。当使用 process.env.NODE_ENV === 'production' 时,一些 library 可能针对具体用户的环境进行代码优化,从而删除或添加一些重要代码。
自动开启一些插件,如:
uglifyjs-webpack-plugin
js代码压缩(所以无需再单独使用)NoEmitOnErrorsPlugin
编译出错时跳过输出,以确保输出资源不包含错误ModuleConcatenationPlugin
webpack3 添加的作用域提升(Scope Hoisting) - --mode development 开发环境
自行定义node环境变量为development
new webpack.DefinePlugin({"process.env.NODE_ENV":JSON.stringify("development") })
使用 eval 构建 module, 提升增量构建速度
自动开启一些插件,如NamedModulesPlugin
使用模块热替换(HMR)时会显示模块的相对路径
具体描述:
Option | Description |
---|---|
development | Sets process.env.NODE_ENV to value development. Enables NamedChunksPlugin and NamedModulesPlugin. |
production | Sets process.env.NODE_ENV to value production. Enables FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin and UglifyJsPlugin. |
none | Opts out of any default optimization options |
启动
在package.json
"scripts" 中添加npm脚本,从而快捷运行开发服务器 | 打包生产环境代码
//package.json
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"private": true,
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack-dev-server --open --config webpack.dev.js",
"build": "webpack --config webpack.prod.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"clean-webpack-plugin": "^0.1.19",
"html-webpack-plugin": "^3.2.0",
"webpack": "^4.15.1",
"webpack-cli": "^3.0.8",
"webpack-dev-server": "^3.1.4",
"webpack-merge": "^4.1.3"
}
}
"start": "webpack-dev-server --open --config webpack.dev.js",
webpack-dev-server 启动开发服务器
--open 打开浏览器
--config webpack.dev.js 设置运行此脚本时执行的配置文件为webpack.dev.js
"build": "webpack --config webpack.prod.js"
webpack 启动webpack
--config webpack.prod.js 设置运行此脚本时执行的配置文件为webpack.prod.js
执行 npm start
此时应该可以看到 Hello webpack4!
执行 npm run build
项目文件夹中自动生成打包后的文件目录(输出文件夹dist)
webpack-demo
|- package.json
|- webpack.common.js
|- webpack.dev.js
|- webpack.prod.js
|- /src
|- index.js
|- /dist
| - index.html
| - app.bundle.js
|- /node_modules
使用sourcemap
sourcemap 能实现打包后的运行代码与源代码的映射,帮助我们debug到原始开发代码。
///webpack.dev.js
module.exports = merge(common,{
devtool: 'cheap-module-eval-source-map',
...
});
大多数时候开发环境用'cheap-module-eval-source-map'是最好的选择,想要完整的功能又不介意构建速度的话就直接用'source-map'。具体的配置项很多,可以是eval,source-map,cheap,module,inline的任意组合。
具体每个参数的作用请查阅官方api:https://webpack.js.org/config...
也可参考这篇文章https://segmentfault.com/a/11... 这里不做详述。
代码分离
把代码分离到不同的 bundle 中,可以按需加载或并行加载这些文件。可用于获取更小的 bundle,以及控制资源加载优先级,如果使用合理,会极大影响加载时间。
三种常用的代码分离方法:
1.入口起点:使用 entry 配置手动地分离代码。
先在src文件夹添加一个文件another-module.js
//another-module.js
import _ from 'lodash';
console.log(
_.join(['Another', 'module', 'loaded!'], ' ')
);
修改index.js
//index.js
import _ from 'lodash';
console.log(
_.join(['index', 'module', 'loaded!'], ' ')
);
用到了lodash,安装下依赖
npm i lodash -S
修改webpack.common.js中entry和output配置
//webpack.common.js
module.exports = {
entry: {
index: './src/index.js',
another: './src/another-module.js'
},
output: {
filename: '[name].bundle.js', //根据入口文件名来定义输出文件名
path: path.resolve(__dirname, 'dist')
}
};
执行 npm run build
将生成如下构建结果:
Hash: 66f57fffc46778f3b145
Version: webpack 4.16.0
Time: 2966ms
Asset Size Chunks Chunk Names
another.bundle.js 70.4 KiB 0 [emitted] another
index.bundle.js 70.4 KiB 1 [emitted] index
index.html 251 bytes [emitted]
[1] (webpack)/buildin/module.js 497 bytes {0} {1} [built]
[2] (webpack)/buildin/global.js 489 bytes {0} {1} [built]
[3] ./src/another-module.js 86 bytes {0} [built]
[4] ./src/index.js 83 bytes {1} [built]
+ 1 hidden module
Child html-webpack-plugin for "index.html":
1 asset
[0] (webpack)/buildin/module.js 497 bytes {0} [built]
[1] (webpack)/buildin/global.js 489 bytes {0} [built]
+ 2 hidden modules
存在的问题:
- 如果入口 chunks 之间包含重复的模块,那些重复模块都会被引入到各个 bundle 中。
- 不够灵活,不能将核心应用程序逻辑动态地拆分代码。
以上两点中,第一点对我们的示例来说无疑是个问题,index.js 和another-module.js中都引入了 lodash,这样就在两个 bundle 中造成重复引用。接着,我们通过使用 SplitChunks 来移除重复的模块。
2.防止重复:使用SplitChunks
去重和分离 chunk。webpack4 之前版本用的是CommonsChunkPlugin
//webpack.common.js
const path = require('path');
module.exports = {
entry: {
index: './src/index.js',
another: './src/another-module.js'
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Production'
})
],
output: {
filename: '[name].bundle.js', //根据入口文件名来定义输出文件名
path: path.resolve(__dirname, 'dist')
},
+ optimization: {
+ splitChunks: {
+ chunks: 'all'
+ }
+ }
};
再次执行npm run build查看效果
...
vendors~another~index.bundle.js 69.5 KiB 0 [emitted] vendors~another~index
another.bundle.js 1.54 KiB 1 [emitted] another
index.bundle.js 1.54 KiB 2 [emitted] index
...
观察打包后文件大小,可以看到index.bundle.js
和another.bundle.js
中已经移除了重复的依赖模块。lodash 被分离到单独的vendors~another~index.bundle.js
chunk中。
3.动态导入:通过模块的内联函数调用来分离代码。
略~。~
分离css
需要用到插件mini-css-extract-plugin
,这个插件会将提取css到单独的文件,根据每个包含css的js文件创建一个css文件,因此,你的样式将不再内嵌到 JS bundle 中。如果你的样式文件大小较大,这会做更快提前加载,因为 CSS bundle 会跟 JS bundle 并行加载。同时还支持按需加载css和SourceMaps.
相较于旧版extract-text-webpack-plugin
插件,mini-css-extract-plugin
的优势有
- 异步加载
- 没有重复的编译
- 更容易使用
- Specific to CSS
- 支持热更新
npm i mini-css-extract-plugin -D
//webpack.common.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
...
plugins: [
new MiniCssExtractPlugin({
filename: "[name].css",
})
],
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../' //可以配置输出的css文件路径
}
},
"css-loader"
]
}
]
}
...
}
注意
,这个插件不兼容style-loader
(用于以<style>标签形式将css-loader内部样式注入到HTML页面)。
如果想在开发环境下使用style-loader
,在生产环境分离css文件,可以这么配置:
//webpack.common.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const devMode = process.env.NODE_ENV !== 'production'
module.exports = {
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css',
})
],
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
'css-loader',
{
loader:"postcss-loader", //本文未用到此loader...
options: { // 如果没有options这个选项将会报错 No PostCSS Config found
plugins: (loader) => []
}
},
'sass-loader',
],
}
]
}
}
很明显我们需要先安装处理样式文件的各种loader
npm i style-loader css-loader postcss-loader node-sass sass-loader -D
这里有个问题,node环境变量process.env.NODE_ENV在webpack.config中其实是undefined,之前提及的mode配置会自动定义这个环境变量,但只能在打包后的js中取到,如何在webpack的配置文件中获取这个值呢,需要引入cross-env
npm i cross-env -D
然后在package.json
的脚本命令中指定环境变量
"start": "cross-env NODE_ENV=development webpack-dev-server --open --config webpack.dev.js",
"build": "cross-env NODE_ENV=production webpack --config webpack.prod.js"
可自行添加css文件,在js中import,执行npm run build查看效果
当然也可以不获取process.env.NODE_ENV
来区分环境,在dev.js和prod.js分别配置处理样式文件的rule就行了,这也是最开始我们分开写开发环境和生产环境的webpack配置文件的原因。这里提及只是方便从低版本webpack迁移到4.x。
在单个文件中提取所有CSS
配合optimization.splitChunks.cacheGroups使用
//webpack.common.js
optimization: {
splitChunks: {
cacheGroups: {
styles: {
name: 'styles',
test: /\.css$/,
chunks: 'all',
enforce: true
}
}
}
}
会额外生成一个styles.bundle.js
按照入口JS来分离css
//webpack.common.js
...
function recursiveIssuer(m) {
if (m.issuer) {
return recursiveIssuer(m.issuer);
} else if (m.name) {
return m.name;
} else {
return false;
}
}
module.exports = {
entry: {
index: './src/index.js',
another: './src/another-module.js'
},
...
optimization: {
splitChunks: {
cacheGroups: {
vendor: { //分离第三方库
test: /[\\/]node_modules[\\/]/,
name: 'lodash',
chunks: 'all'
},
indexStyles: {
name: 'index',
test: (m,c,entry = 'index') => m.constructor.name === 'CssModule' && recursiveIssuer(m) === entry,
chunks: 'all',
enforce: true
},
otherStyles: {
name: 'another',
test: (m,c,entry = 'another') => m.constructor.name === 'CssModule' && recursiveIssuer(m) === entry,
chunks: 'all',
enforce: true
}
}
}
}
};
压缩css
webpack5可能会内置CSS压缩,webpack4需要使用像optimize-css-assets-webpack-plugin
这样的插件。有个问题是设置optimization.minimizer后,会覆盖上文提到的mode配置项提供的默认值,因此需要同时使用JS压缩插件UglifyJsPlugin
npm i optimize-css-assets-webpack-plugin uglifyjs-webpack-plugin -D
//webpack.prod.js
const merge = require('webpack-merge');
const common = require('./webpack.config.js');
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
module.exports = merge(common,{
mode: "production",
optimization: {
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: true // set to true if you want JS source maps
}),
new OptimizeCSSAssetsPlugin({})
],
}
});
缓存
我们都知道浏览器获取资源是比较耗费时间的,所以它会使用一种名为 缓存 的技术。通过命中缓存,以降低网络流量,使网站加载速度更快。如果我们在部署新版本时不更改资源的文件名,浏览器就可能会认为它没有被更新,就会使用它的缓存版本。因此确保 webpack 编译生成的文件能够被客户端缓存,而在文件内容变化后,能够请求到新的文件是很有必要的。
通过使用 output.filename
进行文件名替换,可以确保浏览器获取到修改后的文件。[hash]
替换可以用于在文件名中包含一个构建相关的hash,但是更好的方式是使用[chunkhash]
替换,在文件名中包含一个 chunk相关的hash。遗憾的是chunkhash和热更新不兼容,所以开发环境和生产环境要分开配置。
//webpack.common.js
...
output: {
filename: devMode ? '[name].[hash:8].js': '[name].[chunkhash:8].js', //数字8表示取hash标识符的前八位
chunkFilename: devMode ? '[name].[hash:8].js': '[name].[chunkhash:8].js', //异步模块的文件输出名
path: path.resolve(__dirname, 'dist')
},
...
关于[hash]
和[chunkhash]
的区别,简单来说,[hash]
是编译(compilation)后的hash值,compilation
对象代表某个版本的资源对应的编译进程。项目中任何一个文件改动,webpack就会重新创建compilation
对象,然后计算新的compilation的hash值,所有的编译输出文件名都会使用相同的hash指纹,改一个就一起变。而[chunkhash]
是根据具体模块文件的内容计算所得的hash值,某个文件的改动只会影响它本身的hash指纹,不会影响其他文件。
上文代码分离一节中已经提到了如何将第三方库(比如lodash或react)提取到单独的vendor chunk文件中,因为它们很少像本地的源代码那样频繁修改。利用客户端的长效缓存机制,可以消除请求,减少向服务器获取资源,同时还能保证客户端代码和服务器端代码版本一致。
除了第三方库,webpack在入口模块中,包含了某些样板(boilerplate)
,确切来说就是runtime
和 manifest
。即webpack运行时的引导代码,这部分代码我们也将它单独提取出来。
//webpack.common.js
...
optimization: {
runtimeChunk: 'single', //分离webpack运行时的引导代码
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
}
...
我们删掉another-module.js
,修改index.js
如下
///index.js
import _ from 'lodash';
function component() {
var element = document.createElement('div');
// Lodash, now imported by this script
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
return element;
}
document.body.appendChild(component());
执行npm run build
产生以下输出:
Hash: 131e8681e4403392cb5d
Version: webpack 4.16.1
Time: 744ms
Asset Size Chunks Chunk Names
index.5bc56cae.js 260 bytes 0 [emitted] index
vendors.5d8f5a63.js 69.5 KiB 1 [emitted] vendors
runtime.eb6eb2fb.js 1.42 KiB 2 [emitted] runtime
index.html 316 bytes [emitted]
[1] ./src/index.js 253 bytes {0} [built]
[2] (webpack)/buildin/global.js 489 bytes {1} [built]
[3] (webpack)/buildin/module.js 497 bytes {1} [built]
+ 1 hidden module
Child html-webpack-plugin for "index.html":
1 asset
[2] (webpack)/buildin/global.js 489 bytes {0} [built]
[3] (webpack)/buildin/module.js 497 bytes {0} [built]
+ 2 hidden modules
可以看到编译出的文件名后加上了hash,运行时的引导代码也被单独提取出来了。
接着添加一个print.js
///print.js
export default function print(text) {
console.log(text);
};
修改index.js
///index.js
import _ from 'lodash';
+ import Print from './print';
function component() {
var element = document.createElement('div');
// Lodash, now imported by this script
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
+ element.onclick = Print.bind(null, 'Hello webpack!');
return element;
}
document.body.appendChild(component());
再执行npm run build
构建结果如下:
Hash: a710a54674ea8d4b3263
Version: webpack 4.16.1
Time: 3328ms
Asset Size Chunks Chunk Names
index.15466585.js 327 bytes 0 [emitted] index
vendors.7bde7828.js 69.5 KiB 1 [emitted] vendors
runtime.eb6eb2fb.js 1.42 KiB 2 [emitted] runtime
index.html 316 bytes [emitted]
[1] (webpack)/buildin/global.js 489 bytes {1} [built]
[2] (webpack)/buildin/module.js 497 bytes {1} [built]
[3] ./src/index.js + 1 modules 406 bytes {0} [built]
| ./src/index.js 337 bytes [built]
| ./src/print.js 64 bytes [built]
+ 1 hidden module
Child html-webpack-plugin for "index.html":
1 asset
[2] (webpack)/buildin/global.js 489 bytes {0} [built]
[3] (webpack)/buildin/module.js 497 bytes {0} [built]
+ 2 hidden modules
我们期望的是,只有 index bundle 的 hash 发生变化,然而vendors也跟着变了。这是因为每个 module.id 会基于默认的解析顺序(resolve order)进行增量。也就是说,当解析顺序发生变化,ID 也会随之改变。(官方文档里说runtime的hash也发生了变化,这里并未出现)
可以使用两个插件来解决这个问题。一是NamedModulesPlugin
,将使用模块的路径而不是数字标识符。此插件有助于在开发过程中输出结果的可读性,但执行时间会长一些。二是使用webpack内置插件HashedModuleIdsPlugin
,推荐用于生产环境构建:
const webpack = require('webpack');
...
module.exports = {
...
plugins: [
...
new webpack.HashedModuleIdsPlugin(),
...
],
...
};
接下来,我们可以随意修改index.js的代码或者增删print.js,再进行构建查看hash的变化。
关于css缓存
假如index.js引用了一个index.css文件,它们会共用相同的chunkhash值。这时如果index.js更改了代码,index.css文件就算内容没有任何改变也会重复构建。
我们可以使用MiniCssExtractPlugin
里的contenthash
,保证css文件所处的模块里只要css文件内容不变,其本身就不会重复构建。
new MiniCssExtractPlugin({
filename: "[name].[contenthash:8].css",
chunkFilename: "[name].[contenthash:8].css"
}),
这样基本就完成了webpack的缓存配置。
有个小问题是,当修改index.css文件代码,重新构建后index.js的hash值也一起改变了。。。
尝试了下安装插件WebpackMd5Hash可以解决
npm i webpack-md5-hash -D
but,这个插件可能会引发别的bug,好吧这里先不用,后续补充,有兴趣可自行搜索
Babel
完成了基本的配置文件编写与代码分离,开发中需要用babel将旧的浏览器或环境中的es 2015+代码转换为es5。
需要安装一些依赖。
babel-core //必备的核心库
babel-loader //webpack loader配置必备
babel-preset-env //支持es2015、2016、2017,
babel-preset-stage-0 //默认向后支持 stage-1,stage-2,stage-3,
babel-runtime
babel-plugin-transform-runtime //转译新的API
npm i babel-runtime -S
npm i babel-core babel-loader babel-preset-env babel-preset-stage-0 babel-plugin-transform-runtime -D
创建.babelrc
文件
///.babelrc
{
"presets": [
"env",
"stage-0"
],
"plugins": [
["transform-runtime", {
"helpers": false, //建议为false
"polyfill": false, //是否切换新的内置插件(Promise,Set,Map等)为使用非全局污染的 polyfill,根据你的网站兼容性情况来看,开启会增加很多额外的代码
"regenerator": true //是否切换 generator 函数为不污染全局作用域的 regenerator runtime。
}],
]
}
关于 babel-polyfill 与 babel-plugin-transform-runtime
babel 可以转译新的 JavaScript 语法,但并不会转化BOM里面不兼容的API比如Promise,Set,Symbol,Array.from,async 等。这时就需要 polyfill(软垫片) 来转化这些API
babel-polyfill
会仿效一个完整的 ES2015+ 环境,这样你就可以使用新的内置对象比如 Promise 或WeakMap, 静态方法比如 Array.from 或者 Object.assign, 实例方法比如 Array.prototype.includes 和生成器函数(提供 regenerator 插件)。babel-polyfill
缺点是它通过改写全局prototype的方式实现,会污染全局对象所以不适合第三方库的开发,且打包后代码冗余量比较大,我们可能不需要用到所有的新API,对于现代浏览器有些也不需要polyfill。
babel-plugin-transform-runtime
依赖babel-runtime
,babel编译es6到es5的过程中,babel-plugin-transform-runtime
会自动polyfill es5不支持的特性,这些polyfill包就是在babel-runtime这个包里(这就是为啥babel-runtime
需要作为生产依赖引入(使用 --save))。transform-runtime优点是不会污染全局变量,多次使用只会打包一次,并且统一按需引入依赖,无重复、多余引入。缺点是例如"foobar".includes("foo")等实例方法将不起作用。
React
以react开发为例,如果是搭建新的项目,可以直接安装官方脚手架create-react-app
或者使用阿里的开源ui框架 Ant Design
这里仅仅提一下如何在webpack中配置react开发环境
npm install react react-dom -S
还需要安装
babel-plugin-transform-decorators-legacy //支持修饰符语法 @connect
babel-preset-react //解析react语法
react-hot-loader //react热更新需要在babelrc做配置
///.babelrc
{
"presets": [
"env",
"react",
"stage-0"
],
"plugins": [
["transform-runtime", {
"helpers": false, //建议为false
"polyfill": false, //是否开始polyfill,根据网站兼容性决定是否开启
"regenerator": true
}],
"react-hot-loader/babel", //react热更新插件
"transform-decorators-legacy" //修饰符语法转换插件
]
}
如果之前webpack-dev-server配置正确,这时只要把你的根组件标记为热导出,就能启用react热更新
///index.js
import React from 'react';
import { hot } from 'react-hot-loader';
const App = () => <div>Hello World!</div>
export default hot(module)(App);
别忘了配置babel-loader
///webpack.common.js
module: {
rules: [{
test: /\.jsx?$/,
use: 'babel-loader'
}]
}
未完待续,容老夫喝口水先...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。