基础部分
1.为什么要使用打包工具?
将语法编译成浏览器识别的语法,(框架vue/react,es6语法,sass)
功能:
压缩代码
兼容性处理
提高性能
2.基本使用
注:webpack本身只能编译JS语法
> 问题的产生
// 1,创建src/js/sum.js
export default function sum(x, y) {
return x + y
}
// 2,创建minus.js
export default function minus(x, y) {
return x - y
}
// 3,创建src/main.js,导入sum和minus
import sum from './js/sum'
import minus from './js/minus'
console.log(sum(1, 2));
console.log(minus(1, 2));
// 4,创建public/index.html,导入main.js,结果报错
<script src="../src/main.js"></script>
// Uncaught SyntaxError: Cannot use import statement outside a module
// 报错原因:不能编译模块化语言,需要引入webpack
> 使用webpack
// 1,生成package.json包编译文件
// 注:name不能为webpack,main为main.js的文件路径
npm init -y
// 2,安装webpack
npm i webpack webpack-cli -D
注意:-D === --save-dev
// 3,运行,生成dist/main.js
npx webpack ./src/main.js --mode=development
npx webpack ./src/main.js --mode=production
// 注:
1.编译后的箭头函数\es6相关语法都没有改变
2.--mode=development\--mode=production的区别:production代码会被压缩成一行
// 4,将index.html中script标签的路径改为dist/main.js
<!-- <script src="../src/main.js"></script> -->
<script src="../dist/main.js"></script> // 3 -1
缺点:webpack只能编译js/json,不能编译css,如样式资源、图标字体图片等
3.五个核心概念
entry入口
output出口
loader加载器
plugins插件
mode模式:development/production
4.基本配置
// 1,创建webpack.config.js,必须在最外层目录,和package.json同级
// 注:所有配置在nodejs环境运行,所以用commonjs模块化
const path = require("path")
module.exports = {
entry: "./src/main.js",
output: {
path: path.resolve(__dirname, "dist"), // 绝对路径,__dirname表示当前文件的目录
filename: "main.js",
clean: true, // 为避免每次打包前删除dist包,在生成文件之前清空output所在目录
},
module: { rules: [] },
plugins: [],
mode: "development",
}
// 2,npx webpack
5.处理css
再次:webpack不能直接编译css资源,需要style-loader和css-loader
css-loader:是将css资源编译成commonjs模块到js中
style-loader:将js中的css通过创建style标签的形式添加到html中
> 处理css实操
// 1,安装
npm i css-loader style-loader -D
// 2,配置
webpack.config.js中
module: {
rules: [{
test: /\.css$/i,
use: ["style-loader", "css-loader"], // 执行顺序:从下往上
}]
},
// 3,创建src/css/index.css,导入到main.js中
index.css:
.box1 {
width: 100px;
height: 100px;
background-color: orange;
}
main.js:
import './css/index.css'
// 4,npx webpack
在页面的head中能找到对应的style标签
6.处理less,sass/scss,stylus
> less
// 1,新建less/index.less,main.js中导入index.less
.box2 {
width: 100px;
height: 100px;
background-color: pink;
}
import './less/index.less'
2,安装less,less-loader,并配置
npm i less less-loader -D
webpack.config.js中
module: {
rules: [{
test: /\.css$/,
use: ["style-loader", "css-loader"], // 执行顺序:从下往上
},
{
test: /\.less$/,
use: ["style-loader", "css-loader", 'less-loader'],
},
]
},
// 3,npx webpack
> sass/scss
1,新建scss/index.scss,main.js中导入index.scss
.box3 {
width: 100px;
height: 100px;
background-color: red;
}
import './scss/index.scss'
//2,安装sass,sass-loader,并配置
npm i sass-loader sass -D
webpack.config.js中
{
test: /\.s[ac]ss$/,
use: ["style-loader", "css-loader", 'sass-loader'],
},
// 3,npx webpack
> stylus
stylus和上述相同,具体参考webpack官方文档loader部分,仅供了解
7.处理图片资源
webpack4处理图片资源需要file-loader,url-loader,5已经内置
file-loader:简单的说就是把文件资源编译成webpack可以识别的资源
url-loader:是将图片优化,小于某个大小的文件转化成base64格式
> 处理图片资源
// 1,新建src/images,放入2张图片,一张png一张jpg
// 2,图片放入index.html中,npx webpack成功打包
index.css:
.img1 {
width: 100px;
height: 100px;
background-image: url("../images/img1.jpg");
background-size: cover;
}
.img2 {
width: 100px;
height: 100px;
background-image: url("../images/img2.png");
background-size: cover;
}
index.html:
<div class="img1"></div>
<div class="img2"></div>
// 成功显示
// 优化:将文件较小的图片转化成base64格式,减少请求次数
// 优点:减少请求次数;缺点:体积变大
// 1,配置webpack.config.js
{
test: /\.(png|jpg|jpeg|gif|svg)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 40 * 1024 // 小于40kb会转为base64格式
// 优点:减少请求次数;缺点:体积变大
}
}
}
// 2,删除之前的dist,重新打包,发现图片资源少了一个
8.修改输出文件的目录
问题:打包后的dist文件夹有点乱,分类
// 1,修改output中入口文件的路径
output: {
path: path.resolve(__dirname, "dist"),
filename: "js/main.js",
},
// 2,处理图片的输出目录,删除原先的dist,重新打包
{
test: /\.(png|jpg|jpeg|gif|svg)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 40 * 1024 // 小于40kb会转为base64格式
// 优点:减少请求次数;缺点:体积变大
}
},
generator: {
filename: 'images/[hash:10][ext][query]'
}
}
// 注:
[hash:10]:打包后的文件名
:10长度限制在10以内
[ext]:后缀名
[query]:携带参数,没有可以不写
// 3,注意:打包路径改变后,记得同时修改index.html中的路径
> 自动清空上次打包结果
output: {
path: path.resolve(__dirname, 'dist'),
filename: "main.js",
clean: true,
},
9.处理icon图标和字体资源和其他资源
// 1,iconfont下好资源
// 将iconfont.css放入css文件夹
// 将iconfont.css中依赖的ttf,woff,woff2文件放入font文件夹
// 2,iconfont.css里的路径要改一下
@font-face {
font-family: "iconfont"; /* Project id 4284619 */
src: url("../font/iconfont.woff2?t=1697139184016") format("woff2"),
url("../font/iconfont.woff?t=1697139184016") format("woff"),
url("../font/iconfont.ttf?t=1697139184016") format("truetype");
}
// 3,main.js中引入css文件,重新打包,index.html中使用查看效果
main.js:
import './css/iconfont.css'
index.html:
<span class="iconfont icon-Books"></span>
<span class="iconfont icon-Email"></span>
// 4,优化:类似处理图片的方式处理字体\图标
{
test: /\.(ttf|woff|woff2)$/,
type: 'asset/resource', // asset是用来转码base64的,改为resource
generator: {
filename: 'media/[hash:10][ext][query]'
}
}
// 其他资源
// 原封不动的输出即可,但是webpack又不能识别
// 1,在上述的优化中直接添加后缀即可
{
test: /\.(ttf|woff|woff2|mp3|mp4)$/,
type: 'asset/resource',
generator: {
filename: 'media/[hash:10][ext][query]'
}
}
10.处理JS资源
webpack只能编译es模块化语法,像箭头函数、三目运算符无法编译
处理js资源:
1,babel:针对js兼容性处理
2,eslint:针对代码格式代码规范(优先)
11.eslint基本了解,使用
eslint:代码规范检查工具
配置文件,常用.eslintrc前缀文件,如.eslintrc.js
// 1,安装eslint相关插件,在webpack.config.js中引入
npm i eslint-webpack-plugin eslint -D
webpack.config.js:
const ESLintPlugin = require('eslint-webpack-plugin');
plugins: [new ESLintPlugin({
context: path.resolve(__dirname, 'src') // 检查哪些文件,指定为src路径下的
})],
// 2,配置.eslintrc.js
module.exports = {
// 解析选项
parserOptions: {
ecmaVersion: 6, // es语法版本
sourceType: 'module', // es模块化
ecmaFeatures: { // 其他特性
jsx: true // 如react项目开启jsx
}
},
// 具体规则
// 0,off——关闭规则
// 1,warn——开启规则,警告级别
// 2,error——开启规则,错误级别
rules: {
'no-var': 2 // 禁用var
},
// extends: ['eslint-recommended'], // 继承现有规则,8.56版本已无该配置
env: {
node: true, // 启用node中全局变量
browser: true, // 启用浏览器中全局变量
}
}
// 3,打包,此时如果项目中用var则会报错,用Eslint插件会标红,prettier类插件会自动修改为var
// 4,忽略dist下的文件
创建.eslintignore
dist
12.babel的了解,使用
> 了解
- 1.作用:
js编译器,将es6语法编译为向后兼容的js语法,能够在旧版本浏览器\环境运行
- 2.配置文件
babel.config.*
可以是babel.config.js/json,放在根目录下
.babelrc.*
可以是.babelrc.js/json,放在根目录下
package.json里的babel配置
- 3.具体配置
module.exports = {
presets: ['@babel/preset-env'] // 预设
}
@babel/preset-env:智能预设,能够编译es6文件
@babel/preset-react:编译jsx文件
@babel/preset-typescript:编译ts语法
> 使用
- 1.安装
npm install -D babel-loader @babel/core @babel/preset-env
- 2.配置
webpack.config.js中
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
或者在webpack.config.js中
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
}
}
根目录下新建babel.config.js
module.exports = {
presets: ['@babel/preset-env']
}
- 3.npx webpack观察dist下的js文件变化,箭头函数\es6语法都被修改了
13.处理html资源
> 问题
public下的js文件当前是手动引入的,如果打包的名称改变或者打包出多个js文件,会造成麻烦和问题∴要改成自动引入
将<script src="../dist/js/main.js"></script>注释掉
> 使用
- 1.安装插件plugin
npm i -D html-webpack-plugin
- 2.配置webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
plugins: [
new HtmlWebpackPlugin()
],
- 3.打包
此时dist下会多出一个index.html文件,但是结构是空的和之前的Index.html不同,∴需要配置模板
- 4.重新配置+打包即可
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "public/index.html"),
})
14.自动化,开发服务器
> 问题
改变项目中的数据时,dist/index.html页面不会即时更新,每次改变数据时需要重新打包,需要引入开发服务器的概念
> 使用
- 1.安装
npm i webpack-dev-server -D
- 2.配置webpack.config.js
devServer: {
host: 'localhost',
port: '3000',
open: true
},
- 3.启动服务
npx webpack server(serve也行)
// 注:开发服务器是没有输出的,在内存中编译打包,打包不会生成dist下的文件
15.总结开发配置
entry:入口
output:出口
mode:模式
module(loader):用来处理webpack处理不了的资源,css相关\图片字体\音频视频\babel代码兼容性处理
plugins:插件,如eslint规范代码\处理html资源\开发服务器
16.生产环境与开发环境
> 开发环境
- 1.新建config/webpack.dev.js
- 2.修改相关路径
相对路径不用改(可以理解成在根目录下打包)
绝对路径使用到path需要往上一层
开发环境下是没有输出的,path直接写undefined
entry: "./src/main", // 不变
output: {
path: undefined,
filename: "main.js",
clean: true,
},
plugins: [
new ESLintPlugin({
context: path.resolve(__dirname, '../src')
}),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../public/index.html"),
})
],
- 3.npx webpack serve --config ./config/webpack.dev.js
> 生产环境
- 1.新建config/webpack.prod.js
- 2.修改相关路径
相对路径不用改(可以理解成在根目录下打包)
绝对路径使用到path需要往上一层
entry: "./src/main", // 不变
output: {
path: path.resolve(__dirname, '../dist'),
filename: "main.js",
clean: true,
},
plugins: [
new ESLintPlugin({
context: path.resolve(__dirname, '../src')
}),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../public/index.html"),
})
],
mode: "production"
// devServer删除
- 3.npx webpack --config ./config/webpack.prod.js
> 别名
npx webpack serve --config ./config/webpack.dev.js
npx webpack --config ./config/webpack.prod.js
启动指令太长,简化:
"scripts": {
"start": "npm run dev",
"dev": "webpack serve --config ./config/webpack.dev.js",
"build": "webpack --config ./config/webpack.prod.js"
},
17.提取css成为单独的文件
> 问题
在第五章中,处理css的方法是将css资源编译成commonjs模块到js中,通过创建style标签的形式添加到html中
当使用慢速网络时,会出现白屏情况
> 操作
- 1.安装插件
npm i mini-css-extract-plugin -D
- 2.配置
webpack.prod.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
plugins: [
new MiniCssExtractPlugin()
],
// 将之前所有的style-loader替换为MiniCssExtractPlugin.loader,如下
rules:
[{ test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, "css-loader"],
}, { test: /\.less$/,
use: [MiniCssExtractPlugin.loader, "css-loader", 'less-loader'],
}, { test: /\.s[ac]ss$/,
use: [MiniCssExtractPlugin.loader, "css-loader", 'sass-loader'],
} ]
- 3.打包,此时dist下已生成main.css
- 4.改变main.css的路径,重新打包即可
new MiniCssExtractPlugin({
filename: "css/main.css",
})
18.样式的兼容性处理
- 1.安装插件
npm i postcss-loader postcss postcss-preset-env -D
- 2.配置
// 注意位置:要在css-loader后面,sass/scss/less-loader前面
rules: [{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, "css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
'postcss-preset-env' // 预设
]
}
}
}
],
}, {
test: /\.less$/,
use: [MiniCssExtractPlugin.loader, "css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
'postcss-preset-env'
]
}
}
}, 'less-loader'
],
}, {
test: /\.s[ac]ss$/,
use: [MiniCssExtractPlugin.loader, "css-loader", {
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
'postcss-preset-env'
]
}
}
}, 'sass-loader'],
}, ]
- 3.配置package.json
// 在package.json最下面加上常用的浏览器配置
// 最后两个版本,兼容99%,未停更
"browserslist": [
"last 2 version",
"> 1%",
"not dead"
]
19.封装loader函数,优化18
> 问题
在18中,loader有很多重复的代码,封装函数优化
> 操作
const getStyleLoader = (params) => {
return [
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: ["postcss-preset-env"],
},
},
},
params,
].filter(Boolean)
}
module: {
rules: [{
test: /\.css$/i,
use: getStyleLoader(),
},
{
test: /\.less$/,
use: getStyleLoader("less-loader"),
},
{
test: /\.s[ac]ss$/,
use: getStyleLoader("sass-loader"),
}],
},
20.js\html\css压缩
> 问题
生产模式中,js\html默认压缩
现在处理css压缩
> 操作
- 1.安装插件
npm i css-minimizer-webpack-plugin -D
- 2.配置
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin")
// 写法一
optimization: {
minimizer: [
new CssMinimizerPlugin()
]
},
// 写法二
plugins: [
new CssMinimizerPlugin()
],
进阶部分
// 提高开发体验
sourceMap
// 提升打包速度
hmr
oneOf
include/exclude
cache
thread多进程
// 减少代码体积
tree shaking
@babel/plugin-transform-runtime
image minimizer
// 优化代码运行性能
code split
preload\prefetch
newtork cache
corejs
PWA
1.sourceMap
> 引入
提高开发体验:当开发中碰到错误时,定位到的往往是编译后的文件,sourceMap是源码映射,会生成源码和构建后代码的映射关系
> 操作
// 开发环境常用:
// devtool: "cheap-module-source-map"
// devtool: "eval-cheap-module-source-map"
// 优点:只有行映射,快
// 缺点:没有列映射
- 1.故意写错add.js中的代码
- 2.webpack.dev.js中
devtool: "cheap-module-source-map"
- 3.npm start观察结果
// 生产环境可以不用,或用source-map
// 优点:有行列映射
// 缺点:编译速度慢
- 1.webpack.prod.js中
devtool: "source-map"
2.HMR
- 1.用处
// Hot Module Replace,热模块替换(热更新)
// 用来提升构建速度
- 2.先关闭
// 默认开启,关闭查看效果
devServer: {
host: 'localhost',
port: '3000',
open: true,
hot: false,
},
- 3.启动项目,重新观察
// 此时改变宽高等样式,页面会刷新
// 注:JS代码的修改还是会引发全局更新
// 判断是否有hot热更新功能,有则使用,此时修改add函数中的内容会触发局部更新
main.js中:
if (module.hot) {
module.hot.accept(add);
}
3.oneOf/include,exclude
oneOf
// 作用:提升打包构建速度
// 打包时,每个资源都会经过所有loader处理,比较慢
// oneOf顾名思义就是只要匹配上一个loader剩下的就不匹配了
include,exclude
// 包含排除
> 操作
// webpack.dev.js/webpack.prod.js中
rules: [{
oneOf: [{
test: /\.css$/i,
use: ["style-loader", "css-loader"],
}, {
test: /\.less$/,
use: ["style-loader", "css-loader", 'less-loader'],
}, {
test: /\.s[ac]ss$/,
use: ["style-loader", "css-loader", 'sass-loader'],
}, {
test: /\.(png|jpg|jpeg|gif|svg)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 20 * 1024
}
},
generator: {
filename: 'images/[hash:10][ext][query]'
}
},
{
test: /\.(ttf|woff|woff2|mp3|mp4)$/,
type: 'asset/resource',
generator: {
filename: 'media/[hash:10][ext][query]'
}
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
]
}]
4.缓存cache
> babel缓存
- 1.配置webpack.dev.js/webpack.prod.js
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
cacheDirectory: true, // 开启babel缓存
cacheCompression: false // 关闭缓存文件压缩
}
}
}
- 2.打包后,node_modules/.cache/babel-loader出现缓存
> eslint缓存
// eslint目前自带缓存,如果没有
- 1.配置webpack.dev.js/webpack.prod.js
new ESLintPlugin({
context: path.resolve(__dirname, '../src'),
cache: true,
cacheLocation: path.resolve(__dirname, '../node_modules/.cache/eslintCache')
}),
5.多进程打包threads
> 说明
针对性的提高babel\eslint\terser的运行速度
> 操作
- 1.安装thread-loader
npm i thread-loader -D
- 2.配置webpack.dev.js/webpack.prod.js
const os = require("os")
const thread = os.cpus().length // cpu核数
const TerserWebpackPlugin = require("terser-webpack-plugin") // terser是内置的
// babel
{
test: /\.js$/,
exclude: /node_modules/,
use: [{
loader: 'thread-loader',
options: {
workers: threads // 启动
}
}, {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
cacheDirectory: true,
cacheCompression: false
}
}]
}
// eslint
new ESLintPlugin({
context: path.resolve(__dirname, "../src"),
threads // 启动
}),
// terser:对JS的压缩,可以写在plugins里,也可以写在optimization下minimizer里
optimization: {
minimizer: [
new CssMinimizerPlugin(),
new TerserWebpackPlugin({
parallel: threads // 启动
})
]
},
6.tree shaking
//默认开启
// 作用:
移除js中没有使用的代码
// 注:依赖ES Module
7.针对babel优化
// babel为编译的每个文件都插入了辅助代码,使得体积变大
// 为避免重复引用,引入@babel/plugin-transform-runtime
- 1.安装插件
npm i @babel/plugin-transform-runtime -D
- 2.配置
{
test: /\.js$/,
exclude: /node_modules/,
use: [{
loader: 'thread-loader',
options: {
workers: threads
}
}, {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
cacheDirectory: true, // 开启babel缓存
cacheCompression: false, // 关闭缓存文件压缩
plugins: ['@babel/plugin-transform-runtime']
}
}]
}
8.image minimizer
// 存在多个文件下载不下来的情况,不做演示
// 移步p41章
9.code split
// 作用:代码分割,只渲染首页就只加载首页的js文件
9-1.多入口
- 1.新建webpack2/demo
- 2.安装配置
npm init -y
npm i webpack webpack-cli -D
npm i -D html-webpack-plugin
- 3.新建src/app.js,main.js,新建public/index.html
- 4.新建webpack.config.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: { // 多入口写成对象形式
app: "./src/app.js",
main: "./src/main.js",
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: "[name].js", // 名字根据entry的属性名决定
clean: true,
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "public/index.html"),
})
],
mode: 'production'
}
9-2.多入口提取公共模块
> 问题引入
- 1.新建webpack/demo2,复用demo1的功能
- 2.新建math.js,在app.js/main.js中复用
export const minus = (x, y) => {
console.log(x - y);
return x - y
}
- 3.npx webpack,在打包后的app.js\main.js中都有重复的代码
(()=>{"use strict";console.log(2),console.log("app")})();
(()=>{"use strict";console.log(1),console.log("main")})();
> 解决
- 1.配置webpack.config.js
optimization: {
splitChunks: {
chunks: 'all', // 对所有模块都进行分割
cacheGroups: {
default: {
minSize: 0,
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
}
}
}
},
- 2.重新打包,观察
// 此时dist下会多生成一个24.js文件,用于main.js\app.js引入
9-3.按需加载
> 问题引入
// 页面上按钮绑定的函数,希望点击的时候再加载
> 操作
- 1.新建webpack/demo3,复用demo2的功能,npm i
- 2.新建add.js,在main.js中引用
export const add = (x, y) => {
console.log(x + y);
return x + y
}
- 3.在index.html上添加按钮
<button class="btn">点击</button>
- 4.main.js中
const oBtn = document.querySelector('.btn')
oBtn.onclick = function () {
import('./add').then(res => {
console.log('模块加载成功!', res);
}).catch(err => {
console.log("模块加载失败!", eerr);
})
}
- 4.打包,此时dist下会多生成一个780.js文件,打开页面点击按钮,会加载780文件
9-4.单入口
在单入口实现code split和按需加载,和多入口操作相同
// code split
- 1.回到webpack,配置webpack.prod.js
optimization: {
splitChunks: {
chunks: 'all',
}
},
- 2.index.html中添加按钮,main.js修改代码
const Obtn = document.querySelector('.btn')
Obtn.onclick = function () {
import('./js/add').then((res) => {
console.log('res:', res.default(1, 2));
}).catch(err => {
console.log('err:' + err);
})
}
- 3.打包
9-5.打包模块命名
> 问题
打包后的模块文件命名都是数字
> 处理
- 1.魔术命名
const Obtn = document.querySelector('.btn')
Obtn.onclick = function () {
import( /* webpackChunkName:"add" */ './js/add').then((res) => {
console.log('res:', res.default(1, 2));
}).catch(err => {
console.log('err:' + err);
})
}
- 2.配置chunkFilename
output: {
path: path.resolve(__dirname, "../dist"),
chunkFilename: "[name].js",
filename: "main.js",
clean: true,
},
9-6.统一命名
> 问题
目前存在的命名:
主文件命名,chunk文件命名,图片字体资源命名,css命名等,统一规范
> 解决
output: {
path: path.resolve(__dirname, "../dist"),
filename: "[name].js", // 主文件改为[name]
chunkFilename: "js/[name].chunk.js",// chunk文件加上后缀
assetModuleFilename:"images/[hash:10][ext][query]"
clean: true,
},
// 图片字体的命名重复部分删掉,统一成assetModuleFilename
// generator: {
// filename: 'images/[hash:10][ext][query]'
// }
// css资源
new MiniCssExtractPlugin({
filename: "css/[name].css",
chunkFilename: "js/[name].chunk.js",
}),
10.preload/prefetch
> 说明
// 说明:
// 之前已经做过code split和懒加载,但是如果懒加载的资源体积很大,会卡顿
// 相同点\不同点
// preload:立即加载资源
// prefetch:空闲时加载资源
// 共同点:都会加载资源,不执行,都有缓存
// 不同点:
// preload:优先级高,只能加载当前页面的资源
// prefetch:优先级低,可以加载当前页面资源,也可以加载下一页面资源
// 缺点:兼容性差
> 操作
- 1.安装,配置
npm i --save-dev preload-webpack-plugin
webpack.prod.js:
const PreloadWebpackPlugin = require('@vue/preload-webpack-plugin');
plugins: [
new PreloadWebpackPlugin({
rel: 'preload',
as: 'script'
})
],
- 2.打包后观察index.html
<link href="js/add.chunk.js" rel="preload" as="script" />
11.network cache,
> 问题
// 问题:
当add.js发生变化,打包后hash值改变,引入add.js的main.js也随之发生改变
// 解决:
// 通过一个runtime文件
> 操作
- 0.在开始之前,将output的文件加上contenthash
output: {
path: path.resolve(__dirname, "../dist"),
filename: "[name].[contenthash:8].js",
chunkFilename: "js/[name].chunk.[contenthash:8].js",
assetModuleFilename: "images/[hash:10][ext][query]",
clean: true,
},
- 1.配置webpack.prod.dev
optimization: {
runtimeChunk: {
name: entrypoint => `runtime~${entrypoint.name}.js`
}
},
- 2.打包
// 打包会生成一个runtime文件用来管理,此时修改add不会改变main
12.corejs
babel预设可以解决箭头函数\解构符等语法兼容性,但promsie\async等解决不了,需要corejs
corejs用来做es6及以上的api的polyfill
> 使用
npm i core-js
// 全局
import 'core-js'
打包
// 打包后生成的文件很大,改为按需引入
// 按需引入,如下
import 'core-js/es/promise'
// 继续优化
- 1.新建babel.config.js
module.exports = {
presets: [
['@babel/preset-env', {
useBuiltIns: "usage",
// corejs: 3,
}]
],
}
- 2.打包
// 打包之后没有反应,是因为browserlist中的浏览器都能兼容promise语法
// 如果换成ie浏览器就会生成文件
13.PWA
// 渐进式网络应用程序progressive web app
// 提升离线体验
// 缺点:兼容性差
> 操作
- 1.安装
npm i workbox-plugin -D
- 2.配置
webpack.prod.js中:
const PreloadWebpackPlugin = require('@vue/preload-webpack-plugin');
new WorkboxPlugin.GenerateSW({
clientsClaim: true,
skipWaiting: true,
})
main.js中:
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/service-worker.js').then(registration => {
console.log('SW-register', registration);
}).catch(err => {
console.log('SW-failed', err);
})
})
}
- 3.打包,观察
// SW加载失败,因路径问题,页面是在/dist文件夹下
- 4.npm i serve -g
- 5.serve dist打开开发服务器localhost:3000即可