一、Webpack基础
打包工具:将框架(React、Vue),ES6,Less/Sass等语法编译成浏览器能识别的JS、CSS;压缩代码、兼容性处理、提升代码性能等。
一、entry(入口)
指示Webpack 从哪个文件开始打包
二、output(输出)
指示Webpack打包完的文件输出到哪里去,如何命名等
三、loader(加载器)
webpack本身只能处理JS、JSON等资源,其他资源需要借助loader,webpack才能解析
四、plugins(插件)
扩展webpack的功能
五、mode(模式)
- 开发模式:development
- 编译代码,使浏览器能识别运行
- 代码质量检查,梳理代码规范
- 生产模式:production
- 优化代码运行性能
- 优化代码打包速度
javascript
//webpack.config.js
const path = require("path");// nodejs核心模块,专门用来处理路径问题
const ESLintWebpackPlugin = require('eslint-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizePlugin = require('css-minimize-plugin');
const TerserWebpackPlugin = require("terser-webpack-plugin");
const os = require("os");//nodejs核心模块,直接使用
const threads = os.cpus().length;//cpu核数
module.exports = {
//入口
entry:"./src/main.js",//相对路径
//输出
output:{
//所有文件的输出路径
//_dirname nodejs的变量,代表当前文件的文件夹目录
path:path.resolve(_dirname,"dist"),//绝对路径
//入口文件打包输出文件名
filename:"static/js/[main].js",
//给打包输出的其他文件命名
chunkFilename:"static/js/[name].chunk.js",
//图片、字体等通过type:asset处理资源命名方式
assetModuleFilename:"static/media/[hash:10][ext][query]",
// 自动清空上次打包内容 原理:在打包前,将path整个目录内容清空,再进行打包
clean: true,
},
//加载器
module:{
rules:[
//loader的配置
// css配置
{
test:/\.css$/, //只检测.css文件
use:[
//执行顺序:从右都左(从下到上)
//"style-loader",// 将js中的css通过创建style标签添加html文件中生效
MiniCssExtractPlugin.loader,// 提取css成单独文件
"css-loader",// 将css资源编译成commonjs的模块到js中
{
loader:"postcss-loader",
options:[
postcssOptions:{
plugins:[
"postcss-preset-env",//能解决大多数样式兼容性问题
],
},
],
},
]
},
// less配置
{
test:/\.less$/,
// loader:'xxx', //只能使用1个loader
use:[// 使用多个loader
//"style-loader",// 将js中的css通过创建style标签添加html文件中生效
MiniCssExtractPlugin.loader,// 提取css成单独文件
"css-loader",// 将css资源编译成commonjs的模块到js中
{
loader:"postcss-loader",
options:[
postcssOptions:{
plugins:[
"postcss-preset-env",//能解决大多数样式兼容性问题
],
},
],
},
"less-loader", // 将less编译成css文件
]
},
// Sass/Scss配置
{
test:/\.s[ac]ss$/,
use:[
//"style-loader",// 将js中的css通过创建style标签添加html文件中生效
MiniCssExtractPlugin.loader,// 提取css成单独文件
"css-loader",// 将css资源编译成commonjs的模块到js中
{
loader:"postcss-loader",
options:[
postcssOptions:{
plugins:[
"postcss-preset-env",//能解决大多数样式兼容性问题
],
},
],
},
"sass-loader", // 将sass编译成css文件
]
},
// 图片配置
{
test:/\.(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?|map3|map4|avi)$/,
type:"asset/resourse",
generator:{
//输出名称
//filename: "static/desia/[hash:10][ext][query]",
},
},
// babel配置
{
test:/\.js$/,
//exclude:/node_modules/, // 排除node_moudles下的文件,其他文件都处理
include:path.resolve(_dirname,"../src"),// 只处理src下的文件,其他文件不做处理
use:[
{
loader:"thread-loader",// 开启多进程
options:{
workers:threads, //进程数量
}
},
{
loader: "babel-loader",
options:{
// //智能预设
// presets: ["@babel/preset-env"],
cacheDirectoy:true,// 开启babel缓存
cacheCompression:false,// 关闭缓存文件压缩
plugins:["@babel/plugin-transform-runtime"],//减少代码体积
},
],
},
]
},
//插件
plugins:[
//ESLint的配置
new ESLintPlugin({
//检测哪些文件
context: path.resolve(_dirname,"src"),
exclude:"node_modules",// 默认值
cache:true,//开启缓存
cacheLocation:path.resolve(_dirname,"../mode_modules/.cache/eslintcache"),
threads, //开启多进程和进程数量
}),
new HtmlWebpackPlugin({
// 模板:以public/index.html文件创建新的html文件(自动引入打包输出的资源)
template:path.resolve(_dirname,"public/index.html"),
}),
new MiniCssExtractPlugin({
filename:"static/css/[main].css",
chunkFilename:"static/css/[name].chunk.css",
}),
//new CssMinimizePlugin(),
//new TerserWebpackPlugin({
// parallel:threads, //开启多进程和进程数量
//}),
],
optimization:{
//压缩的操作
minimizer:[
//压缩css
new CssMinimizePlugin(),
//压缩js
new TerserWebpackPlugin({
parallel:threads, //开启多进程和进程数量
}),
],
},
代码分割配置
splitChunks:{
chunks:"all",// 其他都用默认值
},
runtimeChunk:{
name:(entrypoint) => `runtime~${entrypoint.name}.js`,
},
//开发服务器:不会输出资源,在内存中编译打包的
devServer:{
host:"localhost",// 启动服务器域名
port:"3000",// 启动服务器端口号
open:true, //是否自动打开浏览器
hot:true, // 开启HMR(默认开启)
},
//模式
mode:"development",
};
Eslint :可组装的Javascript和JSX检查工具(检测js和jsx语法的工具,可配置各项功能)
文档:https://eslint.nodejs.cn/docs/latest/use/getting-started
Babel :JavaScript编译器。主要用于将ES6语法编写的代码转换为向后兼容的JavaScript语法,以便能够运行在当前和旧版本的浏览器或其他环境中
javascript
// package.json文件
"script":{
"dev":"webpack serve --config ./config/webpack.dev.js",//启动开发服务器,内存编译打包没有输出
"build":"webpack --config ./config/webpack.prod.js",//直接打包输出
}
生产环境:
**提取css成单独文件:**css打包到js文件中,当js文件加载时会创建一个style标签来生成样式,这样对网站的用户体验不好,会出现闪屏现象
解决:使用MiniCssExtractPlugin,提取css成单独文件,通过link标签加载
**样式兼容性处理:**postcss-loader
javascript
//package.json文件
"browserslist":[
//"ie >= 8",
"last 2 version",
"> 1%",
"not dead"
]
**css压缩:**CssMinimizePlugin
二、Webpack优化
1.提升开发体验
SourceMap(源代码映射):用来生成源代码与构建后的代码一一映射的文件的方案,帮助我们更快找到错误根源。
开发模式:cheap-module-source-map
优点:打包编译速度快,只包含行映射 缺点:没有列映射
javascript
// webpack.config.js
module.exports=[
mode:"development",
devtool:"cheap-module-source-map",
]
生产模式:source-map
优点:包含行、列映射 缺点:打包编译速度更慢
javascript
// webpack.config.js
module.exports=[
mode:"production",
devtool:"source-map",
]
2.提升打包构建速度
(1)HotModuleReplacement(HMR:热模块替换)
在程序运行中,替换、添加或删除某个模块代码,就只有这个模块代码需要重新打包编译,其他模块不变,这样打包速度更快,无需重新加载整个页面。(开发环境)
(2)OneOf
javascript
//加载器
module:{
rules:[
// loader的配置
{
//每个文件只能被其中一个loader配置处理
oneOf:[
......
],
},
],
},
(3)Babel、Eslint 对node_modules下的文件 include或exclude处理
(4)Cache:对Eslint检查和Babel编译结果进行缓存
每次打包时js文件都要经过Eslint检查和Babel编译,速度比较慢。可以缓存之前的Eslint检查和Babel编译结果,这样第二次打包时速度更快。(生产环境)
(5)多进程打包:开启电脑的多个进程同时干一件事,速度更快。注意:仅在特别耗时的操作中使用,因为每个进程启动就有大约600ms左右的开销。
javascript
//nodejs核心模块,直接使用
const os = require("os");
//cpu核数
const threads = os.cpus().length;
javascript
npm i thread-loader -D
3.减少代码体积
(1)Tree Shaking:用于移除JavaScript中的没有使用上的代码 注意:它依赖ES Module
webpack已经默认开启了这个功能,无需其他配置。
(2)减少babel生产文件的体积
Babel为编译的每个文件都插入了辅助代码,使代码体积过大。
Babel对一些公共方法使用了非常小的辅助代码,比如_extend。默认情况下会被添加到每一个需要它的文件中。可以将这些辅助代码作为一个独立模块,来避免重复引入。
@babel/plugin-transform-runtime:禁用了babel自动对每个文件的runtime注入,而是引入@babel/plugin-transform-runtime并且使所有辅助代码从这里引入
(3)压缩图片
本地项目静态图片需要压缩
image-minimizer-webpack-plugin:用来压缩图片的插件
4.优化代码运行性能
(1)代码分割Code Split:
1.分割文件:将打包生成的文件进行分割,生成多个js文件
2.按需加载:需要哪个文件就加载哪个文件
打包代码时会将所有的js文件打包到一个文件中,体积太大了,如果只需要渲染首页,就应该只加载首页的js文件,其他文件不应该加载。
需要将打包生成的文件进行代码分割,生成多个js文件,渲染哪个页面就只加载某个js文件,这样加载的资源就少,速度就更快。
javascript
document.getElementById("btn").onclick = function () {
// import动态导入:会将动态导入的文件代码分割(拆分成单独模块),在需要使用的时候自动加载
// /* webpackChunkName: "count" */ webpack魔法命名
import(/* webpackChunkName: "count" */ "./js/count")
.then((res) => {
console.log("模块加载成功", res.default(2,1));
})
.catch((err) => {
cosnole.log("模块加载失败", err);
});
}
(2)Preload和Profetch技术
Preload:告诉浏览器立即加载资源
Prefetch:告诉浏览器在空闲时才开始加载资源
共同点:都只会加载资源,并不执行;都有缓存
区别:preload加载优先级高,prefetch加载优先级低;preload只能加载当前页面需要使用的的资源,prefetch可以加载当前页面资源,也可以加载下一个页面需要使用的资源。
总结:当前页面优先级高的资源用preload加载;下一个页面需要使用的资源用prefetch加载
问题:兼容性较差(preload相对于prefetch兼容性好一点) https://caniuse.com/查看兼容性
(3)Core-js:解决JS兼容性问题,专门用来做ES6及以上API的polyfill(补丁)
polyfill:用社区上提供的一段代码,让我们在不兼容某些新特性的浏览器上,使用该新特性。
javascript
//babel.config.js
module.export = {
//智能预设,能够编译ES6语法
presets: [
"@babel/preset-env",
{
useBuiltIns:"usage",// 按需加载自动引入
corejs: 3,
},
],
},
(4)PWA(progressive web application):渐进式网络应用程序
可以提供类似于native app(原生应用程序)体验的web app技术,在离线(offline)时应用程序能够继续运行功能,内部通过service workers技术实现的。
https://www.webpackjs.com/guides/progressive-web-application/#registering-our-service-worker