前言
这篇文章是学习笔记类型,内容会逐级深入,看完后可以对webpack有基本认知,且可以自行对项目进行配置。
一、初步使用
1. 初始化
在项目终端输入npm init -y
命令,会自动创建并初始化package.json
、README.en.md
、README.md
文件
npm init -y
2. 修改配置
初始化完成后,需要对内容进行修改,main
后面的路径需要改成项目对应的路径
package.json
{
"name": "study-webpack",
"version": "1.0.0",
"description": "webpack学习",
"main": "./src/main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://gitee.com/dream-seller-andy/study-webpack.git"
},
"keywords": [],
"author": "",
"license": "ISC"
}
注意:name
值不能为webpack
,否则会无法安装webpack
3. 安装插件
安装webpack
、webpack-cli
两个插件,运行以下命令
npm i webpack webpack-cli -D
4. 打包
输入npx webpack
打包,因为没有配置文件,所以需要在npx webpack
后面添加入口文件路径
和打包模式
,这是最基础的打包配置,仅能转译js
和json
文件,webpack5
新增了可以打包图片等静态文件功能
开发模式
打包,可以把es6
语法编译成浏览器可识别的低版本语法,不会
对文件进行压缩
npx webpack ./src/main.js --mode=development
生产模式
打包,可以把es6
语法编译成浏览器可识别的低版本语法,并且会
对文件进行压缩
npx webpack ./src/main.js --mode=production
这样,一个最基本的包就生成了
二、深入学习
准备工作里的打包方式,显然不是我们想要的,我们需要的是能够定制化的,功能更全面的,实用性更好的方式,而想要达到这个目的,就需要对webpack
进行具体的配置了。
1. 基础配置
在项目根目录创建一个webpack.config.js
文件,并配置相关信息
const path = require("path"); // node.js核心模块,主要用来解析路径问题
module.exports = {
// 入口
entry: "./src/main.js", // 相对路径
// 出口
output: {
path: path.resolve(__dirname, "dist"), // 文件输出路径-绝对路径
filename: "main.js", // 文件名-命名随意
clean: true, // 打包前自动删除上一次打包文件
},
// 加载器,用来处理webpack自带不能处理的文件,webpack官网有很多loader可添加
module: {
rules: [],
},
// 插件,用来优化打包性能
plugins: [],
// 模式,开发模式或生成模式
mode: "development",
};
2. Loader
- 注意1:所有用到的
loader
都需要安装,官网示例未必是完整的 - 注意2:所有需要打包的文件都需要在
main.js
中先引入 - 注意3:
type
后面的asset
表示压缩,对于字体图标等不需要压缩的文件,需要使用asset/resource
以css-loader
、sass-loader
举例:
安装以下loader
npm install style-loader css-loader --save-dev
npm install sass-loader sass webpack --save-dev
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.css$/,
type: "asset",
use: ["style-loader", "css-loader"],
},
{
test: /\.s[ac]ss$/,
type: "asset",
use: ["style-loader", "css-loader", "sass-loader"],
},
],
},
};
这样,webpack
就可以打包.css
、.sass
、.scss
结尾的文件了,如需添加其它类型的文件,只需要继续在数组中添加新的对象即可,记住,一定要安装所有用到的loader
优化1:减少浏览器请求次数
把项目内体积比较小的图片文件,转换成base64
格式,此方法会增加一定的图片体积,大约20%左右,不过相比较增加请求次数,这点确定还是可以接受的
webpack5
已经内置了图片处理,所以不需要额外下载loader
,但是需要进行配置激活
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.(png|jpe?g|svg|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024, // 10kb,小于10kb会被转译成base64
},
},
},
],
},
};
优化2:分类输入不同类型的文件
为了打包后文件不至于太过混乱,对于不同类型的文件,分别用一个文件夹保存,这个功能需要对每种类型的文件都单独配置出口路径
webpack.config.js
module.exports = {
output: {
path: path.resolve(__dirname, "dist"),
filename: "static/js/main.js",
clean: true,
},
module: {
rules: [
{
test: /\.(png|jpe?g|svg|gif|webp)$/,
type: "asset",
generator: {
// hash:文件名不重复,且不超过10位、ext:保留后缀名、query:保留url地址中自行添加的方便搜索的?等字符
filename: "static/images/[hash:10][ext][query]",
},
},
{
test: /\.(ttf|woff2?)$/,
type: "asset/resourse",
generator: {
filename: "static/media/[hash:10][ext][query]",
},
},
],
},
};
案例1:处理字体图标、音视频等文件
webpack.config.js
rules: [
{
test: /\.(ttf|woff2?|map3|map4|avi)$/,
type: "asset/resourse",
generator: {
filename: "static/media/[hash:10][ext][query]",
},
},
],
案例2:babel-loader
作用:将ES6
语法转译成ES5
语法,详情可查看 babel-loader 官方文档
babel-loader
运行很慢,我们需要用一些方法来进行优化,优化的方法会在第4节:优化
中进行详细去说,此处就不做赘述了
安装babel-loader
npm install -D babel-loader @babel/core @babel/preset-env webpack
webpack.config.js
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
},
],
在项目根目录创建babel.config.js
文件,为了方便以后管理和修改,babel-loader
配置信息写在babel.config.js
文件中,内容设置为只能预设,如下方展示代码
babel.config.js
module.exports = {
presets: ["@babel/preset-env"],
};
案例3:postcss-loader
作用:处理 css
兼容性,使其兼容更多版本的浏览器, 详情可查看 postcss-loader 官方文档
安装postcss-loader
npm install postcss-loader postcss postcss-preset-env --save-dev
使用postcss-loader
,因为这个模块可能会多次重复使用,为了提高代码的美观度和复用性,我们把这个模块封装成一个函数,需要使用的时候直接调用即可
webpack.prod.js
function getStyleLoader(loader) {
return [
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: ["postcss-preset-env"],
},
},
},
loader,
].filter(Boolean);
}
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: getStyleLoader(),
},
{
test: /\.s[ac]ss$/,
type: "asset",
use: getStyleLoader("sass-loader"),
},
],
},
};
在 package.json
文件中添加以下内容,指定需要兼容哪些浏览器,以下代码表示兼容同时满足列举出的 3
个条件的浏览器,这也是目前较为普遍使用的兼容性处理方案
- 99% 以上
- 最近两个版本
- 没有退市
package.json
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
3. Plugin
实际项目开发过程中有很多插件需要用到,本文只列举其中几个进行举例
插件1:EslintWebpackPlugin
作用:用来查找和修复js
代码中的问题,详情可查看
EslintWebpackPlugin 官方文档
安装eslint
和eslint-webpack-plugin
npm install eslint eslint-webpack-plugin --save-dev
创建.eslint.js
和.eslintignore
文件,分别用来配置校验规则
和指定不校验的文件
.eslint.js
module.exports = {
extends: ["eslint:recommended"], // 继承 Eslint 官方校验规则,也可以选择继承 vue、react 等其它校验规则
env: {
node: true, // 开启 node 全局变量
browser: true, // 开启浏览器全局变量
},
parserOptions: {
ecmaVersion: 6, // es6语法
sourceType: "module", // es6模块
},
// 自定义规则会覆盖继承的规则
rules: {
"no-var": 2,
},
plugins: ["import"],
};
.eslintignore
dist
使用eslint-webpack-plugin
webpack.config.js
const ESLintPlugin = require('eslint-webpack-plugin');
module.exports = {
plugins: [
// 仅校验src目录下的文件
new ESLintPlugin({
context: path.resolve(__dirname, "src"),
}),
],
};
插件2:HtmlWebpackPlugin
作用:自动生成一个 HTML5
文件, 并在 body
中使用 script
标签引入你所有 webpack
生成的 bundle
,详情可查看 HtmlWebpackPlugin官方文档
安装HtmlWebpackPlugin
npm install --save-dev html-webpack-plugin
使用HtmlWebpackPlugin
webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
plugins: [
// 保持和public/index.html中的文件结构一致
new HtmlWebpackPlugin({
template: path.resolve(__dirname, 'public/index.html')
}),
],
};
提示:建议以下插件在看完 “开发模式和生产模式” 内容后再看,因为会涉及到这方面的知识点
插件3:MiniCssExtractPlugin
作用:本插件会将 CSS 提取到单独的文件中,为每个包含 CSS 的 JS 文件创建一个 CSS 文件,并且支持 CSS 和 SourceMaps 的按需加载,详情可查看 MiniCssExtractPlugin 官方文档
提示:如果不提取 css
,css
会打包在 main.js
文件中
- 注意1:本插件基于
webpack v5
的新特性构建,并且需要webpack 5
才能正常工作 - 注意2:将所有的
style-loader
都改成MiniCssExtractPlugin.loader
- 注意3:此插件仅推荐在生产模式
production
中使用,在开发模式development
下,style-loader
拥有更快的速度,且可以使用多个标签将 CSS 插入到 DOM 中
安装 mini-css-extract-plugin
npm install --save-dev mini-css-extract-plugin
使用 mini-css-extract-plugin
webpack.prod.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
{
test: /\.s[ac]ss$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
},
],
},
plugins: [
// 指定css文件名
new MiniCssExtractPlugin({
filename: "static/css/main.css",
}),
],
};
插件4:CssMinimizerWebpackPlugin
作用:使用 cssnano
优化和压缩 CSS
,详情可查看 CssMinimizerWebpackPlugin 官方文档
安装 css-minimizer-webpack-plugin
npm install css-minimizer-webpack-plugin --save-dev
使用 css-minimizer-webpack-plugin
webpack.prod.js
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
module.exports = {
plugins: [
new CssMinimizerPlugin()
]
};
配置到了这一步,其实已经可以看到效果了,这时候在项目终端输入npx webpack
命令,会自动打包输入一个dist
文件夹,打开文件夹里的index.html
文件即可看到项目运行的效果
npx webpack
4. devServer
在配置完Loader
和Plugin
后,我们还需要开启前端本地服务,以方便查看效果和调试,这时候就需要配置devServer
信息了
webpack.config.js
module.exports = {
devServer: {
host: 'localhost',
port: '8080',
open: true
},
};
在添加devServer
之前,我们启动项目的命令是npx webpack
,但是此方法不是实时的,每次修改内容后都需要重新输入并执行命令,这显然是不利于项目开发调试的
使用了 devServer
之后,启动项目的命令变成了 npx webpack server
,这个命令不会输出 dist
文件,但是可以启动一个本地服务,在浏览器中访问这个地址 http://localhost:8080/ ,即可查看项目运行效果(也可以通过配置 open:true
来自动打开页面),此方法是实时更新的,不需要反复输入命令,每次修改保存后的内容,都会同步反映到浏览器中
npx webpack server
三、开发模式和生产模式
上面的学习已经比较全面了,但是项目在开发过程中和最终生产上线还是会有不少的区别,为了能够更精细的去管理和控制,我们需要进一步的优化
在根目录下创建config
文件夹,并在此文件夹中分别创建webpack.dev.js
和webpack.prod.js
文件,内容与之前的webpack.config.js
基本一致,部分配置需要调整
- 调整1:所有的绝对路径都要改成相对路径
- 调整2:
webpack.dev.js
中的clean:true
删除,mode
设置为development
- 调整2:
webpack.prod.js
中的devServer
模块删除,mode
设置为production
以下示例只展示了修改的部分,并非是webpack.dev.js
或webpack.prod.js
的全部内容
webpack.dev.js
const path = require("path");
const ESLintPlugin = require("eslint-webpack-plugin");
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: "./src/main.js", // 相对路径
output: {
path: undefined,
filename: "static/js/main.js",
},
plugins: [
new ESLintPlugin({
context: path.resolve(__dirname, "../src"),
}),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../public/index.html')
})
],
devServer: {
host: 'localhost',
port: '8080',
open: true
},
mode: "development",
};
webpack.prod.js
const path = require("path");
const ESLintPlugin = require("eslint-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: "./src/main.js", // 相对路径
output: {
path: path.resolve(__dirname, "../dist"),
filename: "static/js/main.js",
clean: true,
},
plugins: [
new ESLintPlugin({
context: path.resolve(__dirname, "../src"),
}),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../public/index.html"),
}),
],
mode: "production",
};
四、优化
1. 非性能优化
方式1:添加源代码映射,方便定位问题
在 webpack 中配置 Devtool ,可以控制是否生成,以及如何生成 source map,当出现错误的时候,浏览器可以提示错误代码出现的位置,详细内容可查看 Devtool 官方文档
webpack.dev.js
module.exports = {
// ...
devtool: "cheap-module-source-map", // 只映射行,位置模糊,编译速度快
};
webpack.prod.js
module.exports = {
// ...
devtool: "source-map", // 映射行和列,位置精确,编译速度慢
};
方式2:js兼容性
在之前我们已经使用了 babel-loader
对 js
进行了兼容性处理,但 babel-loader
并不能处理所有的兼容性,某些 ES6
新特性,是无法进行处理的,这时候我们需要借助 core-js
对遗漏部分进行补充
安装 core-js
npm install core-js@3 --save
使用 core-js
babel.config.js
module.exports = {
presets: [
[
"@babel/preset-env",
{
useBuiltIns: "usage", // 自动按需引入
corejs: 3, // core-js 第3版
},
],
],
};
2. 提高编译速度
方式1:模块热更新
我们发现,在当前未作处理的情况下,每次修改内容,都会整个项目重新加载编译,如果可以让只做修改的部分重新编译,其它部分不做改变,速度就会提升很多
webpack5
默认开启热更新模块,但是默认只能编译 style-loader
中内置的样式模块 ,如果需要实现 js
热更新模块,则需要手动添加
注意:热模块更新只能用在开发环境
下
webpack.dev.js
module.exports = {
// ...
devServer: {
// ...
hot: true, // 也可以不写,默认为true
},
};
在入口文件 main.js
中,将所有引入的 js
文件都设置一遍,以下代码仅为示例
main.js
import add from "./js/count.js";
import store from "./store/index.js"
// 判断是否支持热模块更新,如果支持,则重新引入
if (module.hot) {
module.hot.accept("./js/count.js");
module.hot.accept("./store/index.js");
}
到这里我们会有一个疑惑,如果引入的 js
文件有几百个,难道要把这几百个文件全部重新引入一遍吗?
答案是不完全正确,如果我们用传统的方式搭配 webpack 开发,确实需要全部都重新引入一遍,但是如果我们使用 vue
、 react
等框架开发,只需要借助 vue-loader
、 react-hot-loader
即可,不需要自己一个个引入,详细内容可自行查看 webpack 模块热替换官方文档
方式2:用 oneOf
对 loader
进行处理
我们在 module.rules
中配置了很多的 loader
,每个文件要被所有的 loader
检测一遍来确定是否需要处理,但实际上每个文件只会被一个 loader
处理,当匹配到一个合适的 loader
时,根本不需要再去对剩下的 loader
进行比对,对此我们需要做一些配置
开发和生产环境下都可以进行此配置,以下代码仅为示例,并非完整代码,在 modules.rules
内 添加一个对象,在这个对象中添加一个 oneOf
的数组,把 loader
放入这个数组中即可
webpack.dev.js、webpack.prod.js
// ...
module.exports = {
// ...
module: {
rules: [
{
// oneOf 表示以下 loader 只要有一个符合条件,其它的就不会继续执行
oneOf: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
},
{
test: /\.s[ac]ss$/,
type: "asset",
use: ["style-loader", "css-loader", "sass-loader"],
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
},
],
},
],
},
};
方式3:限定 Loader
和 Plugins
的检测范围
通过使用 exclude
和 include
,来限定 Loader
和 Plugins
的检测范围
exclude:除了列出模块之外,全部处理
include:只处理列出的模块
webpack.dev.js、 webpack.prod.js
// ...
module.exports = {
// ...
module: {
rules: [
{
oneOf: [
{
test: /\.css$/,
// 只处理 ../src 下的文件,此处只做演示,实际开发中不需要对样式进行限制
include: path.resolve(__dirname, "../src"),
use: ["style-loader", "css-loader"],
},
{
test: /\.js$/,
exclude: /node_modules/, // 除了 node_modules ,全部处理
loader: "babel-loader",
},
],
},
],
},
plugins: [
new ESLintPlugin({
context: path.resolve(__dirname, "../src"),
exclude: "node_modules", // 默认值,可写可不写
}),
],
};
方式4:利用缓存
对于已经打包过的文件,我们可以将其缓存起来,再次打包的时候,未做修改的内容可以直接使用上一次缓存的文件,这样可以提高打包编译的速度
webpack.dev.js、webpack.prod.js
// ...
module.exports = {
// ...
module: {
rules: [
{
oneOf: [
{
test: /\.js$/,
exclude: /node_modules/, // 除了 node_modules ,全部处理
loader: "babel-loader",
options: {
cacheDirectory: true, // 开启babel缓存
cacheCompression: false, // 关闭缓存文件压缩
},
},
],
},
],
},
plugins: [
new ESLintPlugin({
context: path.resolve(__dirname, "../src"),
exclude: "node_modules", // 默认值,可写可不写
cache: true, // 开启缓存
cacheLocation: path.resolve(__dirname, "../node_modules/.cache/eslintcache"), // 指定缓存文件路径
}),
],
};
如果只到这里就结束,我们会发现,当一个文件被引入多个文件中时,一旦这个文件发生改变,打包时,其它文件也会一起重新打包,为了避免这种情况产生,我们可以在 optimization
中追加配置
// ...
module.exports = {
// ...
// webpack5 推荐把优化配置写在这里
optimization: {
// 避免打包时一个文件改变影响到其它文件一起改变
runtimeChunk: {
name: (entrypoint) => `runtime~${entrypoint.name}.js`,
},
},
};
方式5:多进程打包
为了提高打包编译的速度,我们可以开启多线程同时打包,电脑 cpu
有多少核心,最多就能同时开启多少个线程,实现此功能,需要用到 thread-loader
插件,详细内容可以查看 thread-loader 官方文档
- 注意:每开启一个线程,都要多消耗差不多
600ms
的时间,所以这个方式只推荐在项目较大,任务较多时使用 - 注意2:
thread-loader
要写在所有loader
之前
安装 thread-loader
npm install --save-dev thread-loader
使用 thread-loader
webpack.dev.js
、webpack.prod.js
const os = require("os"); // node.js核心模块
const TerserWebpackPlugin = require("terser-webpack-plugin"); // webapck内置插件,无需下载
const threads = os.cpus().length; // cpu核心数
module.exports = {
// ...
module: {
rules: [
{
oneOf: [
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: "thread-loader",
options: {
works: threads,
},
},
{
loader: "babel-loader",
options: {
cacheDirectory: true, // 开启babel缓存
cacheCompression: false, // 关闭缓存文件压缩
},
},
],
},
],
},
],
},
plugins: [
new ESLintPlugin({
context: path.resolve(__dirname, "../src"),
exclude: "node_modules", // 默认值
cache: true, // 开启缓存
cacheLocation: path.resolve(__dirname, "../node_modules/.cache/eslintcache"), // 指定缓存文件路径
threads,
}),
],
// webpack5 推荐把优化配置写在这里
optimization: {
minimizer: [
new CssMinimizerPlugin(),
new TerserWebpackPlugin({
parallel: threads,
}),
],
},
};
3. 减小代码体积
webpack
对于未使用的 js
文件默认不会打包,但除此之外,我们还需要进行更进一步的优化
方式1:优化 babel-loader
在第2节:深入学习
中,我们曾提到 babel-loader
运行很慢,这是因为 Babel
对一些公共方法使用了非常小的辅助代码,比如 _extend
。默认情况下会被添加到每一个需要它的文件中。
为了解决这个问题,我们可以引入 Babel runtime
作为一个独立模块,来避免重复引入
安装 @babel/plugin-transform-runtime
npm install -D @babel/plugin-transform-runtime
使用 @babel/plugin-transform-runtime
webpack.dev.js、webpack.prod.js
// ...
module.exports = {
// ...
module: {
rules: [
{
oneOf: [
{
test: /\.js$/,
exclude: /node_modules/, // 除了 node_modules ,全部处理
loader: "babel-loader",
options: {
cacheDirectory: true, // 开启babel缓存
cacheCompression: false, // 关闭缓存文件压缩
plugins: ['@babel/plugin-transform-runtime'],
},
},
],
},
],
},
};
方式2:压缩图片
对于本地图片,我们可以对其进行压缩,为此我们需要用到 ImageMinimizerWebpackPlugin
插件
安装 image-minimizer-webpack-plugin
npm install image-minimizer-webpack-plugin imagemin --save-dev
无损压缩插件 imagemin-gifsicle
、imagemin-jpegtran
、imagemin-optipng
、imagemin-svgo
npm install imagemin-gifsicle imagemin-jpegtran imagemin-optipng imagemin-svgo --save-dev
有损压缩插件 imagemin-gifsicle
、imagemin-mozjpeg
、imagemin-pngquant
、imagemin-svgo
npm install imagemin-gifsicle imagemin-mozjpeg imagemin-pngquant imagemin-svgo --save-dev
使用 image-minimizer-webpack-plugin
,以无损压缩举例
webpack.prod.js
// ...
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");
// ...
module.exports = {
// ...
// webpack5 推荐把优化配置写在这里
optimization: {
// 压缩配置
minimizer: [
// ...
new ImageMinimizerPlugin({
minimizer: {
implementation: ImageMinimizerPlugin.imageminGenerate,
options: {
plugins: [
["gifsicle", { interlaced: true }],
["jpegtran", { progressive: true }],
["optipng", { optimizationLevel: 5 }],
[
"svgo",
{
plugins: [
'preset-default',
'prefixIds',
{
name: 'sortAttrs',
params: {
xmlnsOrder: 'alphabetical'
}
}
],
},
],
],
}
},
}),
],
},
};
4. 提高代码运行性能
方式1:分割代码
问题:我们发现每次打包后,每个类型的文件都只会打包到一个文件中,这样在项目加载时,就会一次性加载所有同类型的代码,速度就会很慢。
解决思路:如果我们能把不同文件中的代码分别打包到不同的文件中,这样每次加载时,就会只加载当前页所用到的代码。同时,对于公共模块的代码,虽然很多文件都引入了,但是我们也只需要打包一次即可,不需要进行重复打包。
显然,webpack
当然是有这个插件的,并且本身就已经集成了,默认配置下需要达到一定体积才会被单独打包,详细内容可查看 SplitChunksPlugin 官方文档。
webpack.prod.js
// ...
module.exports = {
// ...
output: {
path: path.resolve(__dirname, "../dist"), // 文件输出路径-相对路径
filename: "static/js/[name].js", // 文件名-命名随意
chunkFilrname: "static/js/[name].js", // 其它文件打包输出的名字,沿用原文件命名
clean: true,
},
optimization: {
// 代码分割
splitChunks: {
chunks: "all", // 对所有模块都分割
// 以下为默认配置
minSize: 20000,
minRemainingSize: 0,
minChunks: 1,
maxAsyncRequests: 30,
maxInitialRequests: 30,
enforceSizeThreshold: 50000,
cacheGroups: {
defaultVendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
reuseExistingChunk: true,
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
},
},
},
};
方式2:统一命名规范
在出口文件中追加配置,然后删除和修改 Loader
和 Plugin
中的 filename
配置即可,开发模式下某些没用到的插件不用配置
webpack.prod.js、webpack.prod.js
// ...
module.exports = {
output: {
path: path.resolve(__dirname, "../dist"), // 文件输出路径-相对路径
filename: "static/js/[name].js", // 文件名-命名随意
chunkFilename: "static/js/[name].chunkjs", // 自动生成命名,但是以chunk.js结尾
assetModuleFilename: "static/media/[hash:10][ext][query]", // 图片、文字等资源按照type:assets命名
clean: true,
},
module: {
rules: [
{
oneOf: [
{
test: /\.(png|jpe?g|svg|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024, // 10kb,小于10kb会被转译成base64
},
},
},
{
test: /\.(ttf|woff2?)$/,
type: "asset/resourse",
},
],
},
],
},
plugins: [
// 把css单独提取出来作为独立的文件
new MiniCssExtractPlugin({
filename: "static/css/[name].css",
chunkFilename: "static/css/[name].chunk.css", // 添加命名规范
}),
],
};
方式3:控制加载时期(preload、prefetch)
控制当前页面需要用到的资源立即加载,暂时不用的资源在浏览器空闲时再加载,实现这个功能需要用到 @vue/preload-webpack-plugin
插件,@vue/preload-webpack-plugin 插件 git 地址
- 注意1:preload 是立即加载,prefetch 是在浏览器空闲时加载
- 注意2:preload 兼容性较好(完全不兼容 ie),prefetch 兼容性较差(兼容 ie11,在 Safari 中有兼容性问题)
安装 @vue/preload-webpack-plugin
npm install --save-dev @vue/preload-webpack-plugin
使用 @vue/preload-webpack-plugin
webpack.prod.js
const PreloadWebpackPlugin = require("@vue/preload-webpack-plugin");
module.exports = {
plugins: [
new PreloadWebpackPlugin({
rel: "preload",
as: "script",
}),
],
};
5. 离线访问
我们项目的运行是建立在联网的情况下,如果网络断开,项目将会无法打开,这个问题,可以借助 workbox-webpack-plugin
插件来解决
安装 workbox-webpack-plugin
npm install workbox-webpack-plugin --save-dev
webpack.prod.js
const WorkboxPlugin = require('workbox-webpack-plugin');
module.exports = {
plugins: [
new WorkboxPlugin.GenerateSW({
// 这些选项帮助快速启用 ServiceWorkers
// 不允许遗留任何“旧的” ServiceWorkers
clientsClaim: true,
skipWaiting: true,
}),
],
};
main.js
// 判断是否支持 service-worker
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/service-worker.js').then(registration => {
console.log('SW registered: ', registration);
}).catch(registrationError => {
console.log('SW registration failed: ', registrationError);
});
});
}
此时我们还需要安装一个插件,这是因为 service-worker
查找的目录不是 dist下的目录,所以我们需要修改此处设定
npm install server -g
启动命令
serve dist
这时候再使用 npm run build
打包,就会发现dist中多了一些代码,有了这些代码我们就可以进行离线访问了
结束
webpack
的初步学习到此就告一段落了,后续会对文档进行不定期更新。
关于 webpack
的文章后面还会考虑单独写几篇有关优化和结合 vue
、react
等框架使用分享,应该会在近期内完成。