1、Webpack中loader的作用/ loader是什么?
Loader 是webpack中提供了一种处理多种文件格式的机制,因为webpack只认识JS和JSON,所以Loader相当于翻译官,将其他类型资源进行预处理。
loader文件加载器,能够加载资源文件,并对这些文件进行一些处理,诸如编译压缩等
处理一个文件可以使用多个loader,loader的执行顺序和配置中的顺序是相反的,即最后一个先执行
常见的loader有哪些?
- less-loader:将less文件编译成css文件
- css-loader:将css文件变成commonjs模块加载到js中,模块内容是样式字符串
- style-loader: 创建style标签,将js中的样式资源插入标签内,并将标签添加到head中生效
- ts-loader: 打包编译Typescript文件
2、Plugin有什么作用?/Plugin是什么
Plugin功能更强大,主要目的就是解决loader 无法实现的事情,比如打包优化和代码压缩等。
Plugin加载后,在webpack构建的某个时间节点就会触发plugin定义的功能,帮助webpack做一些事情。实现对webpack的功能扩展。
常见的Plugin有哪些
- html-webpack-plugin :处理html资源,默认会创建一个空的HTML,自动引入打包输出的所有资源(js/css)
- mini-css-extract-plugin: 打包过后的css在js文件里,该插件可以把css单独抽出来
- clean-webpack-plugin :每次打包时候,CleanWebpackPlugin 插件就会自动把上一次打的包删除
3、Webpack中Loader和Plugin的区别
- loader运行在编译阶段,是一个转换器,将a文件进行编译形成b文件,操作的是文件,例如a.less转为a.css
- plugins 在整个周期都起作用,针对loader结束后,webpack打包的整个过程,它并不直接操作文件,而是基于事件机制工作,监听webpack打包过程中的某些点,执行广泛的任务
4、Webpack 做过哪些优化手段?有哪些优化手段?
如何利用webpack来优化前端性能? 问的是生产环境优化
如何提高webpack的构建速度? 问的是构建速度的优化
5、如何利用webpack来优化前端性能?
-
JS代码压缩
-
CSS代码压缩
-
HTML文件压缩
-
文件大小压缩
-
图片压缩
-
Tree Shaking
-
代码分离
-
Dll进行分包
JS代码压缩:
- uglifyjs-webpack-plugin:webpack4以上已经内置了js的压缩插件uglifyjs-webpack-plugin,如要修改插件的配置还是要下载之后再修改,默认打包之后已压缩js代码。
- terser-webpack-plugin:webpack5及以上已经内置了js的压缩插件terser-webpack-plugin,如要修改插件的配置还是要下载之后再修改,默认打包之后已压缩js代码。
-
const TerserPlugin = require('terser-webpack-plugin') module.exports = { ... optimization: { minimize: true, minimizer: [ new TerserPlugin({ parallel: true // 电脑cpu核数-1 }) ] } }
CSS代码压缩:
- 使用optimize-css-assets-webpack-plugin,同时使用cssnano
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
module.exports = {
plugins:[
new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.css$/g,
cssProcessor: require('cssnano')
})
]
}
HTML文件压缩
- 使用html-webpcak-plugin
module.exports = {
...
plugin:[
new HtmlwebpackPlugin({
...
minify:{
minifyCSS:false, // 是否压缩css
collapseWhitespace:false, // 是否折叠空格
removeComments:true // 是否移除注释
}
})
]
}
文件压缩:对文件的大小进行压缩,减少http传输过程中宽带的损耗。
// npm install compression-webpack-plugin -D
new ComepressionPlugin({
test:/\.(css|js)$/, // 哪些文件需要压缩
threshold:500, // 设置文件多大开始压缩
minRatio:0.7, // 至少压缩的比例
algorithm:"gzip", // 采用的压缩算法
})
图片压缩:一般来说在打包之后,一些图片文件的大小是远远要比 js 或者 css 文件要来的大,所以图片压缩较为重要。
module: {
rules: [
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name]_[hash].[ext]',
outputPath: 'images/',
}
},
{
loader: 'image-webpack-loader',
options: {
// 压缩 jpeg 的配置
mozjpeg: {
progressive: true,
quality: 65
},
// 使用 imagemin**-optipng 压缩 png,enable: false 为关闭
optipng: {
enabled: false,
},
// 使用 imagemin-pngquant 压缩 png
pngquant: {
quality: '65-90',
speed: 4
},
// 压缩 gif 的配置
gifsicle: {
interlaced: false,
},
// 开启 webp,会把 jpg 和 png 图片压缩为 webp 格式
webp: {
quality: 75
}
}
}
]
},
]
}
Tree Shaking:在打包时移除掉javascript上下文中无用的代码,从而优化打包的结果
代码分离:splitChunksPlugin来实现,将代码分离到不同的bundle中,之后可以按需加载
Dll进行分包:DLLPlugin把所有的第三方库依赖打包到一个bundle的dll文件里面,
6、如何提高webpack的构建速度?
思路1:减少需要构建的文件或代码
- HMR(Hot Module Replacement) 模块热替换只重新构建发生变化的模块 – 开发环境中
- 缩小处理范围:合理利用这两个属性exclude:不需要处理的文件 和 include:需要处理的文件
- babel缓存 第二次构建时,会读取之前的缓存,只重新构建变化的文件
- 使用Dll进行分包 --> 分包方便按需加载
思路2:多进程进行构建
- 多进程打包 thread-loader,将其放在费时的loader之前
缩小范围:在配置 loader 的时候,我们需要更精确的去指定 loader 的作用目录或者需要排除的目录,通过使用 include
和 exclude
两个配置项,可以实现这个功能
include
:符合条件的模块进行解析exclude
:排除符合条件的模块,不解析,优先级更高
noParse:对于我们引入的一些第三方包,比如jQuery
,在这些包内部是肯定不会依赖别的包,所以根本不需要webpack去解析它内部的依赖关系,使用 noParse 进行忽略的模块文件中不会解析 import
、require
等语法
module:{
noParse:/jquery|lodash/
}
IgnorePlugin:有很多的第三方包内部会做国际化处理,包含很多的语言包,而这些语言包对我们来说时没有多大用处的,只会增大包的体积,我们完全可以忽略掉这些语言包,从而提高构建效率,减小包的体积。
requestRegExp
表示要忽略的路径。contextRegExp
表示要忽略的文件夹目录。-
new webpack.IgnorePlugin({ resourceRegExp, contextRegExp });
缓存:
webpack5新加了缓存项配置,具体如下
默认缓存路径在node_modules/.cache/webpack
// 缓存配置
cache: {
type: 'filesystem', // 开启持久化缓存
version: createEnvironmentHash(env.raw), // 参考react脚手架的配置 可以记录打包缓存的版本
cacheDirectory: path.appWebpackCache, // 缓存路径
store: 'pack',
// 构建依赖,如果有文件修改,则重新执行打包流程
buildDependencies: {
defaultWebpack: ['webpack/lib/'],
config: [__filename],
},
},
babel-loader 开启缓存
babel 在转译 js 过程中时间开销比价大,将 babel-loader 的执行结果缓存起来,重新打包的时候,直接读取缓存
缓存位置: node_modules/.cache/babel-loader
//支持转义ES6/ES7/JSX
{
test: /\.jsx?$/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/react'],
plugins: [
[
require('@babel/plugin-proposal-decorators'),
{ legacy: true },
],
],
cacheDirectory: true, // 启用缓存
},
},
],
include: path.resolve(__dirname, 'src'),
exclude: /node_modules/,
},
cache-loader
缓存一些性能开销比较大的 loader 的处理结果, 缓存位置:node_modules/.cache/cache-loader
const config = {
module: {
// ...
rules: [
{
test: /.(s[ac]|c)ss$/i, //匹配所有的 sass/scss/css 文件
use: [
// 'style-loader',
MiniCssExtractPlugin.loader,
'cache-loader', // 获取前面 loader 转换的结果
'css-loader',
'postcss-loader',
'sass-loader',
]
},
// ...
]
}
}
注意:
dll动态链接(已弃用)
在 webpack5.x 中已经不建议使用这种方式进行模块缓存,因为其已经内置了更好体验的 cache 方法
hard-source-webpack-plugin
hard-source-webpack-plugin 为模块提供了中间缓存,重复构建时间大约可以减少 80%,但是在 webpack5 中已经内置了模块缓存,不需要再使用此插件
7、webpack5 和 webpack4 的区别有哪些 ?
- webpack5的 mode=“production” 自动开启 tree-shaking。
-
.webpack5内部本身就自带 js 压缩功能,他内置了 terser-webpack-plugin 插件,我们不用再下载安装。而且在 mode=“production” 的时候会自动开启 js 压缩功能。
-
webpack5 内部内置了 cache 缓存机制。直接配置即可
-
对loader的优化
8、css代码层优化
- 1、css压缩
- 2、css单一样式更好,例如margin-bottom:10px;margin-top:10px;
- 3、减少使用@import,建议使用link,link在页面加载时一起加载,@import等页面加载完成后再进行加载
- 4、减少使用标签选择器,而是用class
- 5、避免使用通配符选择器*{}
- 6、了解哪些属性是可以通过继承而来的,然后避免对这些属性重复使用
- 7、尽量减少页面的重排、重绘
- 8、公共样式抽离出来,整合并通过class在页面中使用
9、避免重绘回流
注意:触发回流定会触发重绘,重绘不一定引发回流
引起回流:
- 页面的首次渲染
- 浏览器窗口大小发生变化
- 元素内容发生变化
- 元素的尺寸或者位置发生变化
- 元素的字体大小发生变化
- 添加或者删除可见的DOM元素
- 激活css伪类
导致重绘:
- color/background相关属性background-color,background-image等属性
- outline相关属性outline-color,outline-width
- border-radius/visibility/box-shadow
减少回流与重绘:
- 尽量不使用table布局
- 不要频繁操作元素的样式,可以采用修改类名
- 使用absolute或者fixed,使元素脱离文档流
- 将元素设置display:none,操作结束再把它显示出来。因为在display属性为none的元素上进行DOM操作不会引起回流和重绘
9、防抖节流
https://liulibin.blog.youkuaiyun.com/article/details/115230182
10、图片优化
jpg/jpeg
优点:有损压缩、体积小、加载快、不支持透明
有损压缩:当我们把图片体积压缩至原有体积的50%以下时,JPG仍然可以保持住60%的品质
使用场景:
适用于呈现色彩丰富的图片,在我们日常开发中,JPG 图片经常作为大的背景图、轮播图或 Banner 图出现
png-8/png-24
优点:无损压缩、质量高、体积大、支持透明
PNG(可移植网络图形格式)是一种无损压缩的高保真的图片格式。8 和 24,这里都是二进制数的位数。按照我们前置知识里提到的对应关系,8 位的 PNG 最多支持 256 种颜色,而 24 位的可以呈现约 1600 万种颜色。
PNG 图片具有比 JPG 更强的色彩表现力,对线条的处理更加细腻,对透明度有良好的支持。它弥补了上文我们提到的 JPG 的局限性,唯一的 BUG 就是体积太大。
PNG-8 与 PNG-24 的选择题?
什么时候用 PNG-8,什么时候用 PNG-24,这是一个问题。
理论上来说,当你追求最佳的显示效果、并且不在意文件体积大小时,是推荐使用 PNG-24 的。
但实践当中,为了规避体积的问题,我们一般不用PNG去处理较复杂的图像。当我们遇到适合 PNG 的场景时,也会优先选择更为小巧的 PNG-8。
如何确定一张图片是该用 PNG-8 还是 PNG-24 去呈现呢?好的做法是把图片先按照这两种格式分别输出,看 PNG-8 输出的结果是否会带来肉眼可见的质量损耗,并且确认这种损耗是否在我们(尤其是你的 UI 设计师)可接受的范围内,基于对比的结果去做判断。
使用场景:
前面我们提到,复杂的、色彩层次丰富的图片,用 PNG 来处理的话,成本会比较高,我们一般会交给 JPG 去存储。
考虑到 PNG 在处理线条和颜色对比度方面的优势,我们主要用它来呈现小的 Logo、颜色简单且对比强烈的图片或背景等。
此时我们再次把目光转向性能方面堪称业界楷模的淘宝首页,我们会发现它页面上的 Logo,无论大小,还真的都是 PNG 格式
svg矢量图(iconfont)
优点:文本文件、体积小、不失真、兼容性好
最经典的小图标解决方案——雪碧图(CSS Sprites)
webp
优点:支持有损压缩和无损压缩
WebP 像 JPEG 一样对细节丰富的图片信手拈来,像 PNG 一样支持透明,像 GIF 一样可以显示动态图片——它集多种图片文件格式的优点于一身。
WebP 的官方介绍对这一点有着更权威的阐述:
与 PNG 相比,WebP 无损图像的尺寸缩小了 26%。在等效的 SSIM 质量指数下,WebP 有损图像比同类 JPEG 图像小 25-34%。 无损 WebP 支持透明度(也称为 alpha 通道),仅需 22% 的额外字节。对于有损 RGB 压缩可接受的情况,有损 WebP 也支持透明度,与 PNG 相比,通常提供 3 倍的文件大小。
我们开篇提到,图片优化是质量与性能的博弈,从这个角度看,WebP 无疑是真正的赢家。
缺点:兼容性差,兼容主流浏览器,谷歌兼容最好
11、懒加载和预加载的区别
懒加载:也叫延迟加载,用户需要访问时再加载
预加载:将所需的资源提前请求加载到本地,这样以后直接从缓存里面读取资源
12、babel的原理是什么?
- 解析Parse:将代码解析生成抽象语法树ast,即词法分析和语法分析的过程
- 转换Transform:对于AST进行转换一系列操作,babel接受得到AST并通过babel-traverse对其进行遍历,在此过程中进行添加更新移除等操作
- 生产Generate:将转换的ast在转换为js代码,使用到的模块是babel-generator
13、webpack的构建流程?
1.初始化参数:从配置文件和shell语句中读取与合并参数,得出最终的参数
2.开始编译:从上一步得到的参数初始化Compiler对象,加载所有配置的插件,执行对象的run方法开始执行编译
3.确定入口:根据配置中的entry找出所有的入口文件
4.编译模块:从入口文件出发,调用所有配置的loader对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过本步骤的处理;
比如UglifyPlugin 会在 loader 转换递归完对结果使用 UglifyJs 压缩覆盖之前的结果。
5.输出资源:根据⼊⼝和模块之间的依赖关系,组装成⼀个个包含多个模块的Chunk,再把每个 Chunk 转换成⼀个单独的⽂件加⼊到输出列表,这步是可以修改输出内容的最后机会;
6。输出完成:在确定好输出内容后,根据配置确定输出的路径和⽂件名,把⽂件内容写⼊到⽂件系统。
14、热更新原理
- 监听文件变化
- 服务器与客户端通信
- 替换过程
- 降级操作
监听文件变化
webpack监听文件变化主要是通过webpack-dev-middleware这个库来完成,它负责本地文件的编译、输出和监听,
webpack-dev-middleware中执行了compiler.watch方法,它主要做了两件事情
- 对本地文件编译打包
- 编译结束之后,开启监听,文件发生变化时重新编译,并持续进行监听
每次代码修改后,保存都会在控制台出现compiling…字样,可以在控制台中观察到:
如果没有任何改动,直接保存,控制台输出编译打包信息,Hash 值没有发生变化,仍旧是 4f8c0eff7ac051c13277。
通过webpack-dev-server的依赖,在浏览器和服务端直接建立一个websocket长连接,将webpack编译打包的各个阶段的状态信息告知浏览器,浏览器根据这些信息进行不同的操作。服务端传递的最主要的信息是hash值。