目录
  1. 1. 前言
  2. 2. 第一步,创建基本目录
  3. 3. 第二步,安装依赖
  4. 4. 第三步:配置
    1. 4.1. 1. webpack 配置
    2. 4.2. 2. babel 配置
    3. 4.3. 3. 配置命令脚本
  5. 5. 第四步:运行
  6. 6. 其它配置
    1. 6.1. html-webpack-plugin
    2. 6.2. webpack-dev-server
    3. 6.3. CSS相关
      1. 6.3.1. 使用 css 预编译器
      2. 6.3.2. 使用 postcss-loader
      3. 6.3.3. CSS 代码文件分离
    4. 6.4. 加载静态资源
      1. 6.4.1. 加载图片
    5. 6.5. 热模块更新
  7. 7. 模版下载
    1. 7.1. 目录说明
    2. 7.2. 下载
    3. 7.3. 安装依赖
    4. 7.4. 运行
    5. 7.5. 编译输出
Webpack 4 + Babel 7 打造 ES6+ 前端环境

前言

Webpack 4 + Babel 7 打造 ES6+ 前端环境。

如果对配置过程无兴趣或想直接下载模版,快速开始 ES6+ 编程,可直接跳过参考 模版下载


第一步,创建基本目录

src 目录,用于存放自己写的源码。

1
2
3
4
5
6
7
8
demo

└───src # 源码目录
├───main.js # 入口文件
├───js # JS 文件夹
├───css # css 文件夹,如果只需要 ES6 环境不需要页面支持可以省略
├───images # 图片文件夹,如果只需要 ES6 环境不需要页面支持可以省略
├───index.html # 首页模版,如果只需要 ES6 环境不需要页面支持可以省略

第二步,安装依赖

1.创建 package.json 文件

1
2
3
4
5
# demo 项目文件夹内
npm init

# 如果想跳过问题,配置可直接在 package.json 更改
npm init -y

2.安装 webpackwebpack-cli

1
npm i webpack webpack-cli -D
  • i : install 安装命令;
  • -D : --save-dev 开发依赖;

注:webpack 3 中不需要安装 CLIwebpack 包已集成,但在 webpack 4 中已经分开管理,需要分开安装。上述命令安装的版本为 webpack 4,指定版本安装可以执行 npm i webpack@3 -D


3.安装 babel 相关

1
npm i babel-loader @babel/core @babel/preset-env -D
1
npm i @babel/polyfill -S		# 注意,运行时依赖 -S(--save)
  • babel-loader : babel 编译器的 webpack loader;
  • @babel/core : babel 7 的核心代码;
  • @babel/preset-env : babel 智能预设,转换 ES6 语法;
  • @babel/polyfill : 环境垫片,转换 ES6 API等;

第三步:配置

1. webpack 配置

根目录下添加 webpack.config.js 配置文件,配置入口文件和导出设置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const path = require('path');   // 使用 Node 的 path 模块,不需要额外安装,处理绝对路径

module.exports = {
entry: "./src/main.js", // 指定入口文件,等同 { main: "./src/main.js"}
output: {
path: path.resolve(__dirname, 'dist'), // 打包导出目录,必须绝对路径
filename: "[name].bundle.js" // [name],entry 入口属性名即main,也可直接指定名字
},
module: { // 模块配置
rules: [ // 模块规则
{
test: /\.js$/, // 匹配对象,所有js文件
exclude: /node_modules/, // 排除对象,排除 node_modules 目录
loader: "babel-loader" // 使用 babel-loader 编译js文件
}
]
}
}

以上配置包括:

  • 指定入口文件
  • 打包导出设置(目录和文件名)
  • 使用 babel-loader 编译 JS 文件

详细 webpack 配置项可参考官网 webpack.config.js ,十分详细。


2. babel 配置

babel 7 有三种配置方式,任选一种:

  • 添加 babel.config.js 配置文件(官方推荐)
  • 添加 .babelrc 配置文件
  • 直接在 package.json 添加配置

