入口文件
webpack 打包文件时,可以拆分多个入口文件。
首先安装 lodash 插件
npm install lodash
在入口文件 index.js 配置如下内容:
import imgSrc from "./assets/2.png";
import "./style.css";
import "./style.less";
const img = document.createElement("img");
img.src = imgSrc;
document.body.appendChild(img);
const div = document.createElement("div");
div.style.cssText = "width: 100px; height: 100px; background-color: skyblue;";
div.classList.add("bg");
document.body.appendChild(div);
index2.js 文件内容:
import _ from "lodash"
console.log(_.join([1, 2, 3], " "))
webpack.config.js文件 配置:
entry: {
# 配置生成两个入口文件
index: "./src/index.js",
another: "./src/index2.js"
},
# 文件输出位置
output: {
# 配置打包后,设置入口文件名字。[name] 默认拿到 entry对象的key值,也就是打包后的文件 分别为 index.build.js/index2.build.js
filename: "[name].build.js",
path: path.resolve(__dirname, './dist'),
clean: true, // 每次打包前先删除 dist 目录
// contenthash 表示哈希值
// ext 表示扩展名
assetModuleFilename: "images/[contenthash][ext]"
},
开始打包
npx webpack
# 生成两个入口文件
asset another.build.js 1.38 MiB [emitted] (name: another) // index2.js 引用第三方的包,所以 another.build.js 打包后为 1.38 M
asset index.build.js 10 KiB [emitted] (name: index)
打开 dist 下的 app.html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link href="styles/42827711e5e6d5ca309f.css" rel="stylesheet"></head>
<body>
<script defer src="index.build.js"></script>
<script defer src="another.build.js"></script>
</body>
</html>
然后我们开始在 index.js 文件中使用 lodash 。
import imgSrc from "./assets/2.png";
import "./style.css";
import "./style.less";
import _ from "lodash"
console.log(_.join([1, 2, 3], " "))
const img = document.createElement("img");
img.src = imgSrc;
document.body.appendChild(img);
const div = document.createElement("div");
div.style.cssText = "width: 100px; height: 100px; background-color: skyblue;";
div.classList.add("bg");
document.body.appendChild(div);
重新打包,两份入口文件大小都变大了。原因是两份入口文件都打包了 lodash 库。
npx webpack
# 打包结果
# index.build.js 从 10 k 变成了 1.38 M, 造成重复打包了。
asset index.build.js 1.38 MiB [emitted] (name: index)
asset another.build.js 1.38 MiB [compared for emit] (name: another)
防止重复
两份入口文件,防止重复打包相同的 库 文件代码。
在webpack.config.js 文件,配置 entry。
entry: {
index: {
import: "./src/index.js",
dependOn: 'shared'
},
another: {
import: "./src/index2.js",
dependOn: 'shared'
},
# 当两个入口文件有 lodash 模块时就会抽离出来,并且取名 为 shared.build.js
shared: 'lodash'
},
执行打包命令:
npx webpack
# 这里把 loadash 抽离 到 shared.build.js,其它两份入口文件都变小了。
asset shared.build.js 1.39 MiB [emitted] (name: shared)
asset index.build.js 4.39 KiB [emitted] (name: index)
asset another.build.js 1.45 KiB [emitted] (name: another)
打开 dist 下的 app.html 文件, 三份 js 文件都引入到 app.html里面了。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link href="styles/42827711e5e6d5ca309f.css" rel="stylesheet"></head>
<body>
<script defer src="index.build.js"></script>
<script defer src="another.build.js"></script>
<script defer src="shared.build.js"></script>
</body>
</html>
防止重复(第二种方法)
使用webpack自带的插件 split-chunks-plugin,对公共代码进行抽离。
首先:webpack.config.js entry 恢复原来配置
entry: {
index: "./src/index.js",
another: "./src/index2.js"
}
# 优化配置
optimization: {
# 这里的配置项是实现代码分割,并且保存到单独的一个文件里。
splitChunks: {
chunks: 'all'
}
}
开始打包:
npx webpack
结果:生成了三份 js 文件。lodash 库文件单独抽离出来了。
懒加载
使用 ECMAScript 的 import() 来实现代码分离。
首先创建 math.js 文件。并且添加两个函数
export const add = (x, y) => {
return x + y;
};
export const sub = (x, y) => {
return x - y;
};
在 index.js 入口文件中使用 math.js
const btn = document.createElement("button");
btn.textContent = "按钮";
btn.addEventListener("click", () => {
// /* webpackChunkName: 'math' */ 指定打包后文件名为 math
// 最终文件名为 math.build.js ,这是因为 在 webpack.config.js 配置 output 下的 filename
import(/* webpackChunkName: 'math' */ "./math.js").then(({ add }) => {
console.log(add(1, 2))
});
});
document.body.appendChild(btn);
执行 npx webpack 打包 src 目录下文件。结果如下:生成了 新的 math.build.js
执行 npx webpack-dev-server 启动 web 服务器。页面展示一个按钮,并且点击按钮后,才会加载 math.build.js 文件。
预获取/预加载模块
webpack v4.6.0 版本对预获取和预加载的支持。
在声明 import 时,使用下面这些内置指令,可以让webpack 输出 “resource hint(资源提示)”,来告知浏览器:
- prefetch(预获取):将来某些导航下可能需要的资源。
- preload(预加载):当前导航下可能需要的资源。
prefetch 预加载演示
const btn = document.createElement("button");
btn.textContent = "按钮";
btn.addEventListener("click", () => {
// webpackPrefetch 设置 为 true
import(/* webpackChunkName: 'math', webpackPrefetch: true */ "./math.js").then(({ add }) => {
console.log(add(1, 2))
});
});
document.body.appendChild(btn);
启动 webpack 服务器。
npx webpack-dev-server
默认地址是:127.0.0.1:8080。
刷新浏览器,查看 network,可以发现 math.build.js 已经加载下来。
并且 index.html 文件,增加了 link 标签,链接到 math.build.js 文件。
rel=“prefetch” 这里使用 prefetch 预加载,当我们首页内容加载完毕,在网络空闲的时候,才会加载 link 对应的文件。
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="prefetch" as="script" href="http://127.0.0.1:8080/math.build.js">
</head>
preload 预加载演示
打开 index.js 文件, 在 import() 函数中,加入参数 webpackPreload: true
const btn = document.createElement("button");
btn.textContent = "按钮";
btn.addEventListener("click", () => {
// webpackPreload: true
import(/* webpackChunkName: 'math', webpackPreload: true */ "./math.js").then(({ add }) => {
console.log(add(1, 2))
});
});
document.body.appendChild(btn);
效果和懒加载一样,也是点击按钮后才会加载 math.js 文件。
完整的 webpack.config.js 文件
let path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin")
const MinCssExtractPlugin = require("mini-css-extract-plugin")
const CssMinmizerPlugin = require("css-minimizer-webpack-plugin")
module.exports = {
// 入口文件
entry: {
// index: {
// import: "./src/index.js",
// dependOn: 'shared'
// },
// another: {
// import: "./src/index2.js",
// dependOn: 'shared'
// },
// // 当两个入口文件有 lodash 模块时就会抽离出来,并且取名 为 shared.js
// shared: 'lodash'
index: "./src/index.js",
another: "./src/index2.js"
},
// 打包后文件
output: {
// 配置打包后,入口文件名字
filename: "[name].build.js",
path: path.resolve(__dirname, './dist'),
clean: true, // 每次打包前先删除 dist 目录
// contenthash 表示哈希值
// ext 表示扩展名
assetModuleFilename: "images/[contenthash][ext]"
},
// 模式 development/production
mode: 'development',
// 打包后,可以方便的调试代码。代码的位置和源文件一致。
devtool: "inline-source-map",
// 插件使用。
// HtmlWebpackPlugin 用于自动生成 dist 目录下 index.html 魔板文件
plugins: [
new HtmlWebpackPlugin({
// 根据魔板文件生成
template: "./index.html",
// 生成 dist 目录中 html 的文件名
filename: "app.html",
// 生成的 js 文件 引入到body标签中
inject: "body"
}),
// 把 css 合并成一个文件
new MinCssExtractPlugin({
// 打包文件,放到 dist 下的 styles 目录下
// contenthash 哈希字符串
filename: "styles/[contenthash].css"
})
],
// 指定 dist 作为根路径
devServer: {
static: "./dist"
},
// 配置打包 其它资源文件 规则
module: {
rules: [
{
test: /\.png$/,
type: "asset/resource",
// 打包后文件命名
// 优先级高于 output 下 assetModuleFilename
generator: {
filename: "images/[contenthash][ext]"
}
},
{
test: /\.svg$/,
// 导出资源类型的 dataurl (base64格式)
type: "asset/inline"
},
{
test: /\.txt$/,
// 导出资源的源代码
type: "asset/source"
},
{
test: /\.jpg$/,
// 会根据 resource / inline 两种方式进行选择
// 默认情况下,当资源文件大于 8k 选择 resource 模式生成资源
// 当资源文件小于8k 选择 inline 生成 base64 数据。
type: "asset",
parser: {
dataUrlCondition: {
// 设置临界值,超过 maxSize 就会 使用 asset/resource 模式,否则使用 asset/inline 生成 base64 代码
maxSize: 4 * 1024 * 1024 // 4 M
}
}
},
{
test: /\.(css|less)$/,
// loader 执行顺序是从右到左(三个loader位置不能颠倒)
use: [MinCssExtractPlugin.loader, 'css-loader', 'less-loader']
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
// asset/resource 可以帮助我们载入任何类型的资源
type: "asset/resource"
},
{
test: /\.(csv|tsv)$/,
use: "csv-loader"
},
{
test: /\.xml$/,
use: "xml-loader"
},
{
test: /\.js$/,
// 排除 node_modules 目录下的 js 文件
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"]
}
}
}
]
},
// 优化配置
optimization: {
minimizer: [
new CssMinmizerPlugin()
],
// 实现代码分割,并且保存到单独的一个文件里。
splitChunks: {
chunks: 'all'
}
}
}