webpack篇
前言
为什么要使用打包工具
随着前端工程抽象复杂度的提高,前端开发框架盛行,前端项目代码抽象度提高,原始浏览器兼容版本(提供的web api)可能不支持新的语法,如ES6、less、甚至框架语法-vue、react语法等,具备编译转化功能的工程打包工具应运而生,webpack为杰出代表。
打包工具能实现哪些功能
压缩代码、兼容处理、编译转换提升代码性能,且一些适配型打包工具,往往还提供插件,用于作用在打包编译的过程中,让打包过程更可控。
常见打包工具
gulp blog.csdn.net/weixin_5809…
rollup
webpack
三者优缺点分析: www.jianshu.com/p/cea946fa3…
概括为webpack应用最为广泛,适配性强,意味着专用的便利性差。因此其他如gulp、rollup
webpack 基本使用
编译打包之前源代码为.vue、.less、es6等高版本语言,以一个或多个文件作为打包入口,将项目所有文件编译处理为一个或者多个文件
Webpack 是基于 Node.js 运行的,所以采用 Common.js 模块化规范
webpack官网:https://webpack.docschina.org/
五大核心配置
webpack.config.js配置文件
module.exports = {
// 入口
entry: "",
// 输出
output: {},
// 加载器
module: {
rules: [],
},
// 插件
plugins: [],
// 模式
mode: "",
};
资源处理:处理css资源(.less/.sass)、处理js(es6)、处理图片资源(png/jpg)、处理其他资源(.ttf/.swf)、处理框架资源(.vue)
// 封装通用样式loader函数
const getStyleLoaders = (pre) => {
return [
isProduction ? MiniCssExtractPlugin.loader : "vue-style-loader",
"css-loader",
{
// 处理css兼容性问题
// 配合package.json中browserslist来指定兼容性
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: ["postcss-preset-env"],
},
},
},
pre && {
loader: pre,
options:
pre === "sass-loader"
? {
additionalData: `@use "@/styles/element/index.scss" as *;`,
}
: {},
},
].filter(Boolean);
};
module: {
rules: [
// 处理css
{
test: /\.css$/,
use: getStyleLoaders(),
},
{
test: /\.less$/,
use: getStyleLoaders("less-loader"),
},
{
test: /\.s[ac]ss$/,
use: getStyleLoaders("sass-loader"),
},
{
test: /\.styl$/,
use: getStyleLoaders("stylus-loader"),
},
// 处理图片
{
test: /\.(jpe?g|png|gif|webp|svg)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024,
},
},
},
// 处理其他资源
{
test: /\.(woff2?|ttf)$/,
type: "asset/resource",
},
// 处理js
{
test: /\.js$/,
include: path.resolve(__dirname, "../src"),
loader: "babel-loader",
options: {
cacheDirectory: true,
cacheCompression: false,
},
},
{
test: /\.vue$/,
loader: "vue-loader",
options: {
// 开启缓存
cacheDirectory: path.resolve(__dirname, "../node_modules/.cache/vue-loader"),
},
},
],
},
总结 loader使用
设置include、exclude,对处理文件进行筛选,用于特异化处理,并不是每个文件都需要处理(如node_module中的文件不需要处理)
test适配文件类型
loader为指定load名称,需要先下载,如sass-loader(npm install sass-loader sass webpack --save-dev)依赖要下全,具体参考官网
type非代码的资源文件指定类型
include、exclude指定处理包含哪些文件不包含哪些,结果接受参数为Object、Array、Function
sourceMap,指定当报错时报错到源文件位置,便于开发时定位问题
additionData,对处理文件添加内容,如公共变量等
options(重要) loader的配置
如sassLoader:
{
loader: 'sass-loader',
options: {
sassOptions: (loaderContext) => {
// 有关可用属性的更多信息 https://webpack.js.org/api/loaders/
const { resourcePath, rootContext } = loaderContext;
const relativePath = path.relative(rootContext, resourcePath);
if (relativePath === 'styles/foo.scss') {
return {
includePaths: ['absolute/path/c', 'absolute/path/d'],
};
}
return {
includePaths: ['absolute/path/a', 'absolute/path/b'],
};
},
},
},
常用loader对应常用文件类型css(css-loader/style-loader/less-loader/postcss-loader)、js(babel-loader/ts-loader)、其他资源
总结 plugin使用
常用plugin:HtmlWebpackPlugin,ESLintWebpackPlugin,
// plugin的配置
new ESLintPlugin({
// 检测哪些文件
context: path.resolve(__dirname, "../src"),
exclude: "node_modules", // 默认值
cache: true, // 开启缓存
cacheLocation: path.resolve(
__dirname,
"../node_modules/.cache/eslintcache"
),
threads, // 开启多进程和设置进程数量
}),
css样式处理
提取为单独css文件
默认只使用css的loader,则css被打包到js文件中,这样js文件加载时,会创建style标签,导致页面闪屏。通过link引入css样式文件可以解决这个问题。 就需要用到 const MiniCssExtractPlugin = require("mini-css-extract-plugin"); 并采用loader的形式引入:
{
test: /\.s[ac]ss$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
},
css兼容处理
使用postcss,配合browserlist(指定兼容浏览器版本)
package.json :"browserslist": ["last 2 version", "> 1%", "not dead"]
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env", // 能解决大多数样式兼容性问题
],
},
},
},
css压缩
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
// css压缩
new CssMinimizerPlugin(),
开发模式与生产模式
开发环境常用于编译页面,修改自动更新,需考虑缓存,热更新;生产模式考虑代码运行性能,打包速度,需考虑压缩。
开发模式
启动服务,更新页面
devServer: { host: "localhost", // 启动服务器域名 port: "3000", // 启动服务器端口号 open: true, // 是否自动打开浏览器 },
一些常用配置文件
.eslintrc.js eslint配置,用于代码规范,可以继承vue、react官方的模版;另外的优化点,按需引入用到的如Promise .postcssrc.js 设置css版本兼容,可以直接在package.json或者webpack.config.js中设置 .babel.config.js babel配置
优化处理
提升开发体验
devtool: "cheap-module-source-map", // 配置在浏览器控制台,看到console的行 devtool: "source-map", // 配置在浏览器控制台,看到console的行和列,但编译打包速度慢
提升打包构建速度
热模替换HMR
修改个别模块就编译整个项目,效率低,只编译修改的模块将大大提升效率
module.exports = {
// 其他省略
devServer: {
host: "localhost", // 启动服务器域名
port: "3000", // 启动服务器端口号
open: true, // 是否自动打开浏览器
hot: true, // 开启HMR功能(只能用于开发环境,生产环境不需要了)
},
};
原生js热模替换需配置之后,再判断该模块是否支持 if(module.hot)比较麻烦
实际项目中vue-loader、react-hot-loader已经做了
loader精准匹配OneOf
设置匹配到文件类型之后就不进行别的loader查找
new ESLintWebpackPlugin({
// 指定检查文件的根目录
context: path.resolve(__dirname, "../src"),
// exclude: /node_modules/, // 默认值,排除node_modules代码不编译
include: path.resolve(__dirname, "../src"), // 也可以用包含
}),
cache缓存
每次打包编译文件都要经过eslint检查和babel编译,可以缓存cache结果
{
test: /\.js$/,
// exclude: /node_modules/, // 排除node_modules代码不编译
include: path.resolve(__dirname, "../src"), // 也可以用包含
loader: "babel-loader",
options: {
cacheDirectory: true, // 开启babel编译缓存
cacheCompression: false, // 缓存文件不要压缩
},
},
new ESLintWebpackPlugin({
// 指定检查文件的根目录
context: path.resolve(__dirname, "../src"),
exclude: "node_modules", // 默认值
cache: true, // 开启缓存
// 缓存目录
cacheLocation: path.resolve(
__dirname,
"../node_modules/.cache/.eslintcache"
),
}),
开启多进程
继续提升打包速度,其实就是要提升 js 的打包速度,因为其他文件都比较少。
而对 js 文件处理主要就是 eslint 、babel、Terser 三个工具,所以我们要提升它们的运行速度。
npm i thread-loader -D
const threads = os.cpus().length;
在特定loader或plugin中设置开启多线程
{
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编译缓存
},
},
],
},
new ESLintWebpackPlugin({
// 指定检查文件的根目录
context: path.resolve(__dirname, "../src"),
exclude: "node_modules", // 默认值
threads, // 开启多进程
}),
减少代码体积
tree shaking
移除没有用到的js代码,webpack默认开启
babel
babel默认为编译的文件都写入辅助代码,导致代码体积较大
{ loader: "babel-loader", options: { cacheDirectory: true, // 开启babel编译缓存 cacheCompression: false, // 缓存文件不要压缩 plugins: ["@babel/plugin-transform-runtime"], // 减少代码体积 }, }
Image Minimizer
静态图片压缩
优化代码运行性能
代码分割
针对所有js打包到一个文件的情况,导致首屏加载过慢,将代码分包打包,则分化首次加载压力,包含功能:文件分割,按需加载
预加载
代码分割,同时会使用 import 动态导入语法来进行代码按需加载(我们也叫懒加载,比如路由懒加载就是这样实现的)。
但是加载速度还不够好,比如:是用户点击按钮时才加载这个资源的,如果资源体积很大,那么用户会感觉到明显卡顿效果。
我们想在浏览器空闲时间,加载后续需要使用的资源。我们就需要用上 Preload 或 Prefetch 技术。
网络缓存
对静态资源会使用缓存来优化,这样浏览器第二次请求资源就能读取缓存了,速度很快。
core-js
过去我们使用 babel 对 js 代码进行了兼容性处理,其中使用@babel/preset-env 智能预设来处理兼容性问题。
它能将 ES6 的一些语法进行编译转换,比如箭头函数、点点点运算符等。但是如果是 async 函数、promise 对象、数组的一些方法(includes)等,它没办法处理。
所以此时我们 js 代码仍然存在兼容性问题,一旦遇到低版本浏览器会直接报错。
PWA
开发 Web App 项目,项目一旦处于网络离线情况,就没法访问了。
我们希望给项目提供离线体验。