【呕心沥血】webpack春招面试高频考点汇总及真题汇总
webpack面试题
webpack
谈谈你对webpack的看法
webpack是一个模块打包工具,可以使用它管理项目中的模块依赖,并编译输出模块所需的静态文件。它可以很好地管理、打包开发中所用到的HTML,CSS,JavaScript和静态文件(图片,字体)等,让开发更高效。对于不同类型的依赖,webpack有对应的模块加载器,而且会分析模块间的依赖关系,最后合并生成优化的静态资源。
webpack的基本功能和工作原理?
- 代码转换:TypeScript 编译成 JavaScript、SCSS 编译成 CSS 等等
- 文件优化:压缩 JavaScript、CSS、HTML 代码,压缩合并图片等
- 代码分割:提取多个页面的公共代码、提取首屏不需要执行部分的代码让其异步加载
- 模块合并:在采用模块化的项目有很多模块和文件,需要构建功能把模块分类合并成一个文件
- 自动刷新:监听本地源代码的变化,自动构建,刷新浏览器
- 代码校验:在代码被提交到仓库前需要检测代码是否符合规范,以及单元测试是否通过
- 自动发布:更新完代码后,自动构建出线上发布代码并传输给发布系统。
webpack构建过程
- 从entry里配置的module开始递归解析entry依赖的所有module
- 每找到一个module,就会根据配置的loader去找对应的转换规则
- 对module进行转换后,再解析出当前module依赖的module
- 这些模块会以entry为单位分组,一个entry和其所有依赖的module被分到一个组Chunk
- 最后webpack会把所有Chunk转换成文件输出
- 在整个流程中webpack会在恰当的时机执行plugin里定义的逻辑
webpack打包原理
将所有依赖打包成一个bundle.js,通过代码分割成单元片段按需加载
什么是webpack,与gulp,grunt有什么区别
- webpack是一个模块打包工具,可以递归地打包项目中的所有模块,最终生成几个打包后的文件。
- 区别:webpack支持代码分割,模块化(AMD,CommonJ,ES2015),全局分析
什么是entry,output?
- entry 入口,告诉webpack要使用哪个模块作为构建项目的起点,默认为./src/index.js
- output 出口,告诉webpack在哪里输出它打包好的代码以及如何命名,默认为./dist
什么是loader,plugins?
- loader是用来告诉webpack如何转换某一类型的文件,并且引入到打包出的文件中。
- plugins(插件)作用更大,可以打包优化,资源管理和注入环境变量
什么是bundle,chunk,module?
bundle是webpack打包出来的文件,chunk是webpack在进行模块的依赖分析的时候,代码分割出来的代码块。module是开发中的单个模块
如何自动生成webpack配置?
可以用一些官方脚手架
- webpack-cli
- vue-cli
// 首先安装 npm install -g @vue/cli // 新建项目hello vue create hello
- nuxt-cli
// 确保安装了npx,npx在npm5.2.0默认安装了 // 新建项目hello npx create-nuxt-app hello
webpack如何配置单页面和多页面的应用程序?
- 单个页面
module.exports = { entry: './path/to/my/entry/file.js' }
- 多页面应用程序
module.entrys = { entry: { pageOne: './src/pageOne/index.js', pageTwo: './src/pageTwo/index.js' } }
webpack-dev-server和http服务器如nginx有什么区别?
webpack-dev-server使用内存来存储webpack开发环境下的打包文件,并且可以使用模块热更新,相比传统http服务器开发更加简单高效
什么是模块热更新?
webpack的一个功能,可以使代码修改后不用刷新浏览器就自动更新,高级版的自动刷新浏览器
dev-server是怎么跑起来的
webpack-dev-server支持两种模式来自动刷新页面
- iframe模式(页面放在iframe中,当发送改变时重载) 无需额外配置,只要以这种格式url访问即可。
http://localhost:8080/webpack-dev-server/index.html
- inline模式(将webpack-dev-server的客户端入口添加到bundle中) inline模式下url不用发生变化,但启动inline模式分两种情况
// 以命令行启动webpack-dev-server有两种方式 // 方式1 在命令行中添加--inline命令 // 方式2 在webpack-config.js添加devServer:{inline: true} // 以node.js API启动有两种方式 // 方式1 添加webpack-dev-server/client?http://localhost:8080/到webpack配置的entry入口点 config.entry.app.unshift("webpack-dev-server/client?http://localhost:8080/"); // 将<script src="http://localhost:8080/webpack-dev-server.js"></script>添加到html文件中
使用过webpack里面哪些plugin和loader
loader
- babel-loader: 将ES6+转移成ES5-
- css-loader,style-loader:解析css文件,能够解释@import url()等
- file-loader:直接输出文件,把构建后的文件路径返回,可以处理很多类型的文件
- url-loader:打包图片
// url-loader增强版的file-loader,小于limit的转为Base64,大于limit的调用file-loader npm install url-loader -D // 使用 module.exports = { module: { rules: [{ test: /\.(png|jpg|gif)$/, use: [{ loader: 'url-loader', options: { outputPath: 'images/', limit: 500 //小于500B的文件打包出Base64格式,写入JS } }] }] } }
plugins
- html-webpack-plugin: 压缩html
const HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { //... plugins: [ new HtmlWebpackPlugin({ filename: 'index.html', // 配置输出文件名和路径 template: './public/index.html', // 配置要被编译的html文件 hash: true, // 压缩 => production 模式使用 minify: { removeAttributeQuotes: true, //删除双引号 collapseWhitespace: true //折叠 html 为一行 } }) ] }
- clean-webpack-plugin: 打包器清理源目录文件,在webpack打包器清理dist目录
npm install clean-webpack-plugin -D // 修改webpack.config.js const cleanWebpackPlugin=require('clean-webpack-plugin') module.exports = { plugins: [new cleanWebpackPlugin(['dist'])] }
webpack中babel的实现
安装 npm i -D @babel-preset-env @babel-core babel-loader
- @babel-preset-env:可以让我们灵活设置代码目标执行环境
- @babel-core: babel核心库
- babel-loader: webpack的babel插件,让我们可以在webpack中运行babel
配置.babelrc
{ "presets": ['@babel/preset-env']}
配置webpack.config.js
module.exports = { entry: './src/index.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'bundle.js' }, module: { rules: [{ test: /\.js$/, exclude: /node_modules/, use: {loader: 'babel-loader'} }] }}
提取公用代码
module.exports = { optimization: { splitChunks: { common: { // 抽离公共代码 chunks: 'initial', name: 'common', // 打包后的文件名 minChunks: 2, // 最小引用2次 minSize: 0 // 超出0字节就生成一个新包 }, styles: { // 抽离公用代码 name: 'styles', test: /\.css$/, chunks: 'all', minChunks: 2, enforce: true }, vender: { // 抽离第三方插件 test: /node_modules/, chunks: 'initial', name: 'vendor', // 打包后的文件名 priority: 10 // 设置优先级,防止与自定义公共代码提取时被覆盖,不进行打包 } } }}复制代码
什么是长缓存?在webpack中如何做到长缓存优化?
- 浏览器在用户访问页面的时候,为了加快加载速度会对用户访问的静态资源进行存储,但是每一次代码升级或更新都需要浏览器下载新的代码,最简单方便的方式就是引入新的文件名称。
- webpack中可以在output中指定chunkhash,并且分离经常更新的代码和框架代码。通过NameModulesPlugin或HashedModuleIdsPlugin使再次打包文件名不变。
什么是Tree-shaking?CSS可以Tree-shaking?
Tree-shaking是指在打包中取出那些引入了但在代码中没有被用到的死代码。webpack中通过uglifysPlugin来Tree-shaking JS。CSS需要使用purify-CSS
继承 8种
原型链继承
- 重点:子的原型对象为new一个父的实例
Child.prototype = new Parent();
- 缺点:多个实例对引用类型的操作会被篡改
借用构造函数继承
- 重点:在子构造函数内部调用父构造函数
Parent.call(this)
- 缺点:无法实现复用,不能继承原型属性/方法
组合继承
- 重点:使用原型链继承共享的属性和方法,通过借用构造函数继承实例属性
function Child(name,age){ // 继承属性 Parent.call(this, name) this.age=age}// 继承方法Child.prototype = new Parent()Child.prototype.constructor = Child;复制代码
- 缺点:无论在什么情况都会调用两次父构造函数,一次是创建子类型原型,另一次是在子构造函数内部
原型式继承
- 重点:执行对给定对象的浅复制
function object(obj){ function F(){} F.prototype=obj return new F();}var person1=object(person);复制代码
在ES5中Object.create()可替换上面的方法object() var person1 = Object.create(person);
- 缺点:原型链继承多个实例的引用类型属性指向相同,存在篡改的可能;无法传递参数
寄生式继承
- 重点:在原型式继承的基础上,增强对象,返回构造函数
function createAnother(obj){ var clone=object(obj); // ES5中用这个 // var clone=Object.create(obj); // 增强对象 clone.sayHi=function(){}; return clone;}var person1=createAnother(person)复制代码
- 缺点:同原型式继承
寄生组合式继承
- 重点:结合构造函数传递参数和寄生模式实现继承
// 借用构造函数增强子类实例属性(支持传参和避免篡改)function Child(name,age){ // 继承属性 Parent.call(this, name) this.age=age}function inheritPrototype(Child, Parent){ var prototype=Object.create(Parent.prototype); prototype.constructor=Child; Child.prototype=prototype;}// 将父类原型指向子类,这样子类就能使用父类原型链的属性/方法inheritPrototype(Child, Parent);复制代码
优点:只调用一次构造函数,原型链不变,是最成熟的
混入方式继承多个方式
重点:利用Object.assign将父类原型上的方法拷贝到子类原型上,这样子类实例实例就可以使用父类的方法
Object.assign(Child.prototype, Parent.prototype); Child.prototype.constructor=Child; 复制代码
ES6类 extends
重点:使用extends表明继承自哪个父类,并且在子类构造函数中必须使用super,可以看做是Parent.call(this,value)
class Parent{ constructor(value){ this.val=value } } class Child extends Parent{ constructor(value){ super(value) this.val = value } }
为什么要总结webpack相关的面试题
随着现代前端开发的复杂度和规模越来越庞大,已经不能抛开工程化来独立开发了,如react的jsx代码必须编译后才能在浏览器中使用;又如sass和less的代码浏览器也是不支持的。 而如果摒弃了这些开发框架,那么开发的效率将大幅下降。在众多前端工程化工具中,webpack
脱颖而出成为了当今最流行的前端构建工具。 然而大多数的使用者都只是单纯的会使用
,而并不知道其深层的原理。希望通过以下的面试题总结可以帮助大家温故知新、查缺补漏,知其然而又知其所以然。
问题列表
- webpack与grunt、gulp的不同?
- 与webpack类似的工具还有哪些?谈谈你为什么最终选择(或放弃)使用webpack?
- 有哪些常见的Loader?他们是解决什么问题的?
- 有哪些常见的Plugin?他们是解决什么问题的?
- Loader和Plugin的不同?
- webpack的构建流程是什么?从读取配置到输出文件这个过程尽量说全
- 是否写过Loader和Plugin?描述一下编写loader或plugin的思路?
- webpack的热更新是如何做到的?说明其原理?
- 如何利用webpack来优化前端性能?(提高性能和体验)
- 如何提高webpack的构建速度?
- 怎么配置单页应用?怎么配置多页应用?
- npm打包时需要注意哪些?如何利用webpack来更好的构建?
- 如何在vue项目中实现按需加载?
1. webpack与grunt、gulp的不同?
三者都是前端构建工具,grunt和gulp在早期比较流行,现在webpack相对来说比较主流,不过一些轻量化的任务还是会用gulp来处理,比如单独打包CSS文件等。
grunt和gulp是基于任务和流(Task、Stream)的。类似jQuery,找到一个(或一类)文件,对其做一系列链式操作,更新流上的数据, 整条链式操作构成了一个任务,多个任务就构成了整个web的构建流程。
webpack是基于入口的。webpack会自动地递归解析入口所需要加载的所有资源文件,然后用不同的Loader来处理不同的文件,用Plugin来扩展webpack功能。
所以总结一下:
- 从构建思路来说
gulp和grunt需要开发者将整个前端构建过程拆分成多个`Task`,并合理控制所有`Task`的调用关系 webpack需要开发者找到入口,并需要清楚对于不同的资源应该使用什么Loader做何种解析和加工
- 对于知识背景来说
gulp更像后端开发者的思路,需要对于整个流程了如指掌 webpack更倾向于前端开发者的思路
2. 与webpack类似的工具还有哪些?谈谈你为什么最终选择(或放弃)使用webpack?
同样是基于入口的打包工具还有以下几个主流的:
从应用场景上来看:
- webpack适用于大型复杂的前端站点构建
- rollup适用于基础库的打包,如vue、react
- parcel适用于简单的实验性项目,他可以满足低门槛的快速看到效果
由于parcel在打包过程中给出的调试信息十分有限,所以一旦打包出错难以调试,所以不建议复杂的项目使用parcel
3.有哪些常见的Loader?他们是解决什么问题的?
- file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件
- url-loader:和 file-loader 类似,但是能在文件很小的情况下以 base64 的方式把文件内容注入到代码中去
- source-map-loader:加载额外的 Source Map 文件,以方便断点调试
- image-loader:加载并且压缩图片文件
- babel-loader:把 ES6 转换成 ES5
- css-loader:加载 CSS,支持模块化、压缩、文件导入等特性
- style-loader:把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS。
- eslint-loader:通过 ESLint 检查 JavaScript 代码
4.有哪些常见的Plugin?他们是解决什么问题的?
- define-plugin:定义环境变量
- commons-chunk-plugin:提取公共代码
- uglifyjs-webpack-plugin:通过
UglifyES
压缩ES6
代码
5.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
的实例,参数都通过构造函数传入。
6.webpack的构建流程是什么?从读取配置到输出文件这个过程尽量说全
Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:
- 初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数;
- 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译;
- 确定入口:根据配置中的 entry 找出所有的入口文件;
- 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理;
- 完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;
- 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;
- 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。
在以上过程中,Webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果。
7.是否写过Loader和Plugin?描述一下编写loader或plugin的思路?
Loader像一个"翻译官"把读到的源文件内容转义成新的文件内容,并且每个Loader通过链式操作,将源文件一步步翻译成想要的样子。
编写Loader时要遵循单一原则,每个Loader只做一种"转义"工作。 每个Loader的拿到的是源文件内容(source
),可以通过返回值的方式将处理后的内容输出,也可以调用this.callback()
方法,将内容返回给webpack。 还可以通过 this.async()
生成一个callback
函数,再用这个callback将处理后的内容输出出去。 此外webpack
还为开发者准备了开发loader的工具函数集——loader-utils
。
相对于Loader而言,Plugin的编写就灵活了许多。 webpack在运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
8.webpack的热更新是如何做到的?说明其原理?
webpack的热更新又称热替换(Hot Module Replacement),缩写为HMR。 这个机制可以做到不用刷新浏览器而将新变更的模块替换掉旧的模块。
原理:
图片来自饿了么前端@知乎专栏
首先要知道server端和client端都做了处理工作
- 第一步,在 webpack 的 watch 模式下,文件系统中某一个文件发生修改,webpack 监听到文件变化,根据配置文件对模块重新编译打包,并将打包后的代码通过简单的 JavaScript 对象保存在内存中。
- 第二步是 webpack-dev-server 和 webpack 之间的接***互,而在这一步,主要是 dev-server 的中间件 webpack-dev-middleware 和 webpack 之间的交互,webpack-dev-middleware 调用 webpack 暴露的 API对代码变化进行监控,并且告诉 webpack,将代码打包到内存中。
- 第三步是 webpack-dev-server 对文件变化的一个监控,这一步不同于第一步,并不是监控代码变化重新打包。当我们在配置文件中配置了devServer.watchContentBase 为 true 的时候,Server 会监听这些配置文件夹中静态文件的变化,变化后会通知浏览器端对应用进行 live reload。注意,这儿是浏览器刷新,和 HMR 是两个概念。
- 第四步也是 webpack-dev-server 代码的工作,该步骤主要是通过 sockjs(webpack-dev-server 的依赖)在浏览器端和服务端之间建立一个 websocket 长连接,将 webpack 编译打包的各个阶段的状态信息告知浏览器端,同时也包括第三步中 Server 监听静态文件变化的信息。浏览器端根据这些 socket 消息进行不同的操作。当然服务端传递的最主要信息还是新模块的 hash 值,后面的步骤根据这一 hash 值来进行模块热替换。
- webpack-dev-server/client 端并不能够请求更新的代码,也不会执行热更模块操作,而把这些工作又交回给了 webpack,webpack/hot/dev-server 的工作就是根据 webpack-dev-server/client 传给它的信息以及 dev-server 的配置决定是刷新浏览器呢还是进行模块热更新。当然如果仅仅是刷新浏览器,也就没有后面那些步骤了。
- HotModuleReplacement.runtime 是客户端 HMR 的中枢,它接收到上一步传递给他的新模块的 hash 值,它通过 JsonpMainTemplate.runtime 向 server 端发送 Ajax 请求,服务端返回一个 json,该 json 包含了所有要更新的模块的 hash 值,获取到更新列表后,该模块再次通过 jsonp 请求,获取到最新的模块代码。这就是上图中 7、8、9 步骤。
- 而第 10 步是决定 HMR 成功与否的关键步骤,在该步骤中,HotModulePlugin 将会对新旧模块进行对比,决定是否更新模块,在决定更新模块后,检查模块之间的依赖关系,更新模块的同时更新模块间的依赖引用。
- 最后一步,当 HMR 失败后,回退到 live reload 操作,也就是进行浏览器刷新来获取最新打包代码。
9.如何利用webpack来优化前端性能?(提高性能和体验)
用webpack优化前端性能是指优化webpack的输出结果,让打包的最终结果在浏览器运行快速高效。
- 压缩代码。删除多余的代码、注释、简化代码的写法等等方式。可以利用webpack的
UglifyJsPlugin
和ParallelUglifyPlugin
来压缩JS文件, 利用cssnano
(css-loader?minimize)来压缩css - 利用CDN加速。在构建过程中,将引用的静态资源路径修改为CDN上对应的路径。可以利用webpack对于
output
参数和各loader的publicPath
参数来修改资源路径 - 删除死代码(Tree Shaking)。将代码中永远不会走到的片段删除掉。可以通过在启动webpack时追加参数
--optimi***imize
来实现 - 提取公共代码。
10.如何提高webpack的构建速度?
- 多入口情况下,使用
CommonsChunkPlugin
来提取公共代码 - 通过
externals
配置来提取常用库 - 利用
DllPlugin
和DllReferencePlugin
预编译资源模块 通过DllPlugin
来对那些我们引用但是绝对不会修改的npm包来进行预编译,再通过DllReferencePlugin
将预编译的模块加载进来。 - 使用
Happypack
实现多线程加速编译 - 使用
webpack-uglify-parallel
来提升uglifyPlugin
的压缩速度。 原理上webpack-uglify-parallel
采用了多核并行压缩来提升压缩速度 - 使用
Tree-shaking
和Scope Hoisting
来剔除多余代码
11.怎么配置单页应用?怎么配置多页应用?
单页应用可以理解为webpack的标准模式,直接在entry
中指定单页应用的入口即可,这里不再赘述
多页应用的话,可以使用webpack的 AutoWebPlugin
来完成简单自动化的构建,但是前提是项目的目录结构必须遵守他预设的规范。 多页应用中要注意的是:
- 每个页面都有公共的代码,可以将这些代码抽离出来,避免重复的加载。比如,每个页面都引用了同一套css样式表
- 随着业务的不断扩展,页面可能会不断的追加,所以一定要让入口的配置足够灵活,避免每次添加新页面还需要修改构建配置
12.npm打包时需要注意哪些?如何利用webpack来更好的构建?
Npm
是目前最大的 JavaScript 模块仓库,里面有来自全世界开发者上传的可复用模块。你可能只是JS模块的使用者,但是有些情况你也会去选择上传自己开发的模块。 关于NPM模块上传的方法可以去官网上进行学习,这里只讲解如何利用webpack来构建。
NPM模块需要注意以下问题:
- 要支持CommonJS模块化规范,所以要求打包后的最后结果也遵守该规则。
- Npm模块使用者的环境是不确定的,很有可能并不支持ES6,所以打包的最后结果应该是采用ES5编写的。并且如果ES5是经过转换的,请最好连同SourceMap一同上传。
- Npm包大小应该是尽量小(有些仓库会限制包大小)
- 发布的模块不能将依赖的模块也一同打包,应该让用户选择性的去自行安装。这样可以避免模块应用者再次打包时出现底层模块被重复打包的情况。
- UI组件类的模块应该将依赖的其它资源文件,例如
.css
文件也需要包含在发布的模块里。
基于以上需要注意的问题,我们可以对于webpack配置做以下扩展和优化:
- CommonJS模块化规范的解决方案: 设置
output.libraryTarget='commonjs2'
使输出的代码符合CommonJS2 模块化规范,以供给其它模块导入使用 - 输出ES5代码的解决方案:使用
babel-loader
把 ES6 代码转换成 ES5 的代码。再通过开启devtool: 'source-map'
输出SourceMap以发布调试。 - Npm包大小尽量小的解决方案:Babel 在把 ES6 代码转换成 ES5 代码时会注入一些辅助函数,最终导致每个输出的文件中都包含这段辅助函数的代码,造成了代码的冗余。解决方法是修改
.babelrc
文件,为其加入transform-runtime
插件 - 不能将依赖模块打包到NPM模块中的解决方案:使用
externals
配置项来告诉webpack哪些模块不需要打包。 - 对于依赖的资源文件打包的解决方案:通过
css-loader
和extract-text-webpack-plugin
来实现,配置如下:
const ExtractTextPlugin = require('extract-text-webpack-plugin'); module.exports = { module: { rules: [ { // 增加对 CSS 文件的支持 test: /\.css/, // 提取出 Chunk 中的 CSS 代码到单独的文件中 use: ExtractTextPlugin.extract({ use: ['css-loader'] }), }, ] }, plugins: [ new ExtractTextPlugin({ // 输出的 CSS 文件名称 filename: 'index.css', }), ], };
13.如何在vue项目中实现按需加载?
Vue UI组件库的按需加载 为了快速开发前端项目,经常会引入现成的UI组件库如ElementUI、iView等,但是他们的体积和他们所提供的功能一样,是很庞大的。 而通常情况下,我们仅仅需要少量的几个组件就足够了,但是我们却将庞大的组件库打包到我们的源码中,造成了不必要的开销。
不过很多组件库已经提供了现成的解决方案,如Element出品的babel-plugin-component
和AntDesign出品的babel-plugin-import
安装以上插件后,在.babelrc
配置中或babel-loader
的参数中进行设置,即可实现组件按需加载了。
{ "presets": [["es2015", { "modules": false }]], "plugins": [ [ "component", { "libraryName": "element-ui", "styleLibraryName": "theme-chalk" } ] ] }
单页应用的按需加载 现在很多前端项目都是通过单页应用的方式开发的,但是随着业务的不断扩展,会面临一个严峻的问题——首次加载的代码量会越来越多,影响用户的体验。
通过import(*)
语句来控制加载时机,webpack内置了对于import(*)
的解析,会将import(*)
中引入的模块作为一个新的入口在生成一个chunk。 当代码执行到import(*)
语句时,会去加载Chunk对应生成的文件。import()
会返回一个Promise对象,所以为了让浏览器支持,需要事先注入Promise polyfill