目录
Preload / Prefetch
为什么
我们前面已经做了代码分割,同时会使用 import 动态导入语法来进行代码按需加载(我们也叫懒加载,比如路由懒加载就是这样实现的)。
但是加载速度还不够好,比如:是用户点击按钮时才加载这个资源的,如果资源体积很大,那么用户会感觉到明显卡顿效果。
我们想在浏览器空闲时间,加载后续需要使用的资源。我们就需要用上 Preload
或 Prefetch
技术。
是什么
-
Preload
:告诉浏览器立即加载资源。 -
Prefetch
:告诉浏览器在空闲时才开始加载资源。
它们共同点:
- 都只会加载资源,并不执行。
- 都有缓存。
它们区别:
Preload
加载优先级高,Prefetch
加载优先级低。Preload
只能加载当前页面需要使用的资源,Prefetch
可以加载当前页面资源,也可以加载下一个页面需要使用的资源。
总结:
- 当前页面优先级高的资源用
Preload
加载。 - 下一个页面需要使用的资源用
Prefetch
加载。
它们的问题:兼容性较差。
- 我们可以去 Can I Useopen in new window 网站查询 API 的兼容性问题。
Preload
相对于Prefetch
兼容性好一点。
怎么用
- 下载包
npm i @vue/preload-webpack-plugin -D
- 配置 webpack.prod.js
-
const os =
require(
"os");
-
const path =
require(
"path");
-
const
ESLintWebpackPlugin =
require(
"eslint-webpack-plugin");
-
const
HtmlWebpackPlugin =
require(
"html-webpack-plugin");
-
const
MiniCssExtractPlugin =
require(
"mini-css-extract-plugin");
-
const
CssMinimizerPlugin =
require(
"css-minimizer-webpack-plugin");
-
const
TerserPlugin =
require(
"terser-webpack-plugin");
-
const
ImageMinimizerPlugin =
require(
"image-minimizer-webpack-plugin");
-
const
PreloadWebpackPlugin =
require(
"@vue/preload-webpack-plugin");
-
-
// cpu核数
-
const threads = os.
cpus().
length;
-
-
// 获取处理样式的Loaders
-
const
getStyleLoaders = (
preProcessor) => {
-
return [
-
MiniCssExtractPlugin.
loader,
-
"css-loader",
-
{
-
loader:
"postcss-loader",
-
options: {
-
postcssOptions: {
-
plugins: [
-
"postcss-preset-env",
// 能解决大多数样式兼容性问题
-
],
-
},
-
},
-
},
-
preProcessor,
-
].
filter(
Boolean);
-
};
-
-
module.
exports = {
-
entry:
"./src/main.js",
-
output: {
-
path: path.
resolve(__dirname,
"../dist"),
// 生产模式需要输出
-
filename:
"static/js/[name].js",
// 入口文件打包输出资源命名方式
-
chunkFilename:
"static/js/[name].chunk.js",
// 动态导入输出资源命名方式
-
assetModuleFilename:
"static/media/[name].[hash][ext]",
// 图片、字体等资源命名方式(注意用hash)
-
clean:
true,
-
},
-
module: {
-
rules: [
-
{
-
oneOf: [
-
{
-
// 用来匹配 .css 结尾的文件
-
test:
/\.css$/,
-
// use 数组里面 Loader 执行顺序是从右到左
-
use:
getStyleLoaders(),
-
},
-
{
-
test:
/\.less$/,
-
use:
getStyleLoaders(
"less-loader"),
-
},
-
{
-
test:
/\.s[ac]ss$/,
-
use:
getStyleLoaders(
"sass-loader"),
-
},
-
{
-
test:
/\.styl$/,
-
use:
getStyleLoaders(
"stylus-loader"),
-
},
-
{
-
test:
/\.(png|jpe?g|gif|svg)$/,
-
type:
"asset",
-
parser: {
-
dataUrlCondition: {
-
maxSize:
10 *
1024,
// 小于10kb的图片会被base64处理
-
},
-
},
-
// generator: {
-
// // 将图片文件输出到 static/imgs 目录中
-
// // 将图片文件命名 [hash:8][ext][query]
-
// // [hash:8]: hash值取8位
-
// // [ext]: 使用之前的文件扩展名
-
// // [query]: 添加之前的query参数
-
// filename: "static/imgs/[hash:8][ext][query]",
-
// },
-
},
-
{
-
test:
/\.(ttf|woff2?)$/,
-
type:
"asset/resource",
-
// generator: {
-
// filename: "static/media/[hash:8][ext][query]",
-
// },
-
},
-
{
-
test:
/\.js$/,
-
// exclude: /node_modules/, // 排除node_modules代码不编译
-
include: path.
resolve(__dirname,
"../src"),
// 也可以用包含
-
use: [
-
{
-
loader:
"thread-loader",
// 开启多进程
-
options: {
-
workers: threads,
// 数量
-
},
-
},
-
{
-
loader:
"babel-loader",
-
options: {
-
cacheDirectory:
true,
// 开启babel编译缓存
-
cacheCompression:
false,
// 缓存文件不要压缩
-
plugins: [
"@babel/plugin-transform-runtime"],
// 减少代码体积
-
},
-
},
-
],
-
},
-
],
-
},
-
],
-
},
-
plugins: [
-
new
ESLintWebpackPlugin({
-
// 指定检查文件的根目录
-
context: path.
resolve(__dirname,
"../src"),
-
exclude:
"node_modules",
// 默认值
-
cache:
true,
// 开启缓存
-
// 缓存目录
-
cacheLocation: path.
resolve(
-
__dirname,
-
"../node_modules/.cache/.eslintcache"
-
),
-
threads,
// 开启多进程
-
}),
-
new
HtmlWebpackPlugin({
-
// 以 public/index.html 为模板创建文件
-
// 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源
-
template: path.
resolve(__dirname,
"../public/index.html"),
-
}),
-
// 提取css成单独文件
-
new
MiniCssExtractPlugin({
-
// 定义输出文件名和目录
-
filename:
"static/css/[name].css",
-
chunkFilename:
"static/css/[name].chunk.css",
-
}),
-
// css压缩
-
// new CssMinimizerPlugin(),
-
new
PreloadWebpackPlugin({
-
rel:
"preload",
// preload兼容性更好
-
as:
"script",
-
// rel: 'prefetch' // prefetch兼容性更差
-
}),
-
],
-
optimization: {
-
minimizer: [
-
// css压缩也可以写到optimization.minimizer里面,效果一样的
-
new
CssMinimizerPlugin(),
-
// 当生产模式会默认开启TerserPlugin,但是我们需要进行其他配置,就要重新写了
-
new
TerserPlugin({
-
parallel: threads,
// 开启多进程
-
}),
-
// 压缩图片
-
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",
-
},
-
},
-
],
-
},
-
],
-
],
-
},
-
},
-
}),
-
],
-
// 代码分割配置
-
splitChunks: {
-
chunks:
"all",
// 对所有模块都进行分割
-
// 其他内容用默认配置即可
-
},
-
},
-
// devServer: {
-
// host: "localhost", // 启动服务器域名
-
// port: "3000", // 启动服务器端口号
-
// open: true, // 是否自动打开浏览器
-
// },
-
mode:
"production",
-
devtool:
"source-map",
-
};
Network Cache
为什么
将来开发时我们对静态资源会使用缓存来优化,这样浏览器第二次请求资源就能读取缓存了,速度很快。
但是这样的话就会有一个问题, 因为前后输出的文件名是一样的,都叫 main.js,一旦将来发布新版本,因为文件名没有变化导致浏览器会直接读取缓存,不会加载新资源,项目也就没法更新了。
所以我们从文件名入手,确保更新前后文件名不一样,这样就可以做缓存了。
#是什么
它们都会生成一个唯一的 hash 值。
- fullhash(webpack4 是 hash)
每次修改任何一个文件,所有文件名的 hash 至都将改变。所以一旦修改了任何一个文件,整个项目的文件缓存都将失效。
- chunkhash
根据不同的入口文件(Entry)进行依赖文件解析、构建对应的 chunk,生成对应的哈希值。我们 js 和 css 是同一个引入,会共享一个 hash 值。
- contenthash
根据文件内容生成 hash 值,只有文件内容变化了,hash 值才会变化。所有文件 hash 值是独享且不同的。
怎么用
-
const os =
require(
"os");
-
const path =
require(
"path");
-
const
ESLintWebpackPlugin =
require(
"eslint-webpack-plugin");
-
const
HtmlWebpackPlugin =
require(
"html-webpack-plugin");
-
const
MiniCssExtractPlugin =
require(
"mini-css-extract-plugin");
-
const
CssMinimizerPlugin =
require(
"css-minimizer-webpack-plugin");
-
const
TerserPlugin =
require(
"terser-webpack-plugin");
-
const
ImageMinimizerPlugin =
require(
"image-minimizer-webpack-plugin");
-
const
PreloadWebpackPlugin =
require(
"@vue/preload-webpack-plugin");
-
-
// cpu核数
-
const threads = os.
cpus().
length;
-
-
// 获取处理样式的Loaders
-
const
getStyleLoaders = (
preProcessor) => {
-
return [
-
MiniCssExtractPlugin.
loader,
-
"css-loader",
-
{
-
loader:
"postcss-loader",
-
options: {
-
postcssOptions: {
-
plugins: [
-
"postcss-preset-env",
// 能解决大多数样式兼容性问题
-
],
-
},
-
},
-
},
-
preProcessor,
-
].
filter(
Boolean);
-
};
-
-
module.
exports = {
-
entry:
"./src/main.js",
-
output: {
-
path: path.
resolve(__dirname,
"../dist"),
// 生产模式需要输出
-
// [contenthash:8]使用contenthash,取8位长度
-
filename:
"static/js/[name].[contenthash:8].js",
// 入口文件打包输出资源命名方式
-
chunkFilename:
"static/js/[name].[contenthash:8].chunk.js",
// 动态导入输出资源命名方式
-
assetModuleFilename:
"static/media/[name].[hash][ext]",
// 图片、字体等资源命名方式(注意用hash)
-
clean:
true,
-
},
-
module: {
-
rules: [
-
{
-
oneOf: [
-
{
-
// 用来匹配 .css 结尾的文件
-
test:
/\.css$/,
-
// use 数组里面 Loader 执行顺序是从右到左
-
use:
getStyleLoaders(),
-
},
-
{
-
test:
/\.less$/,
-
use:
getStyleLoaders(
"less-loader"),
-
},
-
{
-
test:
/\.s[ac]ss$/,
-
use:
getStyleLoaders(
"sass-loader"),
-
},
-
{
-
test:
/\.styl$/,
-
use:
getStyleLoaders(
"stylus-loader"),
-
},
-
{
-
test:
/\.(png|jpe?g|gif|svg)$/,
-
type:
"asset",
-
parser: {
-
dataUrlCondition: {
-
maxSize:
10 *
1024,
// 小于10kb的图片会被base64处理
-
},
-
},
-
// generator: {
-
// // 将图片文件输出到 static/imgs 目录中
-
// // 将图片文件命名 [hash:8][ext][query]
-
// // [hash:8]: hash值取8位
-
// // [ext]: 使用之前的文件扩展名
-
// // [query]: 添加之前的query参数
-
// filename: "static/imgs/[hash:8][ext][query]",
-
// },
-
},
-
{
-
test:
/\.(ttf|woff2?)$/,
-
type:
"asset/resource",
-
// generator: {
-
// filename: "static/media/[hash:8][ext][query]",
-
// },
-
},
-
{
-
test:
/\.js$/,
-
// exclude: /node_modules/, // 排除node_modules代码不编译
-
include: path.
resolve(__dirname,
"../src"),
// 也可以用包含
-
use: [
-
{
-
loader:
"thread-loader",
// 开启多进程
-
options: {
-
workers: threads,
// 数量
-
},
-
},
-
{
-
loader:
"babel-loader",
-
options: {
-
cacheDirectory:
true,
// 开启babel编译缓存
-
cacheCompression:
false,
// 缓存文件不要压缩
-
plugins: [
"@babel/plugin-transform-runtime"],
// 减少代码体积
-
},
-
},
-
],
-
},
-
],
-
},
-
],
-
},
-
plugins: [
-
new
ESLintWebpackPlugin({
-
// 指定检查文件的根目录
-
context: path.
resolve(__dirname,
"../src"),
-
exclude:
"node_modules",
// 默认值
-
cache:
true,
// 开启缓存
-
// 缓存目录
-
cacheLocation: path.
resolve(
-
__dirname,
-
"../node_modules/.cache/.eslintcache"
-
),
-
threads,
// 开启多进程
-
}),
-
new
HtmlWebpackPlugin({
-
// 以 public/index.html 为模板创建文件
-
// 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源
-
template: path.
resolve(__dirname,
"../public/index.html"),
-
}),
-
// 提取css成单独文件
-
new
MiniCssExtractPlugin({
-
// 定义输出文件名和目录
-
filename:
"static/css/[name].[contenthash:8].css",
-
chunkFilename:
"static/css/[name].[contenthash:8].chunk.css",
-
}),
-
// css压缩
-
// new CssMinimizerPlugin(),
-
new
PreloadWebpackPlugin({
-
rel:
"preload",
// preload兼容性更好
-
as:
"script",
-
// rel: 'prefetch' // prefetch兼容性更差
-
}),
-
],
-
optimization: {
-
minimizer: [
-
// css压缩也可以写到optimization.minimizer里面,效果一样的
-
new
CssMinimizerPlugin(),
-
// 当生产模式会默认开启TerserPlugin,但是我们需要进行其他配置,就要重新写了
-
new
TerserPlugin({
-
parallel: threads,
// 开启多进程
-
}),
-
// 压缩图片
-
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",
-
},
-
},
-
],
-
},
-
],
-
],
-
},
-
},
-
}),
-
],
-
// 代码分割配置
-
splitChunks: {
-
chunks:
"all",
// 对所有模块都进行分割
-
// 其他内容用默认配置即可
-
},
-
},
-
// devServer: {
-
// host: "localhost", // 启动服务器域名
-
// port: "3000", // 启动服务器端口号
-
// open: true, // 是否自动打开浏览器
-
// },
-
mode:
"production",
-
devtool:
"source-map",
-
};
- 问题:
当我们修改 math.js 文件再重新打包的时候,因为 contenthash 原因,math.js 文件 hash 值发生了变化(这是正常的)。
但是 main.js 文件的 hash 值也发生了变化,这会导致 main.js 的缓存失效。明明我们只修改 math.js, 为什么 main.js 也会变身变化呢?
-
原因:
- 更新前:math.xxx.js, main.js 引用的 math.xxx.js
- 更新后:math.yyy.js, main.js 引用的 math.yyy.js, 文件名发生了变化,间接导致 main.js 也发生了变化
-
解决:
将 hash 值单独保管在一个 runtime 文件中。
我们最终输出三个文件:main、math、runtime。当 math 文件发送变化,变化的是 math 和 runtime 文件,main 不变。
runtime 文件只保存文件的 hash 值和它们与文件关系,整个文件体积就比较小,所以变化重新请求的代价也小。
-
const os =
require(
"os");
-
const path =
require(
"path");
-
const
ESLintWebpackPlugin =
require(
"eslint-webpack-plugin");
-
const
HtmlWebpackPlugin =
require(
"html-webpack-plugin");
-
const
MiniCssExtractPlugin =
require(
"mini-css-extract-plugin");
-
const
CssMinimizerPlugin =
require(
"css-minimizer-webpack-plugin");
-
const
TerserPlugin =
require(
"terser-webpack-plugin");
-
const
ImageMinimizerPlugin =
require(
"image-minimizer-webpack-plugin");
-
const
PreloadWebpackPlugin =
require(
"@vue/preload-webpack-plugin");
-
-
// cpu核数
-
const threads = os.
cpus().
length;
-
-
// 获取处理样式的Loaders
-
const
getStyleLoaders = (
preProcessor) => {
-
return [
-
MiniCssExtractPlugin.
loader,
-
"css-loader",
-
{
-
loader:
"postcss-loader",
-
options: {
-
postcssOptions: {
-
plugins: [
-
"postcss-preset-env",
// 能解决大多数样式兼容性问题
-
],
-
},
-
},
-
},
-
preProcessor,
-
].
filter(
Boolean);
-
};
-
-
module.
exports = {
-
entry:
"./src/main.js",
-
output: {
-
path: path.
resolve(__dirname,
"../dist"),
// 生产模式需要输出
-
// [contenthash:8]使用contenthash,取8位长度
-
filename:
"static/js/[name].[contenthash:8].js",
// 入口文件打包输出资源命名方式
-
chunkFilename:
"static/js/[name].[contenthash:8].chunk.js",
// 动态导入输出资源命名方式
-
assetModuleFilename:
"static/media/[name].[hash][ext]",
// 图片、字体等资源命名方式(注意用hash)
-
clean:
true,
-
},
-
module: {
-
rules: [
-
{
-
oneOf: [
-
{
-
// 用来匹配 .css 结尾的文件
-
test:
/\.css$/,
-
// use 数组里面 Loader 执行顺序是从右到左
-
use:
getStyleLoaders(),
-
},
-
{
-
test:
/\.less$/,
-
use:
getStyleLoaders(
"less-loader"),
-
},
-
{
-
test:
/\.s[ac]ss$/,
-
use:
getStyleLoaders(
"sass-loader"),
-
},
-
{
-
test:
/\.styl$/,
-
use:
getStyleLoaders(
"stylus-loader"),
-
},
-
{
-
test:
/\.(png|jpe?g|gif|svg)$/,
-
type:
"asset",
-
parser: {
-
dataUrlCondition: {
-
maxSize:
10 *
1024,
// 小于10kb的图片会被base64处理
-
},
-
},
-
// generator: {
-
// // 将图片文件输出到 static/imgs 目录中
-
// // 将图片文件命名 [hash:8][ext][query]
-
// // [hash:8]: hash值取8位
-
// // [ext]: 使用之前的文件扩展名
-
// // [query]: 添加之前的query参数
-
// filename: "static/imgs/[hash:8][ext][query]",
-
// },
-
},
-
{
-
test:
/\.(ttf|woff2?)$/,
-
type:
"asset/resource",
-
// generator: {
-
// filename: "static/media/[hash:8][ext][query]",
-
// },
-
},
-
{
-
test:
/\.js$/,
-
// exclude: /node_modules/, // 排除node_modules代码不编译
-
include: path.
resolve(__dirname,
"../src"),
// 也可以用包含
-
use: [
-
{
-
loader:
"thread-loader",
// 开启多进程
-
options: {
-
workers: threads,
// 数量
-
},
-
},
-
{
-
loader:
"babel-loader",
-
options: {
-
cacheDirectory:
true,
// 开启babel编译缓存
-
cacheCompression:
false,
// 缓存文件不要压缩
-
plugins: [
"@babel/plugin-transform-runtime"],
// 减少代码体积
-
},
-
},
-
],
-
},
-
],
-
},
-
],
-
},
-
plugins: [
-
new
ESLintWebpackPlugin({
-
// 指定检查文件的根目录
-
context: path.
resolve(__dirname,
"../src"),
-
exclude:
"node_modules",
// 默认值
-
cache:
true,
// 开启缓存
-
// 缓存目录
-
cacheLocation: path.
resolve(
-
__dirname,
-
"../node_modules/.cache/.eslintcache"
-
),
-
threads,
// 开启多进程
-
}),
-
new
HtmlWebpackPlugin({
-
// 以 public/index.html 为模板创建文件
-
// 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源
-
template: path.
resolve(__dirname,
"../public/index.html"),
-
}),
-
// 提取css成单独文件
-
new
MiniCssExtractPlugin({
-
// 定义输出文件名和目录
-
filename:
"static/css/[name].[contenthash:8].css",
-
chunkFilename:
"static/css/[name].[contenthash:8].chunk.css",
-
}),
-
// css压缩
-
// new CssMinimizerPlugin(),
-
new
PreloadWebpackPlugin({
-
rel:
"preload",
// preload兼容性更好
-
as:
"script",
-
// rel: 'prefetch' // prefetch兼容性更差
-
}),
-
],
-
optimization: {
-
minimizer: [
-
// css压缩也可以写到optimization.minimizer里面,效果一样的
-
new
CssMinimizerPlugin(),
-
// 当生产模式会默认开启TerserPlugin,但是我们需要进行其他配置,就要重新写了
-
new
TerserPlugin({
-
parallel: threads,
// 开启多进程
-
}),
-
// 压缩图片
-
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",
-
},
-
},
-
],
-
},
-
],
-
],
-
},
-
},
-
}),
-
],
-
// 代码分割配置
-
splitChunks: {
-
chunks:
"all",
// 对所有模块都进行分割
-
// 其他内容用默认配置即可
-
},
-
// 提取runtime文件
-
runtimeChunk: {
-
name:
(entrypoint) =>
`runtime~${entrypoint.name}`,
// runtime文件命名规则
-
},
-
},
-
// devServer: {
-
// host: "localhost", // 启动服务器域名
-
// port: "3000", // 启动服务器端口号
-
// open: true, // 是否自动打开浏览器
-
// },
-
mode:
"production",
-
devtool:
"source-map",
-
};
Core-js
为什么
过去我们使用 babel 对 js 代码进行了兼容性处理,其中使用@babel/preset-env 智能预设来处理兼容性问题。
它能将 ES6 的一些语法进行编译转换,比如箭头函数、点点点运算符等。但是如果是 async 函数、promise 对象、数组的一些方法(includes)等,它没办法处理。
所以此时我们 js 代码仍然存在兼容性问题,一旦遇到低版本浏览器会直接报错。所以我们想要将 js 兼容性问题彻底解决
是什么
core-js
是专门用来做 ES6 以及以上 API 的 polyfill
。
polyfill
翻译过来叫做垫片/补丁。就是用社区上提供的一段代码,让我们在不兼容某些新特性的浏览器上,使用该新特性。
怎么用
- 修改 main.js
-
import count
from
"./js/count";
-
import sum
from
"./js/sum";
-
// 引入资源,Webpack才会对其打包
-
import
"./css/iconfont.css";
-
import
"./css/index.css";
-
import
"./less/index.less";
-
import
"./sass/index.sass";
-
import
"./sass/index.scss";
-
import
"./styl/index.styl";
-
-
const result1 =
count(
2,
1);
-
console.
log(result1);
-
const result2 =
sum(
1,
2,
3,
4);
-
console.
log(result2);
-
// 添加promise代码
-
const promise =
Promise.
resolve();
-
promise.
then(
() => {
-
console.
log(
"hello promise");
-
});
此时 Eslint 会对 Promise 报错。
- 修改配置文件
- 下载包
npm i @babel/eslint-parser -D
- .eslintrc.js
-
module.exports = {
-
// 继承 Eslint 规则
-
extends: [
"eslint:recommended"],
-
parser:
"@babel/eslint-parser",
// 支持最新的最终 ECMAScript 标准
-
env: {
-
node:
true,
// 启用node中全局变量
-
browser:
true,
// 启用浏览器中全局变量
-
},
-
plugins: [
"import"],
// 解决动态导入import语法报错问题 --> 实际使用eslint-plugin-import的规则解决的
-
parserOptions: {
-
ecmaVersion:
6,
// es6
-
sourceType:
"module",
// es
module
-
},
-
rules: {
-
"no-var":
2,
// 不能使用 var 定义变量
-
},
-
};
- 运行指令
npm run build
此时观察打包输出的 js 文件,我们发现 Promise 语法并没有编译转换,所以我们需要使用 core-js
来进行 polyfill
。
- 使用
core-js
- 下载包
npm i core-js
- 手动全部引入
-
import
"core-js";
-
import count
from
"./js/count";
-
import sum
from
"./js/sum";
-
// 引入资源,Webpack才会对其打包
-
import
"./css/iconfont.css";
-
import
"./css/index.css";
-
import
"./less/index.less";
-
import
"./sass/index.sass";
-
import
"./sass/index.scss";
-
import
"./styl/index.styl";
-
-
const result1 =
count(
2,
1);
-
console.
log(result1);
-
const result2 =
sum(
1,
2,
3,
4);
-
console.
log(result2);
-
// 添加promise代码
-
const promise =
Promise.
resolve();
-
promise.
then(
() => {
-
console.
log(
"hello promise");
-
});
这样引入会将所有兼容性代码全部引入,体积太大了。我们只想引入 promise 的 polyfill
。
- 手动按需引入
-
import
"core-js/es/promise";
-
import count
from
"./js/count";
-
import sum
from
"./js/sum";
-
// 引入资源,Webpack才会对其打包
-
import
"./css/iconfont.css";
-
import
"./css/index.css";
-
import
"./less/index.less";
-
import
"./sass/index.sass";
-
import
"./sass/index.scss";
-
import
"./styl/index.styl";
-
-
const result1 =
count(
2,
1);
-
console.
log(result1);
-
const result2 =
sum(
1,
2,
3,
4);
-
console.
log(result2);
-
// 添加promise代码
-
const promise =
Promise.
resolve();
-
promise.
then(
() => {
-
console.
log(
"hello promise");
-
});
只引入打包 promise 的 polyfill
,打包体积更小。但是将来如果还想使用其他语法,我需要手动引入库很麻烦。
-
自动按需引入
- main.js
-
import count from "./js/count";
-
import sum from "./js/sum";
-
// 引入资源,Webpack才会对其打包
-
import "./css/iconfont.css";
-
import "./css/index.css";
-
import "./less/index.less";
-
import "./sass/index.sass";
-
import "./sass/index.scss";
-
import "./styl/index.styl";
-
-
const result1 = count( 2, 1);
-
console. log(result1);
-
const result2 = sum( 1, 2, 3, 4);
-
console. log(result2);
-
// 添加promise代码
-
const promise = Promise. resolve();
-
promise. then( () => {
-
console. log( "hello promise");
-
});
此时就会自动根据我们代码中使用的语法,来按需加载相应的 polyfill
了。
PWA
为什么
开发 Web App 项目,项目一旦处于网络离线情况,就没法访问了。
我们希望给项目提供离线体验。
是什么
渐进式网络应用程序(progressive web application - PWA):是一种可以提供类似于 native app(原生应用程序) 体验的 Web App 的技术。
其中最重要的是,在 离线(offline) 时应用程序能够继续运行功能。
内部通过 Service Workers 技术实现的。
怎么用
- 下载包
npm i workbox-webpack-plugin -D
- 修改配置文件
-
const os =
require(
"os");
-
const path =
require(
"path");
-
const
ESLintWebpackPlugin =
require(
"eslint-webpack-plugin");
-
const
HtmlWebpackPlugin =
require(
"html-webpack-plugin");
-
const
MiniCssExtractPlugin =
require(
"mini-css-extract-plugin");
-
const
CssMinimizerPlugin =
require(
"css-minimizer-webpack-plugin");
-
const
TerserPlugin =
require(
"terser-webpack-plugin");
-
const
ImageMinimizerPlugin =
require(
"image-minimizer-webpack-plugin");
-
const
PreloadWebpackPlugin =
require(
"@vue/preload-webpack-plugin");
-
const
WorkboxPlugin =
require(
"workbox-webpack-plugin");
-
-
// cpu核数
-
const threads = os.
cpus().
length;
-
-
// 获取处理样式的Loaders
-
const
getStyleLoaders = (
preProcessor) => {
-
return [
-
MiniCssExtractPlugin.
loader,
-
"css-loader",
-
{
-
loader:
"postcss-loader",
-
options: {
-
postcssOptions: {
-
plugins: [
-
"postcss-preset-env",
// 能解决大多数样式兼容性问题
-
],
-
},
-
},
-
},
-
preProcessor,
-
].
filter(
Boolean);
-
};
-
-
module.
exports = {
-
entry:
"./src/main.js",
-
output: {
-
path: path.
resolve(__dirname,
"../dist"),
// 生产模式需要输出
-
// [contenthash:8]使用contenthash,取8位长度
-
filename:
"static/js/[name].[contenthash:8].js",
// 入口文件打包输出资源命名方式
-
chunkFilename:
"static/js/[name].[contenthash:8].chunk.js",
// 动态导入输出资源命名方式
-
assetModuleFilename:
"static/media/[name].[hash][ext]",
// 图片、字体等资源命名方式(注意用hash)
-
clean:
true,
-
},
-
module: {
-
rules: [
-
{
-
oneOf: [
-
{
-
// 用来匹配 .css 结尾的文件
-
test:
/\.css$/,
-
// use 数组里面 Loader 执行顺序是从右到左
-
use:
getStyleLoaders(),
-
},
-
{
-
test:
/\.less$/,
-
use:
getStyleLoaders(
"less-loader"),
-
},
-
{
-
test:
/\.s[ac]ss$/,
-
use:
getStyleLoaders(
"sass-loader"),
-
},
-
{
-
test:
/\.styl$/,
-
use:
getStyleLoaders(
"stylus-loader"),
-
},
-
{
-
test:
/\.(png|jpe?g|gif|svg)$/,
-
type:
"asset",
-
parser: {
-
dataUrlCondition: {
-
maxSize:
10 *
1024,
// 小于10kb的图片会被base64处理
-
},
-
},
-
// generator: {
-
// // 将图片文件输出到 static/imgs 目录中
-
// // 将图片文件命名 [hash:8][ext][query]
-
// // [hash:8]: hash值取8位
-
// // [ext]: 使用之前的文件扩展名
-
// // [query]: 添加之前的query参数
-
// filename: "static/imgs/[hash:8][ext][query]",
-
// },
-
},
-
{
-
test:
/\.(ttf|woff2?)$/,
-
type:
"asset/resource",
-
// generator: {
-
// filename: "static/media/[hash:8][ext][query]",
-
// },
-
},
-
{
-
test:
/\.js$/,
-
// exclude: /node_modules/, // 排除node_modules代码不编译
-
include: path.
resolve(__dirname,
"../src"),
// 也可以用包含
-
use: [
-
{
-
loader:
"thread-loader",
// 开启多进程
-
options: {
-
workers: threads,
// 数量
-
},
-
},
-
{
-
loader:
"babel-loader",
-
options: {
-
cacheDirectory:
true,
// 开启babel编译缓存
-
cacheCompression:
false,
// 缓存文件不要压缩
-
plugins: [
"@babel/plugin-transform-runtime"],
// 减少代码体积
-
},
-
},
-
],
-
},
-
],
-
},
-
],
-
},
-
plugins: [
-
new
ESLintWebpackPlugin({
-
// 指定检查文件的根目录
-
context: path.
resolve(__dirname,
"../src"),
-
exclude:
"node_modules",
// 默认值
-
cache:
true,
// 开启缓存
-
// 缓存目录
-
cacheLocation: path.
resolve(
-
__dirname,
-
"../node_modules/.cache/.eslintcache"
-
),
-
threads,
// 开启多进程
-
}),
-
new
HtmlWebpackPlugin({
-
// 以 public/index.html 为模板创建文件
-
// 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源
-
template: path.
resolve(__dirname,
"../public/index.html"),
-
}),
-
// 提取css成单独文件
-
new
MiniCssExtractPlugin({
-
// 定义输出文件名和目录
-
filename:
"static/css/[name].[contenthash:8].css",
-
chunkFilename:
"static/css/[name].[contenthash:8].chunk.css",
-
}),
-
// css压缩
-
// new CssMinimizerPlugin(),
-
new
PreloadWebpackPlugin({
-
rel:
"preload",
// preload兼容性更好
-
as:
"script",
-
// rel: 'prefetch' // prefetch兼容性更差
-
}),
-
new
WorkboxPlugin.
GenerateSW({
-
// 这些选项帮助快速启用 ServiceWorkers
-
// 不允许遗留任何“旧的” ServiceWorkers
-
clientsClaim:
true,
-
skipWaiting:
true,
-
}),
-
],
-
optimization: {
-
minimizer: [
-
// css压缩也可以写到optimization.minimizer里面,效果一样的
-
new
CssMinimizerPlugin(),
-
// 当生产模式会默认开启TerserPlugin,但是我们需要进行其他配置,就要重新写了
-
new
TerserPlugin({
-
parallel: threads,
// 开启多进程
-
}),
-
// 压缩图片
-
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",
-
},
-
},
-
],
-
},
-
],
-
],
-
},
-
},
-
}),
-
],
-
// 代码分割配置
-
splitChunks: {
-
chunks:
"all",
// 对所有模块都进行分割
-
// 其他内容用默认配置即可
-
},
-
},
-
// devServer: {
-
// host: "localhost", // 启动服务器域名
-
// port: "3000", // 启动服务器端口号
-
// open: true, // 是否自动打开浏览器
-
// },
-
mode:
"production",
-
devtool:
"source-map",
-
};
- 修改 main.js
-
import count
from
"./js/count";
-
import sum
from
"./js/sum";
-
// 引入资源,Webpack才会对其打包
-
import
"./css/iconfont.css";
-
import
"./css/index.css";
-
import
"./less/index.less";
-
import
"./sass/index.sass";
-
import
"./sass/index.scss";
-
import
"./styl/index.styl";
-
-
const result1 =
count(
2,
1);
-
console.
log(result1);
-
const result2 =
sum(
1,
2,
3,
4);
-
console.
log(result2);
-
// 添加promise代码
-
const promise =
Promise.
resolve();
-
promise.
then(
() => {
-
console.
log(
"hello promise");
-
});
-
-
const arr = [
1,
2,
3,
4,
5];
-
console.
log(arr.
includes(
5));
-
-
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);
-
});
-
});
-
}
- 运行指令
npm run build
此时如果直接通过 VSCode 访问打包后页面,在浏览器控制台会发现 SW registration failed
。
因为我们打开的访问路径是:http://127.0.0.1:5500/dist/index.html
。此时页面会去请求 service-worker.js
文件,请求路径是:http://127.0.0.1:5500/service-worker.js
,这样找不到会 404。
实际 service-worker.js
文件路径是:http://127.0.0.1:5500/dist/service-worker.js
。
- 解决路径问题
- 下载包
npm i serve -g
serve 也是用来启动开发服务器来部署代码查看效果的。
- 运行指令
serve dist
此时通过 serve 启动的服务器我们 service-worker 就能注册成功了。
转载:https://blog.csdn.net/qq_63358859/article/details/128765155