Tree Shaking

为什么需要Tree Shaking

  • 开发时我们定义了一些工具函数库,或者引用第三方工具函数库或组件库。例如elementUI等….

  • 如果没有特殊处理的话我们打包时会引入整个库,但是实际上可能我们可能只用上极小部分的功能。

  • 这样将整个库都打包进来,体积就太大了。

Tree Shaking是什么?

  • Tree Shaking 是一个术语(webpack中的术语),通常用于描述移除 JavaScript 中的没有使用上的代码。

  • 注意:它依赖 ES Module

如何使用Tree Shaking

  • Webpack 已经默认开启了这个功能,无需其他配置。

Babel处理重复的辅助代码

为什么?

  • Babel 为编译的每个文件都插入了辅助代码,使代码体积过大!

  • Babel 对一些公共方法使用了非常小的辅助代码,比如 _extend。默认情况下会被添加到每一个需要它的文件中。

  • 你可以将这些辅助代码作为一个独立模块,来避免重复引入。

是什么

  • @babel/plugin-transform-runtime: 禁用了 Babel 自动对每个文件的 runtime 注入,而是引入 @babel/plugin-transform-runtime 并且使所有辅助代码从这里引用。

怎么用

1. 下载包

npm i @babel/plugin-transform-runtime -D

2. 配置

// 使用的是commonjs 的语法格式[node.js]
const path = require("path");//node.js中的核心模块,专门用于处理路径问题
// 引入eslint
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
// 引入HtmlWebpackPlugin插件
const HtmlWebpackPlugin = require("html-webpack-plugin");
// 获取os内置模块
const os = require("os");
// 引入Terser内置插件
// const TerserPlugin = require("terser-webpack-plugin");

// 获取cpu核数
const threads = os.cpus().length;

module.exports = {
// 入口
// 相对路径和绝对路径都行
entry:"./src/main.js",//相对路径
// 输出
output:{
// 所有文件的输出目录,必须是绝对路径
path: undefined, // 开发模式没有输出(因为存在开发服务器,不存在输出),不需要指定输出目录
// js文件(入口文件)输出的文件名(打包后在输出路径当中生成的文件夹名)
filename:"static/js/main.js",//所以我们这里改成js资源就输出到一个js文件夹当中
// clean: true, // 开发模式没有输出,不需要清空输出结果(开发服务器)
},
// 加载器
module:{
rules:[
// loder的配置
{
// oneOf配置, 每个文件只能被其中一个loader处理(第一个遇到的)***********************************
oneOf: [
// 1.处理css资源
{
// 用来匹配 .css 结尾的文件
test: /\.css$/,
// use 数组里面 Loader 执行顺序是从右到左
use: [
"style-loader", //将js中css通过创建style标签添加html文件当中生效
"css-loader"//将css资源编译成common.js的模块到js当中
],
},
// 2.处理less资源
{
test: /\.less$/,
// loader:xxx => 自能使用一个loader
use: [
"style-loader",
"css-loader",
"less-loader"//将less编译成css文件
], // use能够使用多个loader
},
// 3.处理图片资源
{
test: /\.(png|jpe?g|gif|webp)$/,//正则判断图片后缀
type: "asset",
parser:{
dataUrlCondition:{
// 将小于10kb的图片转化为base64
// 优点:减小请求数量 缺点:原图片的体积会变大(故大体积突变不会使用这种方法)
maxSize: 10*1024//10kb(大体积图片不会使用这种方法)
}
},
generator: {
// 将图片文件输出到 static/imgs 目录中
// 将图片文件命名 [hash:8][ext][query]
// [hash:8]: hash值取8位
// [ext]: 使用之前的文件扩展名
// [query]: 添加之前的query参数
filename: 'static/imgs/[hash:8][ext][query]'
}
},
// 4.处理字体资源
{
test: /\.(ttf|woff2?)$/,
type: "asset/resource",//这里的是改成"asset/resource"
generator: {
filename: "static/media/[hash:8][ext][query]",
},
},
// 配置babel**********************************************************
{
test: /\.js$/,//检查匹配以js结尾的文件

// Include/Exclude*******************************************
// exclude: /node_modules/, // 排除node_modules代码不编译
include: path.resolve(__dirname, "../src"), // 也可以用包含(两者只能用其一)
// **********************************************************

use: [
{//开启多线程编译打包***************************
loader: "thread-loader", // 开启多进程
options: {
workers: threads, // 数量
},
// *****************************************
},
{
loader: "babel-loader",
//cache缓存**********************************
options: {
cacheDirectory: true, // 开启babel编译缓存
cacheCompression: false, // 缓存文件不要压缩

// 减小babel编译时生成的重复辅助代码**************************
plugins: ["@babel/plugin-transform-runtime"], // 减少代码体积
// *********************************************************
},
// ******************************************
},
],
// ********************************************************
},
// *******************************************************************
]
// ********************************************************************************
}
],
},
// 插件
plugins:[
// plugin的配置

// eslint配置
new ESLintWebpackPlugin({
// 指定检查文件的根目录(src目录下的所有文件的语法)
context: path.resolve(__dirname, "../src"),

// Include/Exclude******************
exclude: "node_modules", // 默认值
// ********************************

// cache缓存设置*******************
cache: true, // 开启缓存
// 缓存目录(eslint缓存存放的路径)
cacheLocation: path.resolve(
__dirname,
"../node_modules/.cache/.eslintcache"
),
// ******************************

// 开启多线程打包编译***************
threads, // 开启多进程
// *******************************
}),

// HtmlWebpackPlugin配置*******************************************************
new HtmlWebpackPlugin({
// 以 public/index.html 为模板创建文件
// 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源
template: path.resolve(__dirname, "../public/index.html"),
}),
// ****************************************************************************
],

// 配置开发服务器: 不会输出任何资源, 在内存中的编译打包的*******************************
devServer: {
host: "localhost", // 启动服务器域名
port: "5000", // 启动服务器端口号
open: true, // 是否自动打开浏览器
hot: true, // 关闭HMR功能(默认开启,只能用于开发环境,生产环境不需要了)
},
// **********************************************************************************
// 模式
mode:"development",//开发模式
devtool: "cheap-module-source-map",//sourceMap开发模式
};