1)根目录下添加 babel.config.js 配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
module.exports = {

presets: [
[
"@babel/preset-env",
{
useBuiltIns: "usage", // 让 @babel/polyfill 按需引入
corejs: 2 // 新版本 polyfill 需要声明 core-js 版本,否则打包会 wanning
}
]
] // 使用babel智能预设

}

2)根目录下添加 .babelrc 配置文件:

1
2
3
4
5
6
7
8
{
"presets": [
["@babel/preset-env",{
"useBuiltIns": "usage",
"corejs": "2"
}]
]
}

3)直接在 package.json 添加配置,键名babel

1
2
3
4
5
6
7
8
9
10
11
12
{
"name": "xxx",
"version": "1.0.0",
"babel": {
"presets": [
["@babel/preset-env",{
"useBuiltIns": "usage",
"corejs": "2"
}]
]
}
}

三种配置方式任选一种,默认编译 ES2015 + 语法。


配置说明:

关于 @babel/polyfill :

Babel 转换 ES6 代码,仅仅只是转换 ES6 的语法,诸如 letconst 、箭头函数、模版字符串、解构赋值等。并不会转换 ES6 的新 API,如GeneratorSetMapsProxyReflectSymbolPromise 等全局对象,还有如 Array.from 等 ES6 新增方法。

如需使用新 API 并且兼容旧浏览器时,就需要使用到 polyfill ,原理则是向全局注入这些新API,即相当于直接调用写好的一个功能函数集,只需引用即可。注意:使用 polyfill 会污染全局环境,如是写类库的同学,请使用 transform-runtime ,参考 babel-plugin-transform-runtime

@babel/polyfill 使用有如下几种:

直接importrequire引用:

1
2
3
// require("@babel/polyfill");
import "@babel/polyfill";
new Promise((resolve, reject) => {});

webpack.config.js 多入口引用 polyfill :

1
2
3
module.exports = {
entry: ["@babel/polyfill", "./src/main.js"],
};

以上两种的缺点:引入了整个 polyfill 包,没用到的 API 也打包进去(不推荐)。

推荐做法参考以下 关于预设的配置 useBuiltIns


关于预设的配置 useBuiltIns

根据官方文档 babel-polyfill

With webpack, there are multiple ways to include the polyfills:

  • When used alongside @babel/preset-env,
    • If useBuiltIns: 'usage' is specified in .babelrc then do not include @babel/polyfill in either webpack.config.js entry array nor source. Note, @babel/polyfill still needs to be installed.
    • If useBuiltIns: 'entry' is specified in .babelrc then include @babel/polyfill at the top of the entry point to your application via require or import as discussed above.
    • If useBuiltIns key is not specified or it is explicitly set with useBuiltIns: false in your .babelrc, add @babel/polyfill directly to the entry array in your webpack.config.js.

@babel/polyfill@babel/preset-env 搭配时,babel预设配置添加 useBuiltIns: "usage" 可以让 polyfill 不需 import ,也会自动将代码里已使用到的,且 browserslist 环境不支持的垫片导入,可以避免打包后文件过大。

注意:添加了 useBuiltIns: "usage" 就不需要再像上述两种引用 polyfill 包了,babel 会自动将 polyfill 自动按需引用打包。而且需要指定 core-js 版本,如上文配置一样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// babel.config.js
module.exports = {

presets: [
[
"@babel/preset-env",
{
useBuiltIns: "usage",
corejs: 2
}
]
]

}

指定浏览器:指定浏览器兼容编译,会很大程度影响编译文件大小,也有两种配置方式。= =

  • presets 添加 targets 指定浏览器;
  • 配置 browserslist (推荐)

Babel 编译优先看有没有配置 targets,再看是否配置 browserslist ,都没有就默认编译所有 ES2015 + 代码。

1)presets 添加 targets ,以 babel.config.js 为例:

