目录
二、webpack 中 loader 的作用是什么,以及常用 loader 有哪些?
四、webpack 的 Loader 和 Plugin 的不同
六、使用 webpack 开发时,你用过哪些可以提高效率的插件?
十二、在实际工程中,配置文件上百行乃是常事,如何保证各个loader按照预想方式工作?
十四、你刚才也提到了代码分割,那代码分割的本质是什么?有什么意义呢?
一、对 webpack 的理解
1、什么是 webpack?
webpack 是目前比较常用的模块打包工具,它能够很好地管理与打包开发中所用到的HTML、 JavaScript 、CSS以及各种静态文件(图片、字体等)。使用 webpack 管理模块依赖,并编译输岀模块所需的静态文件,让开发过程更加高效。
对于不同类型的资源, webpack 有对应的模块加载器。它会分析模块间的依赖关系,最后生成优化且合并后的静态资源。
当 webpack 处理应用程序时,它会在内部构建一个依赖图,此依赖图对应映射到项目所需的每个模块(不再局限js
文件),然后形成资源列表,最终打包生成到指定的文件中。
webpack 做的事情,仅仅是分析出各种模块的依赖关系,然后形成资源列表,最终打包生成到指定的文件中。
2、webpack 的两大特色
① 代码切割( code splitting)
可以将代码切割成不同的块,实现按需加载,缩短了初始化时间;
② 使用 loader 处理各种类型的静态文件,并且支持串行操作 webpack 以 CommonJS 规范来书写代码,但对 AMD/CMD 的支持也很全面,方便对项目进行代码迁移。
webpack 具有 require.js和 browserify的功能,但也有很多自己的新特性:
(1)对 CommonJS、AMD、ES6的语法实现了兼容;
(2)对 JavaScript、CSS、图片等资源文件都支持打包;
(3)串联式模块加载器和插件机制,让其具有更好的灵活性和扩展性,例如提供对CoffeeScript、 EMAScript 6的支持;
(4)有独立的配置文件 webpack.config. js;
(5)可以将代码切割成不同的块,实现按需加载,缩短了初始化时间;
(6)支持 SourceUrls 和 SourceMaps,易于调试;
(7)具有强大的 Plugin接口,大多是内部插件,使用起来比较灵活
(8)使用异步I/O,并具有多级缓存,这使得 webpack 速度很快且在增量编译上更加快。
二、webpack 中 loader 的作用是什么,以及常用 loader 有哪些?
说说webpack中常见的Loader?解决了什么问题?- 题目详情 - 前端面试题宝典
1、loader 作用
① 实现对不同格式文件的处理,比如将 Scss 转换为CSS,或将 TypeScript 转化为Javascript;
② 可以编译文件,从而使其能够添加到依赖关系中。
loader是 webpack 最重要的部分之一。通过使用不同的 loader,我们能够调用外部的脚本或者工具,实现对不同格式文件的处理。loader 需要在 webpack.config.js 里单独用 module 进行配置。
更多背景介绍:
在 webpack 内部中,任何文件都是模块,不仅仅只是
js
文件。默认情况下,在遇到import
或者load
加载模块的时候,webpack
只支持对js
文件打包,像css
、sass
、png
等这些类型的文件的时候,webpack
则无能为力,这时候就需要配置对应的loader
进行文件内容的解析。在加载模块的时候,执行顺序如下:
当
webpack
碰到不识别的模块的时候,webpack
会在配置的中查找该文件解析规则。关于配置
loader
的方式有三种:
- 配置方式(推荐):在 webpack.config.js文件中指定 loader
- 内联方式:在每个 import 语句中显式指定 loader
- CLI 方式:在 shell 命令中指定它们
配置方式:
关于
loader
的配置,我们是写在module.rules
属性中,属性介绍如下:
rules
是一个数组的形式,因此我们可以配置很多个loader
每一个
loader
对应一个对象的形式,对象属性test
为匹配的规则,一般情况为正则表达式属性
use
针对匹配到文件类型,调用对应的loader
进行处理代码编写,如下形式:
module.exports = { module: { rules: [ { test: /\.css$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader', options: { modules: true } }, { loader: 'sass-loader' } ] } ] } };
从上述代码可以看到,在处理
css
模块的时候,use
属性中配置了三个loader
分别处理css
文件。因为
loader
支持链式调用,链中的每个loader
会处理之前已处理过的资源,最终变为js
代码。顺序为相反的顺序执行,即上述执行方式为sass-loader
、css-loader
、style-loader
同一个任务的
loader
可以同时挂载多个,处理顺序为:从右到左,从下往上除此之外,
loader
的特性还有如下:
- loader 可以是同步的,也可以是异步的
- loader 运行在 Node.js 中,并且能够执行任何操作
- 除了常见的通过
package.json
的main
来将一个 npm 模块导出为 loader,还可以在 module.rules 中使用loader
字段直接引用一个模块- 插件(plugin)可以为 loader 带来更多特性
- loader 能够产生额外的任意文件
可以通过 loader 的预处理函数,为 JavaScript 生态系统提供更多能力。用户现在可以更加灵活地引入细粒度逻辑,例如:压缩、打包、语言翻译和更多其他特性。
2、常用的 loader
css-loader:加载 CSS,支持模块化、压缩、文件导入等特性;
style-loader:将 解析后的 css, 用
style
标签挂载到页面的head
中;
如果只通过css-loader
加载文件,这时候页面代码设置的样式并没有生效。原因在于,css-loader
只是负责将.css
文件进行一个解析,而并不会将解析后的css
插入到页面中。如果我们希望再完成插入style
的操作,那么我们还需要另外一个loader
,就是style-loader
less-loader: 将 LESS 代码转换成CSS
sass-loader: 将 SCSS/SASS 代码转换成CSS
开发中,我们也常常会使用less
、sass
、stylus
预处理器编写css
样式,使开发效率提高,这里需要使用less-loader、sass-loader
postcss-loader: 扩展 CSS 语法,使用下一代 CSS,可以配合 autoprefixer 插件自动补齐 CSS3 前缀;
raw-loader: 在
webpack
中通过import
方式导入文件内容,该loader
并不是内置的;babel-loader:把 ES6 转换成 ES5;
eslint-loader:通过 ESLint 检查 JavaScript 代码;
html-minify-loader: 压缩HTML
image-loader:加载并且压缩图片文件;
file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件 (处理图片和字体);
url-loader:与 file-loader 类似,区别是用户可以设置一个阈值,大于阈值会交给file-loader处理,小于阈值时返回文件 base64 形式编码 (处理图片和字体);
source-map-loader:加载额外的 Source Map 文件,以方便断点调试
三、webpack中常见的Plugin?解决了什么问题?
说说webpack中常见的Plugin?解决了什么问题?- 题目详情 - 前端面试题宝典
1、plugin 的作用
Plugin
是一种计算机应用程序,它和主应用程序互相交互,以提供特定的功能。是一种遵循一定规范的应用程序接口编写出来的程序,只能运行在程序规定的系统下,因为其需要调用原纯净系统提供的函数库或者数据。
webpack
中的plugin
也是如此,plugin
赋予其各种灵活的功能,例如打包优化、资源管理、环境变量注入等,它们会运行在 webpack
的不同阶段(钩子 / 生命周期),贯穿了webpack
整个编译周期。
目的在于解决 loader
无法实现的其他事。
配置方式
这里讲述文件的配置方式,一般情况,通过配置文件导出对象中plugins
属性传入new
实例对象。如下所示:
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装
const webpack = require('webpack'); // 访问内置的插件
module.exports = {
...
plugins: [
new webpack.ProgressPlugin(),
new HtmlWebpackPlugin({ template: './src/index.html' }),
],
};
2、常见的 Plugin
html-webpack-plugin:简化 HTML 文件创建 (依赖于 html-loader);
在打包结束后,⾃动生成⼀个 html 文件,并把打包生成的 js 模块引⼊到该 html 中
mini-css-extract-plugin:分离样式文件,CSS 提取为独立文件,支持按需加载 (替代extract-text-webpack-plugin);
uglifyjs-webpack-plugin:不支持 ES6 压缩 (Webpack4 以前);
terser-webpack-plugin
: 支持压缩 ES6 (Webpack4);
webpack-bundle-analyzer:可视化 webpack 输出文件的体积;
optimize-css-plugin:压缩CSS;
copy-webpack-plugin:复制文件或目录到执行区域;
如 Vue 的打包过程中,如果我们将一些文件放到 public 的目录下,那么这个目录会被复制到 dist 文件夹中
define-plugin:定义环境变量;允许在编译时创建配置的全局对象; (Webpack4 之后指定 mode 会自动配置)
是一个webpack 内置的插件,不需要安装
webpack-parallel-uglify-plugin:多核压缩,提高压缩速度;
clean-webpack-plugin: 删除(清理)构建目录;
ignore-plugin
:忽略部分文件;
webpack-parallel-uglify-plugin
: 多进程执行代码压缩,提升构建速度
四、webpack 的 Loader 和 Plugin 的不同
Loader 直译为"加载器"。Webpack 将一切文件视为模块,但是 webpack 原生是只能解析 js 文件,如果想将其他文件也打包的话,就会用到 loader
。 所以 Loader 的作用是让 webpack 拥有了加载和解析非JavaScript文件 的能力。
Plugin 直译为"插件"。Plugin 可以扩展 webpack 的功能,让 webpack 具有更多的灵活性。 在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
不同的用法:
Loader 在 module.rules
中配置,也就是说他作为模块的解析规则而存在。
类型为数组,每一项都是一个
Object
,里面描述了对于什么类型的文件(test
),使用什么加载(loader
) 和使用的参数(options
)
Plugin 在 plugins
中单独配置。
类型为数组,每一项是一个
plugin
的实例,参数都通过构造函数传入。
五、Webpack 构建流程简单说一下
Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:
初始化参数
:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数开始编译
:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译确定入口
:根据配置中的 entry 找出所有的入口文件编译模块
:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理完成模块编译
:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系输出资源
:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会输出完成
:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统
在以上过程中,Webpack
会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果。
简单说
- 初始化:启动构建,读取与合并配置参数,加载 Plugin,实例化 Compiler
- 编译:从 Entry 出发,针对每个 Module 串行调用对应的 Loader 去翻译文件的内容,再找到该 Module 依赖的 Module,递归地进行编译处理
- 输出:将编译后的 Module 组合成 Chunk,将 Chunk 转换成文件,输出到文件系统中
六、使用 webpack 开发时,你用过哪些可以提高效率的插件?
webpack-dashboard
:可以更友好的展示相关打包信息。webpack-merge
:提取公共配置,减少重复配置代码speed-measure-webpack-plugin
:简称 SMP,分析出 Webpack 打包过程中 Loader 和 Plugin 的耗时,有助于找到构建过程中的性能瓶颈。size-plugin
:监控资源体积变化,尽早发现问题HotModuleReplacementPlugin
:模块热替换
七、source map是什么?生产环境怎么用?
source map
是将编译、打包、压缩后的代码映射回源代码的过程。打包压缩后的代码不具备良好的可读性,想要调试源码就需要 soucre map。
map文件只要不打开开发者工具,浏览器是不会加载的。
线上环境一般有三种处理方案:
hidden-source-map
:借助第三方错误监控平台 Sentry 使用nosources-source-map
:只会显示具体行数以及查看源代码的错误栈。安全性比 sourcemap 高sourcemap
:通过 nginx 设置将 .map 文件只对白名单开放(公司内网)
注意:避免在生产中使用 inline-
和 eval-
,因为它们会增加 bundle 体积大小,并降低整体性能。
八、模块打包原理知道吗?
Webpack 实际上为每个模块创造了一个可以导出和导入的环境,本质上并没有修改代码的执行逻辑,代码执行顺序与模块加载顺序也完全一致。
九、文件监听原理呢?
在发现源码发生变化时,自动重新构建出新的输出文件。
Webpack开启监听模式,有两种方式:
- 启动 webpack 命令时,带上 --watch 参数
- 在配置 webpack.config.js 中设置 watch:true
缺点:每次需要手动刷新浏览器
原理:轮询判断文件的最后编辑时间是否变化,如果某个文件发生了变化,并不会立刻告诉监听者,而是先缓存起来,等 aggregateTimeout
后再执行。
module.export = {
// 默认false,也就是不开启
watch: true,
// 只有开启监听模式时,watchOptions才有意义
watchOptions: {
// 默认为空,不监听的文件或者文件夹,支持正则匹配
ignored: /node_modules/,
// 监听到变化发生后会等300ms再去执行,默认300ms
aggregateTimeout:300,
// 判断文件是否发生变化是通过不停询问系统指定文件有没有变化实现的,默认每秒问1000次
poll:1000
}
}
十、说一下 Webpack 的热更新原理
Webpack
的热更新又称热替换(Hot Module Replacement
),缩写为 HMR
。 这个机制可以做到不用刷新浏览器而将新变更的模块替换掉旧的模块。
HMR的核心就是客户端从服务端拉去更新后的文件,准确的说是 chunk diff (chunk 需要更新的部分),实际上 WDS 与浏览器之间维护了一个 Websocket
,当本地资源发生变化时,WDS 会向浏览器推送更新,并带上构建时的 hash,让客户端与上一次资源进行对比。客户端对比出差异后会向 WDS 发起 Ajax
请求来获取更改内容(文件列表、hash),这样客户端就可以再借助这些信息继续向 WDS 发起 jsonp
请求获取该chunk的增量更新。
后续的部分(拿到增量更新之后如何处理?哪些状态该保留?哪些又需要更新?)由 HotModulePlugin
来完成,提供了相关 API 以供开发者针对自身场景进行处理,像react-hot-loader
和 vue-loader
都是借助这些 API 实现 HMR。
十一、如何对 bundle 体积进行监控和分析?
VSCode
中有一个插件 Import Cost
可以帮助我们对引入模块的大小进行实时监测,还可以使用 webpack-bundle-analyzer
生成 bundle
的模块组成图,显示所占体积。
bundlesize
工具包可以进行自动化资源体积监控。
十二、在实际工程中,配置文件上百行乃是常事,如何保证各个loader按照预想方式工作?
可以使用 enforce
强制执行 loader
的作用顺序,pre
代表在所有正常 loader 之前执行,post
是所有 loader 之后执行。(inline 官方不推荐使用)
十三、如何优化 Webpack 的构建速度?
说说如何借助webpack来优化前端性能?_小草莓蹦蹦跳的博客-CSDN博客
十四、你刚才也提到了代码分割,那代码分割的本质是什么?有什么意义呢?
代码分割的本质其实就是在源代码直接上线
和打包成唯一脚本main.bundle.js
这两种极端方案之间的一种更适合实际场景的中间状态。
用可接受的服务器性能压力增加来换取更好的用户体验。
源代码直接上线:虽然过程可控,但是http请求多,性能开销大。
打包成唯一脚本:一把梭完自己爽,服务器压力小,但是页面空白期长,用户体验不好。
(Easy peezy right)
十五、webpack解决的问题
① 模块化的方式开发代码;
② 使用一些高级的特性来加快我们的开发效率或者安全性;
比如通过ES6+、TypeScript开发脚本逻辑,通过sass、less等方式来编写css样式代码
③ 监听文件的变化来并且反映到浏览器上,提高开发的效率;
④ 模块化JavaScript 、HTML 和 CSS等资源;
⑤ 将代码进行压缩、合并以及其他相关的优化;
十六、webpack的能力
① 编译代码能力,提高效率,解决浏览器兼容问题
② 模块整合能力,提高性能,可维护性,解决浏览器频繁请求文件的问题
③ 万物皆可模块能力,项目维护性增强,支持不同种类的前端模块类型,统一的模块化方案,所有资源文件的加载都可以通过代码控制