3. 图片压缩(Image Minimizer)

为什么需要图片压缩?

  • 开发如果项目中引用了较多图片(本地图片),那么图片体积会比较大,将来请求速度比较慢。

  • 我们可以对图片进行压缩,减少图片体积。

注意:如果项目中图片都是在线链接,那么就不需要了。本地项目静态图片才需要进行压缩。

图片压缩是什么?

  • image-minimizer-webpack-plugin: 用来压缩图片的插件

使用方法:

1. 下载包

npm i image-minimizer-webpack-plugin imagemin -D
  • 还有剩下包需要下载,有两种模式:

2. 无损压缩

npm install imagemin-gifsicle imagemin-jpegtran imagemin-optipng imagemin-svgo -D

3. 有损压缩

npm install imagemin-gifsicle imagemin-mozjpeg imagemin-pngquant imagemin-svgo -D

4. 配置webpack.prod.js(一般是生产模式,以无损压缩为例)

// 使用的是commonjs 的语法格式[node.js]
const path = require("path");//node.js中的核心模块,专门用于处理路径问题
// 获取os内置模块
const os = require("os");
// 引入eslint
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
// 引入HtmlWebpackPlugin插件
const HtmlWebpackPlugin = require("html-webpack-plugin");
// 引入MiniCssExtractPlugin插件
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// 引入CssMinimizerPlugin插件
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
// 引入Terser内置插件
const TerserPlugin = require("terser-webpack-plugin");
// 引入图片压缩插件
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");

// 获取cpu核数
const threads = os.cpus().length;

// 设置一个函数用来获取样式处理的loader(提高代码复用率)
function getStyleLoader(pre){//pre为其他的loader,如less-loader
return [
// *************************************************************************
MiniCssExtractPlugin.loader, //将style-loder改成MiniCssExtractPlugin.loader
// ************************************************************************
"css-loader",//将css资源编译成common.js的模块到js当中

// postcss-loader处理css样式的兼容性问题(放在cssloder后面,lessloder前面)*****
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env", // 能解决大多数样式兼容性问题
],
},
},
},
// ************************************************************************
pre,
].filter(Boolean)//设置一个布尔值的filter来过滤掉undefined(存css样式不需要pre[即其他的loader])
}