1
2
3
4
5
6
7
8
9
10
11
module.exports = {
presets: [
[
"@babel/preset-env",
{
targets: "> 0.25%, not dead"
}
]
]
}
// 表示市场份额>0.25%的而且忽略没有安全更新的浏览器,如IE 10和BlackBerry

or targets 传入对象,指定浏览器最低版本。

1
2
3
4
5
6
7
8
9
10
module.exports = {
presets: [
[
"@babel/preset-env",
{
targets: { chrome: "58", ie: "8" }
}
]
]
}

注意:如果是在 .babelrc 下配置 targets ,所有键名记得加双引号 ““,.babelrc 其实就是个 JSON 文件,写法必须符合 JSON 格式。


2)配置 browserslist 列表

添加 .browserslistrc 配置文件:

1
2
> 0.25%
not dead

or 直接在 package.json 添加配置,键名browserslist :(推荐)

1
2
3
4
5
6
7
8
9
10
{
"name": "xxx",
"version": "1.0.0",
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
}
// Vue-cli 3 的默认浏览器列表配置,参考

总结 Babel 配置,babel.config.js 添加预设配置,package.json 添加 browserslist


3. 配置命令脚本

修改 package.json 文件中的 “script” ,添加 webpack 打包命令;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
"name": "demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "webpack --mode development", // 开发模式打包,不压缩代码
"build": "webpack --mode production" // 生产模式打包,压缩丑化代码
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.6.4",
"@babel/preset-env": "^7.6.3",
"babel-loader": "^8.0.6",
"webpack": "^4.41.2",
"webpack-cli": "^3.3.9"
},
"dependencies": {
"@babel/polyfill": "^7.7.0"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
}

第四步:运行

如果你只是单纯的想要有个 ES6 编码环境,并编译打包 JS 代码,那到这里就算完成啦,接下来就是愉快的敲 ES6 + 代码啦。
比如:

1
2
3
4
5
6
demo

├───src # 源码目录
│ ├───main.js # 入口文件
│ └───js
│ └───util.js # 模块js

模块代码文件 util.js

1
2
3
4
5
6
7
8
9
export function add(a, b) {
return a + b;
}

export function square(n) {
return n * n;
}

// 输出 add、square 功能函数

入口文件 main.js

1
2
3
4
5
6
import { add, square } from "./js/util";  // 引入模块 .js后缀可省略

let num1 = add(10,10);
let num2 = square(10);

console.log(num1, num2); // => "20 100"

运行编译打包:

不压缩丑化代码,运行开发模式打包:

1
npm run dev

或压缩丑化代码,运行生产模式打包:

1
npm run build

运行完毕后,目录会出现一个 dist 目录:

1
2
3
4
5
6
7
8
9
10
11
12
13
demo

├───node_modules # 项目依赖包目录
├───dist # 编译打包出口目录
│ └───main.bundle.js # 编译打包后的文件
├───src # 源码目录
│ ├───main.js # 入口文件
│ └───js # 其它JS 文件夹
│ └───util.js # 模块js
├───babel.config.js # babel 配置文件
├───package-lock.json # 记录实际安装依赖来源及版本
├───package.json # npm 配置文件
└───webpack.config.js # webpack 配置文件

main.bundle.js 即为编译打包好的文件。


其它配置

如果不仅仅只是需要 JS 环境,且需要前端 HTML 支持,或打包 css 文件等。可以按需如下操作:

html-webpack-plugin

这个插件会根据提供的 src/index.html 为模版,将打包好的js 文件通过 script 标签注入到 HTML 文件中,并将生成的 HTML 文件输出到 dist 目录中,不需要手动添加。

安装:

1
npm i html-webpack-plugin -D

配置 webpack.config.js :

1
2
3
4
5
6
7
8
9
10
11
const HtmlWebpackPlugin = require("html-webpack-plugin");   // 引入插件

