webpack面试题
常用的loader
1、打包less、css
css-loader : 将css文件变成commonjs模块加载js中
style-loader :动态创建 style
标签,将 css
插入到 head
中.
less-loader :负责处理编译 .less
文件,将其转为 css
sass-loader:将SCSS/SASS代码转换成CSS
2、样式中的图片
file-loader :把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件 (处理图片和字体)
url-loader:资源大小小于 某值 时,将资源转换为 base64
,超过 某值 时,将图片拷贝到 dist
目录
3、html中的图片
html-loader
4、css兼容性处理
postcss-loader :自动生成浏览器兼容性前缀
postcss-preset-env
5、js语法检查
eslint-loader
eslint-config-airbnb-base
eslint-plugin-import
6、将JS代码向低版本转换
babel-loader
@babel/core
@babel/preset-env
7、 在一些性能开销较大的 loader
之前添加 cache-loader
,将结果缓存中磁盘中
cache-loader
cacheDirectory: true
8、同一时刻处理多个任务
happypack、thread-loader
9、映射会源文件的具体位置
source-map-loader
devtool: ‘cheap-module-eval-source-map’
常用的plugin
1、html文件
html-webpack-plugin:简化 HTML 文件创建 (依赖于 html-loader)
web-webpack-plugin:可方便地为单页应用输出 HTML,比 html-webpack-plugin 好用
2、自动打包运行
webpack-dev-server
3、提取css为单独文件
mini-css-extract-plugin
4、js兼容性处理
@babel/polyfill
5、清空打包目录
clean-webpack-plugin
7、将单个文件或整个目录复制到构建目录
copy-webpack-plugin
8、热模替换
HotModuleReplacementPlugin
9、定义环境变量
DefinePlugin
10、测量各个插件和loader
所花费的时间
speed-measure-webpack-plugin
11、开启 JS 多进程压缩
webpack-parallel-uglify-plugin
uglifyjs-webpack-plugin
12、为模块提供中间缓存
hard-source-webpack-plugin
13、忽略第三方包指定目录
IgnorePlugin
14、可视化 Webpack 输出文件的体积
webpack-bundle-analyzer
优化
webpack-dashboard:可以更友好的展示相关打包信息
webpack-merge:提取公共配置,减少重复配置代码
speed-measure-webpack-plugin:简称 SMP,分析出 Webpack 打包过程中 Loader 和 Plugin 的耗时,有助于找到构建过程中的性能瓶颈。
size-plugin:监控资源体积变化,尽早发现问题
HotModuleReplacementPlugin:模块热替换
-JS文件按需加载
-resolve.modules 配置 webpack 去哪些目录下寻找第三方模块
-通过 exclude、include 配置来确保转译尽可能少的文件
-在一些性能开销较大的 loader 之前添加 cache-loader,将结果缓存中磁盘中。
-thread-loader:同一时刻处理多个任务。把 thread-loader 放置在其它 loader 之前,那么放置在这个 loader 之后的 loader 就会在一个单独的 worker 池中运行
-HardSourceWebpackPlugin 为模块提供中间缓存
-IgnorePlugin:忽略第三方包指定目录
-externals:externals使用 CDN 的方式引入,剥离出webpack的打包,并且可以正常import,减少 Webpack打包出来的 js 体积
-DllPlugin:如果所有的JS文件都打成一个JS文件,会导致最终生成的JS文件很大,DllPlugin 和 DLLReferencePlugin 可以实现拆分 bundles,将一些不做修改的依赖文件,提前打包,可以大大提升构建速度
-tree-shaking:如果使用ES6的import 语法,那么在生产环境下,会自动移除没有使用到的代码。
-scope hosting:变量提升,可以减少一些变量声明。在生产环境下,默认开启。
-@babel/plugin-transform-runtime:
Loader和Plugin的区别
- Loader本质就是一个函数。因为 Webpack 只认识 JavaScript,loader是使webpack拥有加载和解析非js文件的能力
- plugin 可以扩展webpack的功能,使得webpack更加灵活。可以在构建的过程中通过webpack的api改变输出的结果
- Loader 在 module.rules 中配置,作为模块的解析规则,类型为数组。每一项都是一个 Object,内部包含了 test(类型文件)、loader、options (参数)等属性。
- Plugin 在 plugins 中单独配置,需要 require 该插件,类型为数组,每一项是一个 Plugin 的实例,参数都通过构造函数传入。
什么是webpack
1.本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包工具
2.当 webpack 处理应用程序时,它会在内部构建一个 依赖图(dependency graph),此依赖图会映射项目所需的每个模块,并生成一个或多个 bundle。
webpack的基本功能和工作原理
代码转换:TypeScript 编译成 JavaScript、SCSS 编译成 CSS 等等
文件优化:压缩 JavaScript、CSS、HTML 代码,压缩合并图片等
代码分割:提取多个页面的公共代码、提取首屏不需要执行部分的代码让其异步加载
模块合并:在采用模块化的项目有很多模块和文件,需要构建功能把模块分类合并成一个文件
自动刷新:监听本地源代码的变化,自动构建,刷新浏览器
代码校验:在代码被提交到仓库前需要检测代码是否符合规范,以及单元测试是否通过
自动发布:更新完代码后,自动构建出线上发布代码并传输给发布系统。
bundle,chunk,module
对于一份同逻辑的代码,当我们手写下一个一个的文件,它们无论是 ESM 还是 commonJS 或是 AMD,他们都是 module ;
当我们写的 module 源文件传到 webpack 进行打包时,webpack 会根据文件引用关系生成 chunk 文件,webpack 会对这个 chunk 文件进行一些操作;
webpack 处理好 chunk 文件后,最后会输出 bundle 文件,这个 bundle 文件包含了经过加载和编译的最终源文件,所以它可以直接在浏览器中运行。
hash、chunkhash、contenthash
通过webpack构建之后,生成对应文件名自动带上对应的MD5值
(1)hash整体打包内容的md5值
(2)chunkhash当前chunk内容的md5值
(3)contenthash当前bundle内容的md5值
用hash有什么问题?
如果都使用hash的话,因为这是工程级别的,即每次修改任何一个文件,所有文件名的hash至都将改变。所以一旦修改了任何一个文件,整个项目的文件缓存都将失效。
每个压缩后的文件的hash值是一样的,所以对于没有改变的模块而言,这样做显然不恰当,因为缓存失效了嘛。此时,chunkhash的用途随之而来。
用chunkhash有什么问题?
每个chunk模块的hash是不一样的
但是这样又有一个问题,因为我们是将样式作为模块import到JavaScript文件中的,所以它们的chunkhash是一致的,如test1.js和test1.css
contenthash是针对文件内容级别的,只有你自己模块的内容变了,那么hash值才改变
webpack构建过程
- 初始化:启动构建,读取与合并配置参数,加载 Plugin,实例化 Compiler
- 编译: 从入口文件出发,调用所有配置的 Loader 对模块进行编译,再找出该模块依赖的模块,递归地进行编译处理
- 输出:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,将 Chunk 转换成最终的bundle文件,写入bundle.js中
模块打包原理
将所有依赖打包成一个bundle.js,通过代码分割成单元片段按需加载。
热更新原理
首先对本地文件代码进行编译打包,也就是webpack的一系列编译流程。
其次编译结束后,开启对本地文件的监听,当文件发生变化,重新编译,编译完成之后继续监听。(监听本地文件的变化主要是通过文件的生成时间是否有变化)
当监听到一次webpack编译结束,server 端与浏览器之间维护了一个 Websocket,当本地资源发生变化时,server 端会向浏览器推送更新,并带上构建时的 hash,让客户端与上一次资源进行对比。客户端对比出差异后会向server 端发起 Ajax 请求来获取更改内容(文件列表、hash),获取到更新列表后,该模块再次通过 jsonp 请求,获取到最新的模块代码。HotModulePlugin在决定更新模块后,检查模块之间的依赖关系,更新模块的同时更新模块间的依赖引用。
当 HMP 失败后,进行浏览器刷新来获取最新打包代码。
首先是建立起浏览器端和服务器端之间的通信,浏览器会接收服务器端推送的消息,如果需要热更新,浏览器发起Ajax 请求去服务器端获取打包好的资源解析并局部刷新页面。
Babel原理
- 解析:使用babylon这个解析器,它会根据输入的javascript代码字符串根据ESTree规范生成AST(抽象语法树)。
- 转换:plugin用babel-traverse对AST树进行遍历转译,得到新的AST树
- 生成:用babel-generator通过AST树生成ES5代码
文件指纹
文件指纹是打包后输出的文件名的后缀。
Hash:和整个项目的构建相关,只要项目文件有修改,整个项目构建的 hash 值就会更改
Chunkhash:和 Webpack 打包的 chunk 有关,不同的 entry 会生出不同的 chunkhash
Contenthash:根据文件内容来定义 hash,文件内容不变,则 contenthash 不变
代码分割的本质是什么?有什么意义呢?
在最开始使用Webpack的时候, 都是将所有的js文件全部打包到一个build.js文件中(文件名取决与在webpack.config.js文件中output.filename), 但是在大型项目中, build.js可能过大, 导致页面加载时间过长. 这个时候就需要code splitting, code splitting就是将文件分割成块(chunk), 我们可以定义一些分割点(split point), 根据这些分割点对文件进行分块, 并实现按需加载。
entry,output
entry 入口,告诉webpack要使用哪个模块作为构建项目的起点,默认为./src/index.js
output 出口,告诉webpack在哪里输出它打包好的代码以及如何命名,默认为./dist
与gulp、grunt的区别
grunt和gulp是基于任务和流(Task、Stream)的。类似jQuery,找到一个(或一类)文件,对其做一系列链式操作,更新流上的数据, 整条链式操作构成了一个任务,多个任务就构成了整个web的构建流程。
webpack是基于入口的。webpack会自动地递归解析入口所需要加载的所有资源文件,然后用不同的Loader来处理不同的文件,用Plugin来扩展webpack功能。
npm打包时需要注意哪些?如何利用webpack来更好的构建?
完善基本信息;
定义依赖;
忽略文件;
打标签;
webpack规范
webpack默认遵循commonjs规范 module.exports
使用webpack进行打包时有两种模式:
开发模式:主要是用于测试,代码调试等;
生产模式:要考虑性能问题,要压缩 如果没有插件 就不会压缩;
默认情况下webpack的配置文件叫webpack.config.js,可以通过--config指定webpack的配置文件名
webpack4的新特性
1.mode
webpack增加了一个mode配置,只有两种值development | production。对不同的环境他会启用不同的配置。
2、optimization
webpack4删除了CommonsChunkPlugin(提取第三方库和公共模块)插件,它使用内置API optimization.splitChunks 和 optimization.runtimeChunk,这意味着webpack会默认为你生成共享的代码块。其它插件变化如下:
NoEmitOnErrorsPlugin (遇到错误代码将不会退出)废弃,使用optimization.noEmitOnErrors替代,在生产环境中默认开启该插件。
ModuleConcatenationPlugin (启用作用域提升)废弃,使用optimization.concatenateModules替代,在生产环境默认开启该插件。
NamedModulesPlugin (显示模块的相对路径)废弃,使用optimization.namedModules替代,在生产环境默认开启。
uglifyjs-webpack-plugin(缩小\压缩优化js文件)升级到了v1.0版本, 默认开启缓存和并行功能。
3、开箱即用WebAssembly
4.代码分割。
使用动态import,而不是用system.import或者require.ensure
5.vue-loader。
使用vue-loader插件为.vue文件中的各部分使用相对应的loader,比如css-loader等