当前位置: 首页 > Web前端 > JavaScript

深入探讨按需导入组件库

时间:2023-03-27 16:17:42 JavaScript

为了减少首屏代码量,对于一些大型的第三方库或者团队的基础工具库,需要按需导入模块。如:importButtonfrom'antd/lib/button';但当需要导入大量组件场景时,开发繁琐,体验不友好。这些组件库的官方文档或者社区都会推荐一些babel插件来帮助实现良好的开发体验和性能优化。本文详细探讨了这些工具的工作原理。Antd等UI组件库按需加载。在使用旧版antd时,推荐使用babel-plugin-import工具按需导入组件。该工具可以进行以下转换:import{Button}from'antd';ReactDOM.render();↓↓↓↓↓var_button=require('antd/lib/button');require('antd/lib/button/style');ReactDOM.render(<_button>xxxx);antd和element-ui都叫按需加载,但我觉得叫按需导入更符合意境。eleemnt-ui的按需导入工具是babel-plugin-component。babel-plugin-import工具会在编译时分析模块导入语句。当需要导入的是目标库组件时,会删除原来的导入,并生成多个新的导入(如果配置样式,会导入额外的样式)。由于重新生成的import语句会导致模块变量发生变化(比如上面案例演示中的Button会转换为_button),这会导致插件程序也分析当前模块的所有变量。对于使用原变量的语句,变量名修复。最新的antd已经推荐使用webpack的treeshaking机制来实现按需加载。babel-plugin-import基本没有更新。对于Vue生态,很多组件库不能使用treeshaking来支持全局注册。babel-plugin-import等工具虽然支持部分配置定制,但仍然存在以下不足:每个插件都是针对特定的组件库,需要遵守特定的目录和文件维护规范。比如babel-plugin-import导入的模块需要支持目录:|--component|----index.js|----*.js|----style|------index.js|------*.cssbabel-plugin-import由于底层实现改变了引入的模块变量,然后在整个模块的枚举语句类型中找到该变量进行修复,在一些非常不常见的语句,会出现不改变模块变量导致的语法错误问题。支持任何库的按需导入。如果你也想在源码中支持完全导入,但实际上是按需加载项目中的公共基础模块(公共组件、公共工具文件等),可以通过forkbabel-plugin-等工具调整逻辑import来实现,也可以使用工具babel-plugin-transform-imports来支持。babel-plugin-transform-imports是自己配置转换格式,比如可以实现如下效果:import{Row,GridasMyGrid}from'react-bootstrap';从'lodash'导入{合并};↓↓↓↓↓↓从'react-bootstrap/lib/Row'导入行;从'react-bootstrap/lib/Grid'导入MyGrid;从'lodash/merge'导入合并;此时需要的配置是:true},}]]}transform可以支持功能,实现高级定制,扩展性非常高。而babel-plugin-transform-imports的实现是直接修复import语句,比babel-plugin-import更加优雅适用。阅读它的源码也可以发现它比babel-plugin-import要简洁的多。.babel-plugin-import底层是删除原来的import,然后生成新的targetimport,导致导入模块的变量发生变化。但是babel-plugin-transform-imports也有一些缺陷:它不能从一个导入中生成多个导入。这也意味着babel-plugin-transform-imports不能用于antd、element-ui等UI组件库的按需导入模块:这些UI组件库除了导入js模块外,往往还有一个样式模块。你可以forkbabel-plugin-transform-imports来扩展它的逻辑,比如这个库babel-plugin-transform-module-imports。参考他的实现原理,我自己实现了一个工具babel-plugin-transform-import-module,可以支持更多的配置,基本可以用它来满足源码中导入所有模块但实际按需导入的效果。像lodash一样基于调用按需导入在使用lodash时,可以使用babel-plugin-lodash插件进行导入优化。转换能力:import_from'lodash'import{add}from'lodash/fp'constaddOne=add(1)_.map([1,2,3],addOne)to:import_addfrom'lodash/fp/add'import_mapfrom'lodash/map'constaddOne=_add(1)_map([1,2,3],addOne)在使用lodash时使用babel-plugin-lodash可以提升开发体验:在代码中是完全导入使用,无需关注其内部结构,按需导入相应的工具功能模块,交给底层babel插件处理。除了不用担心是否导入额外的代码,用户还可以配合typescript使用,以获得更好的代码提示,从而减少认知。目前这个插件只支持lodash库。借鉴其概念,可以实现:/file')如果改造的再深入一些,可以优化一些市面上流行的库,比如antd库的使用:import*asAntdfrom'antd';ReactDOM.render(xxxx);↓↓↓↓↓↓从'antd/lib/button'导入按钮;import('antd/lib/button');ReactDOM.render();以上效果是在我的一个babel插件babel-plugin-module-call-import中实现的,可以支持。如果需要像babel-plugin-lodash一样根据文件目录结构自动转换loader,可以直接fork源码调整。我团队的很多项目基本上都是用这个方法。根据Vue代码中的标签,在Vue应用中导入和注册组件的方式有两种:全局注册和本地注册。全局注册开发体验最好,但是会导入UI组件库的所有代码,增加很多无用的代码,导致首屏暴涨。如何像全局注册组件一样开发友好,支持按需导入组件提升性能?这里有一个解决方法:在解析vue文件的模板时,记录下模板文件中使用的标签,然后在编译该文件对应的js代码时,根据标签自动导入UI组件,然后在组件中注册组件配置对象的属性上升。如果代码:在编译时time,会转换成类似这样的东西:;exportdefault{components:{ElButton,},created(){},};我开发了两个工具来支持这个解决方案:babelplugin:babel-plugin-vue-import-component-by-tagwebpackloader:vue-record-tags-loader只支持vue2版本,vue3可参考解决方案实现。大家有什么更好的想法,欢迎讨论。