module.exports = {
// ...
plugins: [
new HtmlWebpackPlugin({
template: "src/index.html", // 你的 HTML 模版文件
filename: "index.html" // 输出 HTML 文件名字,同样会被输出到 dist 目录
})
]
}

更多配置查看官方文档 => html-webpack-plugin

src/index.html 创建 HTML 模版:

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Webpack4 + babel7</title>
</head>
<body>
<h1><a href="https://vincef0ng.cn">Vincent F0ng</a></h1>
</body>
</html>

npm run build :

1
2
3
4
dist

├───index.html # html-webpack-plugin 生成的 html
└───main.bundle.js # 打包 js 文件

html-webpack-plugin 生成的 HTML ,js 文件自动被引入。

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Webpack4 + babel7</title>
</head>
<body>
<h1><a href="https://vincef0ng.cn">Vincent F0ng</a></h1>
<script type="text/javascript" src="main.bundle.js"></script>
</body>
</html>

webpack-dev-server

这个插件可以在创建本地服务器,热更新等,默认根目录为打包输出目录 dist ,也可以自己配置。

安装:

1
npm i webpack-dev-server -D

配置 package.json ,添加 webpack-dev-server 命令 :

1
2
3
4
5
6
7
{
"scripts": {
"dev": "webpack --mode development",
"build": "webpack --mode production",
"start": "webpack-dev-server --open" // --open,浏览器自动打开 localhost 页面;
}
}

以上start 命令是以 webpack-dev-server 命令运行,自动打开 localhost 页面,修改源码保存会自动编译,并刷新页面。

1
npm run start

此时,浏览器会自动打开 localhost:8080 页面,页面即是 dist 文件夹下的 index.html ,现在就可以直接修改 html、js 源码,一保存代码会自动编译,页面也会自动刷新。


--open相关配置及其它配置也可直接在 webpack.config.js 中指定,就不需要在命令中指定 --open 等命令了,键名 devServer

1
2
3
4
5
6
7
8
9
10
module.exports = {
//...
devServer: {
contentBase: path.join(__dirname, 'dist'), // 服务器根目录,只有在你想要提供静态文件时才需要
open: true, // 浏览器自动打开,--open
hot: true, // 热模块更新,--hot
port: 8080, // 指定端口,--port 8080
https: true, // 启动https,--https
}
};

注意,热模块更新(HMR)需要搭配 webpack 内置插件 HotModuleReplacementPlugin 使用,关于热模块更新下文详解 热模块更新。。

更多配置查看官方文档 => webpack-dev-server


CSS相关

加载 CSS 文件需要使用到 css-loaderstyle-loader

1
npm i style-loader css-loader -D
  • css-loader : 解析css文件中的@importurl() 语法,根据文件关系将 CSS 转化成 CommonJS 模块。
  • style-loader : 将css-loader打包好的css以 <style> 标签输出在 <head> 中。

webpack.config.js 添加模块规则:

1
2
3
4
5
6
7
8
9
10
11
12
13
module.exports = {
// ...
module: {
rules: [
// ...
// css 配置
{
test: /\.css$/,
use: ["style-loader", "css-loader"] // 注意loader顺序,从后向前执行。
}
]
}
}

main.js 引入 css 文件:

1
import "./css/style.css";

npm run start 即可以在页面中看到引用的样式啦。

注:使用 style-loader 并不会生成独立 css 文件,css 样式会被打包进 main.bundle.js 文件中,打开dist/index.html 页面时样式才会被 JS 写入 <head> 下的 <style> 标签中。


使用 css 预编译器

  • Sass :安装 sass-loadernode-sass文档
  • Less :安装 less-loaderless文档
  • Stylus : 安装 stylus-loaderstylus

以书写 scss 文件为例,先安装依赖:

1
npm i sass-loader node-sass -D

