谈谈你对Webpack的看法
1.Webpack是一个模块打包工具,可以使用它管理项目中的模块依赖,并编译输出模块所需的静态文件。
2.它可以很好地管理、打包开发中所用到的HTML,CSS,JavaScript和静态文件(图片,字体)等,让开发更高效。
3.对于不同类型的依赖,Webpack有对应的模块加载器,而且会分析模块间的依赖关系,最后合并生成优化的静态资源。
Webpack的基本功能有哪些?
1.代码转换:TypeScript编译成JavaScript、SCSS编译成CSS等等
2.文件优化:压缩JavaScript、CSS、HTML代码,压缩合并图片等
3.代码分割:提取多个页面的公共代码、提取首屏不需要执行部分的代码让其异步加载
4.模块合并:在采用模块化的项目有很多模块和文件,需要构建功能把模块分类合并成一个文件
5.自动刷新:监听本地源代码的变化,自动构建,刷新浏览器
6.代码校验:在代码被提交到仓库前需要检测代码是否符合规范,以及单元测试是否通过
7.自动发布:更新完代码后,自动构建出线上发布代码并传输给发布系统。
Webpack构建过程
1.从entry里配置的module开始递归解析entry依赖的所有module
2.每找到一个module,就会根据配置的loader去找对应的转换规则
3.对module进行转换后,再解析出当前module依赖的module
4.这些模块会以entry为单位分组,一个entry和其所有依赖的module被分到一个组Chunk
5.最后Webpack会把所有Chunk转换成文件输出在整个流程中Webpack会在恰当的时机执行plugin里定义的逻辑
有哪些常见的Loader?
1.file-loader:把文件输出到一个文件夹中,在代码中通过相对URL去引用输出的文件(处理图片和字体)
2.url-loader:与file-loader类似,区别是用户可以设置一个阈值,大于阈值会交给file-loader处理,小于阈值时返回文件base64形式编码(处理图片和字体)
3.css-loader:加载CSS,支持模块化、压缩、文件导入等特性
4.style-loader:把CSS代码注入到JavaScript中,通过DOM操作去加载CSS
5.json-loader:加载JSON文件(默认包含)
6.ts-loader:babel-loader:把ES6转换成ES5
7.ts-loader:将TypeScript转换成JavaScript
8.less-loader:将less代码转换成CSS
9.eslint-loader:通过ESLint检查JavaScript代码
10.vue-loader:加载Vue单文件组件
有哪些常见的Plugin?
1.html-webpack-plugin:根据模板页面生成打包的html页面
2.uglifyjs-webpack-plugin:不支持ES6压缩(Webpack4以前)
3.mini-css-extract-plugin:分离样式文件,CSS提取为独立文件,支持按需加载
4.clean-webpack-plugin:目录清理
5.copy-webpack-plugin:拷贝文件
6.webpack-bundle-analyzer:可视化Webpack输出文件的体积(业务组件、依赖第三方模块)
那你再说一说Loader和Plugin的区别?
1.Loader本质就是一个函数,在该函数中对接收到的内容进行转换,返回转换后的结果。因为Webpack只认识JavaScript,所以Loader就成了翻译官,对其他类型的资源进行转译的预处理工作。
2.Plugin就是插件,基于事件流框架Tapable,插件可以扩展Webpack的功能,在Webpack运行的生命周期中会广播出许多事件,Plugin可以监听这些事件,在合适的时机通过Webpack提供的API改变输出结果。
3.Loader在module.rules中配置,作为模块的解析规则,类型为数组。每一项都是一个Object,内部包含了test(类型文件)、loader、options(参数)等属性。
4.Plugin在plugins中单独配置,类型为数组,每一项是一个Plugin的实例,参数都通过构造函数传入。
说一下Webpack的热更新原理吧
Webpack的热更新又称热替换(HotModuleReplacement),缩写为HMR。这个机制可以做到不用刷新浏览器而将新变更的模块替换掉旧的模块。
HMR的核心就是客户端从服务端拉去更新后的文件,准确地说是chunkdiff(chunk需要更新的部分),实际上WDS与浏览器之间维护了一个Websocket,当本地资源发生变化时,WDS会向浏览器推送更新,并带上构建时的hash,让客户端与上一次资源进行对比。客户端对比出差异后会向WDS发起Ajax请求来获取更改内容(文件列表、hash),这样客户端就可以再借助这些信息继续向WDS发起jsonp请求获取该chunk的增量更新。
后续的部分(拿到增量更新之后如何处理?哪些状态该保留?哪些又需要更新?)由HotModulePlugin来完成,提供了相关API以供开发者针对自身场景进行处理,像react-hot-loader和vue-loader都是借助这些API实现HMR。
如何优化Webpack的构建速度?
1.使用高版本的Webpack和Node.js
2.压缩代码
1).通过uglifyjs-webpack-plugin压缩JS代码
2).通过mini-css-extract-plugin提取chunk中的CSS代码到单独文件,通过css-loader的minimize选项开启cssnano压缩CSS。
3.多线程/多进程构建:thread-loader,HappyPack
4.压缩图片:image-webpack-loader
5.缩小打包作用域
1).exclude/include(确定loader规则范围)
2).resolve.modules指明第三方模块的绝对路径(减少不必要的查找)
3).resolve.mainFields只采用main字段作为入口文件描述字段(减少搜索步骤,需要考虑到所有运行时依赖的第三方模块的入口文件描述字段)
4).resolve.extensions尽可能减少后缀尝试的可能性
5).noParse对完全不需要解析的库进行忽略(不去解析但仍会打包到bundle中,注意被忽略掉的文件里不应该包含import、require、define等模块化语句)
6).ignorePlugin(完全排除模块)
7).合理使用alias
6.提取页面公共资源,基础包分离
1).使用html-webpack-externals-plugin,将基础包通过CDN引入,不打入bundle中。
2).使用SplitChunksPlugin进行(公共脚本、基础包、页面公共文件)分离(Webpack4内置),替代了CommonsChunkPlugin插件。
7.充分利用缓存提升二次构建速度:
babel-loader开启缓存
terser-webpack-plugin开启缓存
使用cache-loader或者hard-source-webpack-plugin
8.Treeshaking
打包过程中检测工程中没有引用过的模块并进行标记,在资源压缩时将它们从最终的bundle中去掉(只能对ES6Modlue生效)开发中尽可能使用ES6Module的模块,提高treeshaking效率
禁用babel-loader的模块依赖解析,否则Webpack接收到的就都是转换过的CommonJS形式的模块,无法进行tree-shaking
使用PurifyCSS(不在维护)或者uncss去除无用CSS代码
purgecss-webpack-plugin和mini-css-extract-plugin配合使用(建议)
9.Scopehoisting
构建后的代码会存在大量闭包,造成体积增大,运行代码时创建的函数作用域变多,内存开销变大。Scopehoisting将所有模块的代码按照引用顺序放在一个函数作用域里,然后适当地重命名一些变量以防止变量名冲突。