0%

Webpack 4 提取页面基础库

背景

使用 Webpack 打包资源时体积过大,通常需要将基础库分离出来。

基础库分离

使用 html-webpack-externals-plugin

使用 html-webpack-externals-pluginreactreact-dom 基础库通过 CDN 引入,不打如 bundle 中

初始化项目

1
npm init -y

安装依赖

1
2
npm install --save react react-dom
npm install --save-dev webpack webpack-cli babel-loader @babel/core @babel/preset-env @babel/preset-react html-webpack-plugin html-webpack-externals-plugin

根目录下新建 webpack.config.js.bablerc

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
30
31
32
33
34
35
36
37
const path = require("path");

const HtmlWebpackExternalsPlugin = require("html-webpack-externals-plugin");

module.exports = {
entry: "./src/index.js",
output: {
path: path.join(__dirname, "dist"),
},
mode: "development",
module: {
rules: [
{
test: /.js$/,
use: "babel-loader",
},
],
},
plugins: [
new HtmlWebpackExternalsPlugin({
externals: [
{
module: "react",
entry:
"https://cdn.bootcss.com/react/16.13.1/umd/react.development.js",
global: "React",
},
{
module: "react-dom",
entry:
"https://cdn.bootcss.com/react-dom/16.13.1/umd/react-dom.development.js",
global: "ReactDOM",
},
],
}),
],
};

.bablerc 内容

1
2
3
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}

根目录下新建 index.html

index.html 内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="root"></div>
<script src="https://cdn.bootcss.com/react/16.13.1/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.13.1/umd/react-dom.development.js"></script>
<script src="./dist/main.js"></script>
</body>
</html>

修改 package.json

package.json 内容

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
{
"name": "webpack-externals",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "webpack",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"react": "^16.13.1",
"react-dom": "^16.13.1"
},
"devDependencies": {
"@babel/core": "^7.9.0",
"@babel/preset-env": "^7.9.5",
"@babel/preset-react": "^7.9.4",
"babel-loader": "^8.1.0",
"html-webpack-externals-plugin": "^3.8.0",
"html-webpack-plugin": "^4.2.0",
"webpack": "^4.42.1",
"webpack-cli": "^3.3.11"
}
}

新建src/index.js

src/index.js 内容

1
2
3
4
5
6
7
8
import React from "react";
import ReactDOM from "react-dom";

function App() {
return <div>Hello, Webpack</div>;
}

ReactDOM.render(<App />, document.getElementById("root"));

执行npm start

此时的 dist 目录中的 main.js 就是只打包了我们自己写的 src/index.js 的内容

不想用 CDN,想使用 node_modules 中的怎么办

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
30
31
32
33
34
35
const path = require("path");

const HtmlWebpackExternalsPlugin = require("html-webpack-externals-plugin");

module.exports = {
entry: "./src/index.js",
output: {
path: path.join(__dirname, "dist"),
},
mode: "development",
module: {
rules: [
{
test: /.js$/,
use: "babel-loader",
},
],
},
plugins: [
new HtmlWebpackExternalsPlugin({
externals: [
{
module: "react",
entry: "umd/react.development.js",
global: "React",
},
{
module: "react-dom",
entry: "umd/react-dom.development.js",
global: "ReactDOM",
},
],
}),
],
};

会在ouput目录下新建一个vendor的目录, 将对应的两个文件拷过去,此时 html 文件中的script引用路径也需要更改

index.html 内容更改为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="root"></div>
<script src="./dist/vendor/react/umd/react.development.js"></script>
<script src="./dist/vendor/react-dom/umd/react-dom.development.js"></script>
<script src="./dist/main.js"></script>
</body>
</html>

webpack 4 中还可以使用SplitChunksPlugin来提取公共资源

使用 SplitChunksPlugin

使用 optimization.SplitChunksPlugin

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
const path = require("path");

module.exports = {
entry: "./src/index.js",
output: {
path: path.join(__dirname, "dist"),
},
mode: "development",
module: {
rules: [
{
test: /.js$/,
use: "babel-loader",
},
],
},
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
name: "vendor",
chunks: "all",
},
},
},
},
};

会在output目录下生成一个vendor.js的文件,在 html 中引用即可

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="root"></div>
<script src="./dist/vendor.js"></script>
<script src="./dist/main.js"></script>
</body>
</html>