module.exports = {
// 入口
// 相对路径和绝对路径都行
entry:"./src/main.js",//相对路径
// 输出
output:{
// 所有文件的输出目录,必须是绝对路径
// path.resolve()方法返回一个绝对路径
// __dirname为node.js中的变量,代表当前文件的文件夹名(就是这个文件夹的webpack_code)
path: path.resolve(__dirname , "../dist"),//相较于开发模式,生产模式需要输出
// js文件(入口文件)输出的文件名(打包后在输出路径当中生成的文件夹名)
filename:"static/js/main.js",//所以我们这里改成js资源就输出到一个js文件夹当中
clean: true,//需要输出就需要clean(自动清空上次打包内容) 原理:在打包前,将path整个目录内容清空,在进行打包
},
// 加载器
module:{
rules:[
// loder的配置
{
// oneOf配置, 每个文件只能被其中一个loader处理(第一个遇到的)************************
oneOf: [
// 1.处理css资源
{
// 用来匹配 .css 结尾的文件
test: /\.css$/,
// use 数组里面 Loader 执行顺序是从右到左
use: getStyleLoader()
},
// 2.处理less资源
{
test: /\.less$/,
// loader:xxx => 自能使用一个loader
use: getStyleLoader("less-loader")
},
// 3.处理图片资源
{
test: /\.(png|jpe?g|gif|webp)$/,//正则判断图片后缀
type: "asset",
parser:{
dataUrlCondition:{
// 将小于10kb的图片转化为base64
// 优点:减小请求数量 缺点:原图片的体积会变大(故大体积突变不会使用这种方法)
maxSize: 10*1024//10kb(大体积图片不会使用这种方法)
}
},
generator: {
// 将图片文件输出到 static/imgs 目录中
// 将图片文件命名 [hash:8][ext][query]
// [hash:8]: hash值取8位
// [ext]: 使用之前的文件扩展名
// [query]: 添加之前的query参数
filename: 'static/imgs/[hash:8][ext][query]'
}
},
// 4.处理字体资源
{
test: /\.(ttf|woff2?)$/,
type: "asset/resource",//这里的是改成"asset/resource"
generator: {
filename: "static/media/[hash:8][ext][query]",
},
},
// 配置babel***********************************************
{
test: /\.js$/,//检查匹配以js结尾的文件
// Include/Exclude*******************************************
// exclude: /node_modules/, // 排除node_modules代码不编译
include: path.resolve(__dirname, "../src"), // 也可以用包含(两者只能用其一)
// **********************************************************

use: [
{//开启多线程编译打包***************************
loader: "thread-loader", // 开启多进程
options: {
workers: threads, // 数量
},
// *****************************************
},
{
loader: "babel-loader",
options: {
cacheDirectory: true, // 开启babel编译缓存
},
},
],
// ********************************************************
},
]
// ****************************************************************************
}
],
},
// 插件
plugins:[
// plugin的配置

// eslint配置
new ESLintWebpackPlugin({
// 指定检查文件的根目录(src目录下的所有文件的语法)
context: path.resolve(__dirname, "../src"),
// Include/Exclude******************
exclude: "node_modules", // 默认值
// ********************************
cache: true, // 开启缓存
// 缓存目录
cacheLocation: path.resolve(
__dirname,
"../node_modules/.cache/.eslintcache"
),
// 开启多线程打包编译***************
threads, // 开启多进程
// *******************************
}),

// HtmlWebpackPlugin配置*******************************************************
new HtmlWebpackPlugin({
// 以 public/index.html 为模板创建文件
// 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源
template: path.resolve(__dirname, "../public/index.html"),
}),
// ****************************************************************************

// 提取css成单独文件
new MiniCssExtractPlugin({
// 定义输出文件名和输出路径
filename: "static/css/main.css",
}),
// css压缩************************************************************************
// new CssMinimizerPlugin(),
// ******************************************************************************
],

// 开启多线程需要重新手写 Terser 内置模块*********************************************
// webpack5一般指定压缩地方为这里,上面也可以
optimization: {
minimize: true,
minimizer: [
// css压缩
// css压缩也可以写到optimization.minimizer里面,效果一样的
new CssMinimizerPlugin(),//压缩css

//js压缩
// 当生产模式会默认开启TerserPlugin,但是我们需要进行其他配置,就要重新写了
new TerserPlugin({//内置模块压缩js
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",
},
},
],
},
],
],
},
},
}),
// *************************************************
],
},
// **********************************************************************************

/*
生产模式不需要开发服务器(devServer)
*/
// 模式
mode:"production",//生产模式
devtool: "source-map",//sourceMap生产模式
};