webpack.config.js 添加模块规则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
module.exports = {
// ...
module: {
rules: [
// babel-loader 配置
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader"
},
// scss-loader 配置
{
test: /\.scss$/,
use: ["style-loader", "css-loader", "sass-loader"]
}
]
}
}

main.js 引入 scss 文件:

1
import "./scss/style.scss";

使用 postcss-loader

PostCSS 是一个 CSS 处理工具,和 Sass 等不同的地方可以用不同的插件扩展css的特性,包括给 CSS 自动加前缀、压缩CSS、使用下一代 CSS 语法等。

这里使用 autoprefixercssnano 插件来自动加css浏览器前缀和压缩css:

1
npm i postcss-loader autoprefixer cssnano -D

webpack.config.js 添加模块规则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
module.exports = {
// ...
module: {
rules: [
// css 配置
{
// test: /\.scss/,
test: /\.css$/,
use: [
"style-loader",
{
loader: 'css-loader',
options: { importLoaders: 1 } // css @import 前使用loader数量,参考下方注意事项
},
{
loader: "postcss-loader",
options: {
plugins: [
require("autoprefixer"), // 添加前缀插件
require("cssnano") // 压缩css插件
]
}
},
// "sass-loader"
]
}
]
}
}

postcss-loader 的配置也可以是单独的配置文件 postcss.config.js ,详情查看文档 postcss-loader


atuoprefixer 会根据上文中提到的 babel配置 中的 browserslist 浏览器列表来添加前缀,本例是在 package.json 添加了浏览器列表:

1
2
3
4
5
6
7
8
9
{
// ...
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
}
// Vue-cli 3 的默认浏览器列表配置,参考

注意:

  • 如果同时有使用 css 预编译器loader的话如 sass-loaderpostcss-loader 应该在sass-loader 之前, css-loader 之后。
  • 配置其他loader的同时,注意 css-loader 要指定 importLoaders 配置,指定使用 css-loader时前面还需要经过几个loader先。不然在css文件中使用 @import 再引入其他css 时会直接跳过其他 loader,问题如下:

原始 Css :

1
2
3
4
5
6
7
8
9
src

├───css
│ ├───style.css
│ └───other.js
├───js
│ └───util.js
├───index.html
└───main.js
1
2
3
4
5
6
7
/* style.css */
@import "other.css";

.app {
display: flex;
justify-content: center;
}

style.css 通过 @import 引入 other.css

1
2
3
4
/* other.css */
body {
background-color: #ccc;
}

npm run start 后打开 HTML 你会发现:

1
2
3
4
<style>body {
background-color: #ccc;
}</style>
<style>.app{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}</style>

明显只有 style.css 中的样式经过了postcss-loader

other.css 虽然被引入了,但是并没有经过 postcss-loader 的压缩和加前缀。所以,应该给 css-loader 指定 importLoaders ,告诉 css-loader 处理引入 css 时应该先经过几个 loader。同理,如果同时使用了 postcss-loadersass-loaderimportLoaders 应该设置为 2


指定 css-loaderimportLoaders 后的运行结果(前缀+压缩):

