前端打包工具之Webpack5
- 什么是打包工具
- 打包工具的作用
- 常见的打包工具
- 一、Webpack
- 1、什么是[webpack](https://webpack.docschina.org/concepts/)
- 2、webpack本身的功能是有限的
- 3、webpack基本使用:基于本身功能只解析JS资源
- 4、webpack配置
- 4.1、`entry`(入口):指示webpack从哪个文件开始打包
- 4.2、`output`(出口):指示webpack打包完的文件输出到哪里、如何命名
- 4.3、`loader` ([加载器](https://webpack.docschina.org/concepts/loaders)):webpack本身只能处理js、json资源,其他资源需要借助loader
- 4.4、`plugins` ([插件](https://webpack.docschina.org/api/plugins)): 扩展webpack功能
- 4.5、`mode` ([模式](https://webpack.docschina.org/configuration/mode)) :开发、生产模式
- 4.6、`browser compatibility` (浏览器兼容性)
- 4.7、`environment` (环境): Webpack 5 运行于 Node.js v10.13.0+ 的版本
- 5、webpack提升打包构建速度
- 5.1、热更新:只针对开发模式
- 5.2、oneOf配置项
- 5.3、exclude配置项或者include配置项
- 5.4、ESLint、babel添加缓存
- 5.5、启动多线程打包
- 5.6、减少代码体积
- 5.7、减少文件中的babel辅助代码引入
- 5.8、压缩静态资源图片
- 6、webpack配置代码
什么是打包工具
将浏览器无法运行的高级语法代码(如:es6、scss)编译成浏览器能识别的JS、CSS等语法。
打包工具的作用
- 语法编辑
- 压缩代码
- 兼容性处理
- 代码性能优化
- …
常见的打包工具
- Vite
- Webpack
- parcel
一、Webpack
1、什么是webpack
webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具。它会以一个或多个文件作为打包的入口,将整个项目所有文件编译组合成一个或者多个文件(
bundles
)输出。
webpack 开箱即用,可以无需使用任何配置文件。然而,webpack 会假定项目的入口起点为 src/index.js,然后会在 dist/main.js 输出结果,并且在生产环境开启压缩和优化
2、webpack本身的功能是有限的
webpack本身的功能是有限的
- 开发模式: 仅能编译JS中的ES Model语法
- 生产模式:编译JS中的ES Model语法,还能压缩JS代码
即是:webpack本身只能处理JS编译,其他编译和处理需要进一步的配置
3、webpack基本使用:基于本身功能只解析JS资源
- 初始化package.json
$ npm init -y
- 下载依赖 cli
$ npm i webpack webpack-cli -D
webpack从4.0版本开始,在安装时,就需要安装webpack和webpack-cli这两个东西。(1、webpack是打包代码时的核心内容;2、webpack-cli是一个用来在命令行中运行webpack的工具)
xxx-cli的主要功能就是:处理命令行参数(如果你想使用 npx 来运行 webpack,请确保你已经安装了 webpack-cli);npm run build -> 执行node_modules/webpack文件 -> 执行webpack-cli文件 -> 执行cli.run() -> 处理命令行参数。
- 执行webpack打包
// 开发环境
$ npx webpack ./app.js --mode=development
// 生产环境
$ npx webpack ./app.js --mode=production
npx webpack: 运行本地安装的webpack包(npx: 用于快速执行本地或远程的npm包)
./app.js: 打包入口文件
–mode=XXX:打包模式
以上步骤默认打包的是JS代码,CSS等其他代码的处理,需要另行配置
4、webpack配置
npx webpack init: 根据项目需求快速生产webpack配置
4.1、entry
(入口):指示webpack从哪个文件开始打包
默认src/index.js
4.2、output
(出口):指示webpack打包完的文件输出到哪里、如何命名
4.3、loader
(加载器):webpack本身只能处理js、json资源,其他资源需要借助loader
webpack 只能理解 JavaScript 和 JSON 文件,这是 webpack 开箱可用的自带能力。loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效 模块,以供应用程序使用,以及被添加到依赖图中。
loader 的两个属性:
test
属性,识别出哪些文件会被转换。use
属性,定义出在进行转换时,应该使用哪个 loader。
const path = require('path');module.exports = {output: {filename: 'my-first-webpack.bundle.js',},module: {// 嘿,webpack 编译器,当你碰到「在 require()/import 语句中被解析为 '.txt' 的路径」时,在你对它打包之前,先 use(使用) raw-loader 转换一下rules: [{ test: /\.txt$/, use: 'raw-loader' }],},
};
4.4、plugins
(插件): 扩展webpack功能
想要使用一个插件,你只需要 require() 它,然后把它添加到 plugins 数组中。多数插件可以通过选项(option)自定义。你也可以在一个配置文件中因为不同目的而多次使用同一个插件,这时需要通过使用 new 操作符来创建一个插件实例
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack'); // 用于访问内置插件module.exports = {module: {rules: [{ test: /\.txt$/, use: 'raw-loader' }],},plugins: [new HtmlWebpackPlugin({ template: './src/index.html' })],
};
4.5、mode
(模式) :开发、生产模式
4.6、browser compatibility
(浏览器兼容性)
Webpack 支持所有符合 ES5 标准 的浏览器(不支持 IE8 及以下版本)。webpack 的 import() 和 require.ensure() 需要 Promise。如果你想要支持旧版本浏览器,在使用这些表达式之前,还需要 提前加载 polyfill。
4.7、environment
(环境): Webpack 5 运行于 Node.js v10.13.0+ 的版本
5、webpack提升打包构建速度
5.1、热更新:只针对开发模式
// 生产模式下不需要devServer
devServer: {host: '0.0.0.0',port: 3000,compress: true,// 默认为true: 提升开发模式的打包构建速度// 默认只支持css热更新 js的需要加载相应loaderhot: true, // 开启HRM 热更新
},
5.2、oneOf配置项
// 加载器: 帮助webpack识别 本身不能识别的资源
module: {// loader的配置rules: {// 避免找到了loader 还会继续遍历后面的loaderoneOf: [// 处理css资源{},// 处理图片资源{},// 处理其他资源{},// 将高阶JS语法处理成IE等旧浏览器能识别的JS语法{test: /\.js$/,// 排除哪些不需要处理的文件exclude: /(node_modules|bower_components)/,// 只加载一个loader 可以直接使用loader替换useloader: 'babel-loader',// 可以直接在项目中 新建babel配置文件(babel.config.js), 方便配置扩展// options: {// presets: ['@babel/preset-env']// }}]}
},
5.3、exclude配置项或者include配置项
exclude、include不能同时使用
{test: /\.js$/,// 排除哪些不需要处理的文件exclude: /(node_modules|bower_components)/,// include: path.resolve(__dirname, "../src"),// 只加载一个loader 可以直接使用loader替换useloader: 'babel-loader',// 可以直接在项目中 新建babel配置文件(babel.config.js), 方便配置扩展// options: {// presets: ['@babel/preset-env']// }
}
5.4、ESLint、babel添加缓存
- babel添加缓存
// 将高阶JS语法处理成IE等旧浏览器能识别的JS语法
{test: /\.js$/,// 排除哪些不需要处理的文件exclude: /(node_modules|bower_components)/,// 只加载一个loader 可以直接使用loader替换useloader: 'babel-loader',options: {// 可以直接在项目中 新建babel配置文件(babel.config.js), 方便配置扩展// presets: ['@babel/preset-env']cacheDirectory: true, // 开启babel缓存cacheCompression: false // 关闭缓存文件压缩}
}
- ESLint 添加缓存
// 插件
plugins: [// ESLint检验new ESLintPlugin({// eslint 只检测src下面的文件context: path.resolve(__dirname, '../src'),exclude: 'node_modules', // 默认值: node_modulescache: true, // 开启缓存cacheLocation: path.resolve(__dirname, "../node_modules/.cache/eslintcache")}),
],
5.5、启动多线程打包
- 获取cpu核数
const os = require('os')
// 获取cpu核数
const threads = os.cpus().length;
- babel操作开启多线程
# 安装thread-loader
$ npm install --save-dev thread-loader
// 将高阶JS语法处理成IE等旧浏览器能识别的JS语法
{test: /\.js$/,// 排除哪些不需要处理的文件exclude: /(node_modules|bower_components)/,use: [{loader: "thread-loader",options: {workers: threads, // babel: 进程数量}},{loader: 'babel-loader',options: {// 可以直接在项目中 新建babel配置文件(babel.config.js), 方便配置扩展// presets: ['@babel/preset-env']cacheDirectory: true, // 开启babel缓存cacheCompression: false // 关闭缓存文件压缩}}]
}
- ESLint开启多进程
plugins: [// ESLint检验new ESLintPlugin({// eslint 只检测src下面的文件context: path.resolve(__dirname, '../src'),exclude: 'node_modules', // 默认值: node_modulescache: true, // 开启缓存cacheLocation: path.resolve(__dirname, "../node_modules/.cache/eslintcache"),threads // 开启多进程}),
],
- 压缩js开启多进程
const TerserWebpackPlugin = require('terser-webpack-plugin')
optimization: {// 压缩的操作minimizer: [// 压缩jsnew TerserWebpackPlugin({// 开启多进程parallel: threads,}),],
},
5.6、减少代码体积
Tree Shaking: 移除JS中没有使用上的代码。 生产环境下已经默认开启了
5.7、减少文件中的babel辅助代码引入
{test: /\.js$/,// 排除哪些不需要处理的文件exclude: /(node_modules|bower_components)/,use: [{loader: "thread-loader",options: {workers: threads, // babel: 进程数量}},{loader: 'babel-loader',options: {// 可以直接在项目中 新建babel配置文件(babel.config.js), 方便配置扩展// presets: ['@babel/preset-env']cacheDirectory: true, // 开启babel缓存cacheCompression: false, // 关闭缓存文件压缩plugins: ["@babel/plugin-transform-runtime"] // 减少代码体积:避免不必要的babel的辅助代码注入}}]
}
5.8、压缩静态资源图片
图片压缩
6、webpack配置代码
const path = require('path')
const os = require('os')
const ESLintPlugin = 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 nodeExternals = require('webpack-node-externals')
const TerserWebpackPlugin = require('terser-webpack-plugin')
// 获取cpu核数
const threads = os.cpus().length;
// 生产模式下:进行项目优化: 优化打包速度; 优化运行性能module.exports = {target: 'node', // ignore built-in modules like path, fs, etc.externals: [nodeExternals()], // 排除Node.js核心模块// 项目打包入口: 相对路径entry: './src/app.js',// 模式mode: "production",// 包含行和列的映射 打包速度慢// 开发模式: 'cheap-module-source-map'devtool: 'source-map', // 将编译后的代码映射回原始源代码// 打包出口: 绝对路径output: {// __dirname: node变量: 当前文件的文件夹目录path: path.resolve(__dirname, '../dist'), // 打包后所有文件的输出路径filename: 'static/js/[name].js', // 入口文件打包后的输出路径// 给打包输出的其他文件命名 比如import动态导入的文件// 结合webpack 魔法命名 import(/* webpackChunkName: "app" */ "./src/app.js").then(()=>{})chunkFilename: 'static/js/[name].chunk.js',// 图片、字体等通过type: asset 处理资源命名方式 替换掉generatorassetModuleFilename: 'static/media/[hash:10][ext][query]',clean: true, // 自动清空path目录内容,再进行打包publicPath: '/assets/',},// 加载器: 帮助webpack识别 本身不能识别的资源module: {// loader的配置rules: {// 避免找到了loader 还会继续遍历后面的loaderoneOf: [// 处理css资源{test: /\.s[ac]ss$/,// use的加载顺序: 从右向左use: [// "style-loader", // 将js中的css通过创建style标签添加到html文件中MiniCssExtractPlugin.loader, // 将css资源抽离成css文件, 通过link引入(避免了加载js的阻塞)"css-loader", // 将css资源编译成commonjs模块到js中// sass兼容处理// 需要在package 添加需要兼容到哪些浏览器// "browserslist": [// "last 2 version", // 所有的浏览器取最新的两个版本// "> 1%", // 覆盖99% 的浏览器// "not dead"// ]{loader: 'postcss-loader',options: {postcssOptions: {plugins: [['postcss-preset-env',{// 其他选项},],],},},},"sass-loader" // 将sass编译成css],},// 处理图片资源{// webpack5内置了处理图片的loadertest: /\.(png|jpe?g|gif|webp|svg)$/,type: 'asset',parser: {dataUrlCondition: {// 将小于10kb的图片打包成base64// 优点: 较少请求数量// 缺点: 图片体积变大(所以一般都转的小体积的图片)maxSize: 10 * 1024 // 10kb}},// 图片打包后的目录// generator: {// // hash:10 取hash前10个字符// filename: 'static/images/[hash:10][ext][query]'// }},// 处理其他资源{test: /\.(ttf|woff2?|mp3|mp4|avi)$/,type: 'asset/resource', // 原样打包到dist中// generator: {// // hash:10 取hash前10个字符// filename: 'static/media/[hash:10][ext][query]'// }},// 将高阶JS语法处理成IE等旧浏览器能识别的JS语法// babel-loader: 不能处理async、promise等ES+的语法 需要借助core-js// core-js 是专门做ES6以上API的polyfill(补丁)// 在babel.config.js// module.exports = {// // 智能预设: 能够编译ES6语法// presets: [// '@babel/preset-env',// {// useBuiltIns: 'usage', // 按需自动加载core-js对ES6+的兼容性处理// corejs: 3 // core-js的版本号// }// ]// }{test: /\.js$/,// 排除哪些不需要处理的文件exclude: /(node_modules|bower_components)/,// include: path.resolve(__dirname, "../src"),// 只加载一个loader 可以直接使用loader替换useuse: [{loader: "thread-loader",options: {workers: threads, // babel: 进程数量}},{loader: 'babel-loader',options: {// 可以直接在项目中 新建babel配置文件(babel.config.js), 方便配置扩展// presets: ['@babel/preset-env']cacheDirectory: true, // 开启babel缓存cacheCompression: false, // 关闭缓存文件压缩plugins: ["@babel/plugin-transform-runtime"] // 减少代码体积:避免不必要的babel的辅助代码注入}}]}]}},// 插件plugins: [// ESLint检验new ESLintPlugin({// eslint 只检测src下面的文件context: path.resolve(__dirname, '../src'),exclude: 'node_modules',threads}),// html文件自动引入依赖资源new HtmlWebpackPlugin({// 模板: 以public/index.html 文件作为模板,创建打包后新的html文件// 新的html文件特点:1、结构和打包之前的一致; 2、自动引入打包输出的资源template: path.resolve(__dirname, '../public/index.html')}),// 单独打包出css文件new MiniCssExtractPlugin({filename: 'static/css/[name].[contenthash:10].css',chunkFilename: 'static/css/[name].chunk.[contenthash:10].css'}),],optimization: {// 压缩的操作minimizer: [// css压缩// 开启生产模式 html、js会自动压缩的new CssMinimizerPlugin(),// 压缩jsnew TerserWebpackPlugin({// 开启多进程parallel: threads,}),],// 代码分割配置splitChunks: {chunks: 'all'},// 保证引用文件不变// 只变runtime和map里面的文件runtimeChunk: {name: (entrypoint) => `runtime-${entrypoint.name}.js`}},// 开发服务器: 不会输出资源到dist中的, 是在内存中进行编译打包的// src下的代码更改后,自动打包/自动编译代码// 生产模式下不需要devServerdevServer: {host: '0.0.0.0',port: 3000,compress: true,// 默认为true: 提升开发模式的打包构建速度// 默认只支持css热更新 js的需要加载相应loaderhot: true, // 开启HRM 热更新},
}