1
2
<style>body{background-color:#ccc;}</style>
<style>.app{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}</style>

CSS 代码文件分离

上述配置后,打包无论多少css文件,都会被 css-loader 打包进 main.bundle.js 文件中,再由 style-loader 输出至 <head><style> 标签中。如果要将css代码文件分离,可以使用 webpack 提供的其他插件。


注意:由于翻译的滞后性,在 webpack 中文文档中,有些文档如 sass-loader 中文 中,建议我们使用 extract-text-webpack-plugin 插件来css代码分割,中文文档中的 ExtractTextWebpackPlugin 中文 也没有提醒 webpack 4 中并不可用,但是,你阅读英文原文 ExtractTextWebpackPlugin 英文 ,有如下提醒:

:warning: Since webpack v4 the extract-text-webpack-plugin should not be used for css. Use mini-css-extract-plugin instead.

在中文文档中,你甚至找不到 mini-css-extract-plugin 这个插件(= = !!!),所以尽量阅读英文文档,在用webpack 4 时我们应该使用 mini-css-extract-plugin 来进行代码分离。


安装:

1
npm i mini-css-extract-plugin -D

webpack.config.js 替代 style-loader 模块规则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// 1.引入插件
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
// ...
module: {
rules: [
// css 配置
{
test: /\.css$/,
use: [
// "style-loader", 3. 替代 style-loader,单独css文件输出
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: "../", // 资源目录
// hmr: true 热模块更新,根据需求
}
},
{
loader: 'css-loader',
options: { importLoaders: 1 }
},
{
loader: "postcss-loader",
options: {
plugins: [
require("autoprefixer"),
require("cssnano")
]
}
},
// "sass-loader"
]
}
]
},
plugins: [
// ...
// 2. 使用插件
new MiniCssExtractPlugin({
filename: "css/[name].css" // [name] 占位符,为 entry 入口属性,默认 main
})
],
}
  • filename : css 文件输出目录及名字;
  • publicPath : 主目录地址,这与 filename 指定的文件目录有关,因为上述配置了输出文件放在 dist/css 目录中,所以publicPath: "../" 就是将主目录拉回到 dist 目录,即在输出时给资源自动加上 ../,这样css中引入资源才不会有路径问题。
  • hmr : 热模块更新,开发模式下才使用,关于热模块更新下文详解 热模块更新

npm run builddist 文件夹:

1
2
3
4
5
6
7
demo

├───dist
│ ├───css
│ │ └───main.css
│ ├───index.html
│ └───main.bundle.js

输出的 main.css 同样会自动以 <link href="css/main.css" rel="stylesheet"> 自动写入 index.html 的 <head> 中,无需自己手动引用 css 文件。


加载静态资源

webpack 除了 JS 以外,所有的其他格式的文件都需要响应的 loader 来解析,才能做到被 webpack 处理打包。加载图片、字体需要 file-loader,加载数据需要 csv-loaderxml-loader

加载图片

建议使用 url-loaderfile-loader 配合。

安装:

1
npm i url-loader file-loader -D
  • url-loader : 可以将图片转换成 base 64 。
  • file-loader : 图片以文件形式输出。

webpack.config.js 添加模块规则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
module.exports = {
// ...
module: {
rules: [
// 图片配置
{
test: /\.(png|jpg|gif|svg)$/,
loader: "url-loader",
options: {
limit: 8192, // 8 kb
name: "assets/[name]-[hash:8].[ext]" // 默认 dist目录 [hash].[ext]
}
}
]
}
}
  • loader : 配置 url-loader 即可,超过大小的图片会自动使用 file-loader
  • limit : 限制图片大小,单位bite;超过这个输出文件,小于转成 base 64,不宜过大;
  • name : 输出文件名字,可以指定目录,不指定所有图片会被放在 dist 目录下。
  • 占位符[name] : 原始文件名;
  • 占位符[hash:8] : 图片对应哈希值,8 指位数。[hash] 默认是 32位;
  • 占位符[ext] : 文件后缀;

使用:

1
2
3
4
5
6
7
8
9
demo

├───src
│ ├───css
│ │ └───style.css
│ ├───images
│ │ └───bg.jpg
│ ├───index.html
│ └───main.js

入口文件 main.js 引入 style.css , css 内容:

1
2
3
body {
background: url(../images/bg.jpg);
}

npm run build 后:

1
2
3
4
5
6
7
8
9
demo

├───dist
│ ├───assets
│ │ └───bg-87727d5e.jpg
│ ├───css
│ │ └───main.css
│ ├───index.html
│ └───main.bundle.js

main.css 如下:

1
body{background:url(../assets/bg-87727d5e.jpg)}

相对路径及引用都正确被正确识别。


热模块更新

热模块更新(HMR)在上文的 webpack-dev-serverCSS 代码文件分离 中都有提到,如上述在不配置 HMR 的情况下,已经可以做到一修改保存源码,页面自动刷新了。但这样可能会面临这样的问题,比如修改的 JS 或 CSS 代码是在页面中需要 N 步操作后才会显示的,这样我们每修改代码,页面自动刷新,就又要经历 N 步之后才能看到是否正确,尤其是在修改 CSS 样式时。

HMR 就是解决这样的问题,可以保持页面不刷新,只刷新修改的源码部分


第一步:webpack-dev-server 启动 HMR

命令行直接添加 --hot

1
2
3
4
5
6
7
{
"scripts": {
"dev": "webpack --mode development",
"build": "webpack --mode production",
"start": "webpack-dev-server --open --hot"
}
}

或抽离 webpack-dev-server 配置到 webpack.config.js ,键名 devServer

1
2
3
4
5
6
7
{
"scripts": {
"dev": "webpack --mode development",
"build": "webpack --mode production",
"start": "webpack-dev-server" // 配置放到 webpack.config.js
}
}
1
2
3
4
5
6
7
8
9
10
11
// webpack.config.js
module.exports = {
//...
devServer: {
open: true, // 浏览器自动打开
hot: true, // 热模块更新,修改代码编译失败会刷新页面
// hotOnly: true, // 只进行热模块更新,即使编译失败也不刷新页面
// port: 8080, // 指定端口,--port 8080
// https: true, // 启动https,--https
}
};

第二步:使用 webpack 内置插件 HotModuleReplacementPlugin

1
2
3
4
5
6
7
8
9
// webpack.config.js
const webpack = require('webpack'); // 引入webpack

module.exports = {
// ...
plugins: [
new webpack.HotModuleReplacementPlugin() // 使用插件
]
}

关于 CSS 热模块更新,如果是使用 style-loader ,那如上配置即可做到热模块更新了,如果是使用 MiniCssExtractPlugin 插件对 CSS 代码文件分离的话,需要在 loader 的配置加上 hrm: true

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
// ...
module: {
rules: [
// css 配置
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: "../", // 资源目录
hmr: true // 热模块更新
}
},
{
loader: 'css-loader',
options: { importLoaders: 1 }
},
{
loader: "postcss-loader",
options: {
plugins: [
require("autoprefixer"),
require("cssnano")
]
}
}
]
}
]
},
plugins: [
// ...
new MiniCssExtractPlugin({
filename: "css/[name].css" // css 文件输出目录及名字
})
],
}

此时,npm run start 后页面自动打开,修改 JS 或 CSS 后保存,页面就不会自动刷新,而是只有修改的模块代码被更新。


模版下载

模版除了 css 预编译器没有配置外,其它都一致,如需要配置 css 预编译器,安装相应 loader ,配置相应的模块规则即可,参考 #使用 css 预编译器

Github : https://github.com/VincentTV/ES6

目录说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ES6

├───src # 源码目录
│ ├───css # css 目录
│ │ ├───other.css
│ │ └───style.css
│ ├───images # 图片目录
│ │ └───avatar.png
│ ├───js # js 目录
│ │ └───util.css
│ ├───index.html # html 模版
│ └───main.js # 入口文件
├───babel.config.js # babel 配置
├───package-lock.json # 实际依赖及关系
├───package.json # npm 配置
├───webpack.config.js # webpack 配置

下载

1
git clone https://github.com/VincentTV/ES6.git

安装依赖

1
cd ES6
1
npm install

运行

1
npm run start

开始 ES6 编程。

编译输出

1
npm run build
1
2
3
4
5
6
7
8
9
ES6

├───dist
│ ├───assets
│ │ └───avatar-78c62249.png
│ ├───css
│ │ └───main.css
│ ├───index.html
│ └───main.bundle.js

文章作者: Vincent F0ng
文章链接: https://vincef0ng.cn/post/es6-env/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Vincent F0ng

评论(支持Markdown)