基于rollup的组件库打包体积优化小结

前端之家收集整理的这篇文章主要介绍了基于rollup的组件库打包体积优化小结前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

背景

前段时间对公司内部的组件库(类似element-ui)做了打包体积优化,现在抽点时间记录下。以前也做过构建速度的优化,具体可以看

一些存在的问题

最开始打包是基于webpack的,在按需加载上存在的体积冗余会比较大,如:

  1. webpack打包特有的模块加载器函数,这部分其实有些多余,最好去掉
  2. 使用babel转码时,babel带来的helper函数全部是内联状态,需要转成importrequire来引入
  3. 使用transform-rumtime对一些新特性添加polyfill,也是内联状态,需要转成importrequire来引入
  4. vue-loader带来的额外代码,如normalizeComponent,不做处理也是内联
  5. transform-vue-jsx带来的额外函数引入,如mergeJSXProps,不做处理也是内联

以上几个问题,如果只是一份代码,那不会有太大问题,但是如果是按需加载,用户一旦引入多个组件,以上的代码就会出现多份,带来严重的影响

以上代码会转成

这样,就会出现多份相同的helper函数代码,多份webpack的模块加载器函数,而且还不好去重

寻找解决方

讨论过后主要有以下几种选择

采用后编译

我们也认同这种方案,采用后编译可以解决上面的各种问题,也有组件库是这样做的,比如cube-ui,但是这样有些不方便,因为用户需要设置各种alias,还要保证好各种编译环境,如jsx,而且未来可能会引入flow,会更加不方便,所以暂时不考虑

使用rollup打包,设置external(当然webpack也可以)外联helper函数

使用rollup打包,可以直接解决问题1和问题4,设置external可以解决transform-runtime等带来的helper,这取决于相关插件实现时是不是通过importrequire添加helper的,如果是直接copy的话,那就还得另找办法。最后决定就这种方案进行尝试

使用rollup对打包进行重构

使用rollup打包可能某些习惯和webpack有些出入,在这里很多事需要引入插件来完成,比如引入node_modules中的模块的话,需要加入rollup-plugin-node-resolve,加载commonjs模块需要引入rollup-plugin-commonjs等等。另外还有些比较麻烦的,比如经常会这样写

然后希望模块打包器可以识别成

rollup里还是需要用插件来完成这件事,找到的插件都没能满足各种需求,比如还需要对alias也能识别然后加上index.js,最后还是需要自己实现这个插件

基本的rollup配置应该差不多是这样的

这里采用的rollup-plugin-vue的版本是v3.0.0,不采用v4,因为打包出来的体积更小,功能完全满足组件库需要。因为会存在各种约定,比如组件肯定是存在render函数(不一定指的就是手写renderjsx,只是不会有在js中使用template这种情况,这样的好处是可以使用runtime-onlyvue),组件肯定不存在style部分等等。

babel的配置上基本不会有改变,只是rollup-plugin-babel加上runtimeHelpers,用来开启transform-runtme的。可能你会觉得为了更精简体积,应该去掉transform-runtime,这点我持保留意见,这里使用transform-runtime的主要作用是为了接管babel-helpers,因为这个babel-helpers无法被external。另外整个组件库用到的babel-runtime其实也不多,主要是类似Object.assign这样的函数,像这些函数,使用的话还是需要加上transform-runtime的,或者需要自己实现,感觉没什么必要。类似Array.prototype.includes这种无法被transform-runtime处理的还是会避免使用的

localResolve是自己实现的插件,用来添加index.js,并且能支持alias

alias插件用来添加alias,并且需要设置后缀

replace插件用来替换一些环境变量,比如开发环境会有错误提示生成环境不会有,这里展示的是开发环境的配置。

配置external

所有优化的关键在于external上,除了最基本的vue需要external外,还有比如Button组件内部依赖了Icon组件,那是需要把Icon组件external

其实就是所有的组件和共用的util函数都需要external,当然这里本来就存在了,不是本次优化要做的

主要要处理的是babel-helperhelper函数,但是这里不能做到,我也没有去了解babel是如何对这块进行处理的,最后还是需要transform-runtime来接管它。

rollupexternal配置是支持函数类型的,大概看tranform-runtime这个插件源码可以找到addImport这些方法,可以知道polyfill是通过import来引入的,可以被external,所以只需要在rollup配置的external添加上类似函数就可以达到我们想要的效果

这里就可以解决问题2和问题3

另外问题5,这个是如何来的呢,比如在写jsx时,可能会这样写

{/* other */}
) } }

在某个组件中依赖了另一个组件,考虑到扩展性,是支持对另一个组件进行props设置的,所以经常会这样写,在template中的话就类似于v-bind="tolltipProps"

这个时候transform-vue-jsx插件是会引入一个helper函数的,也就是babel-helper-vue-jsx-merge-props,大概看看transform-vue-jsx源码也可以得知,这个helper也是import进来的,所以可以把external改成

这样就可以做到对所有helper都使用import的形式来引入,而且使用rollup打包后的代码更可读,大概长这样

var Alert = { render: function render() {
var _class;

var _vm = this;var _h = _vm.$createElement;var _c = _vm._self._c || _h;return _c('transition',{ attrs: { "name": "gs-zoom-in-top" } },[_vm.show ? _c('div',{ class: (_class = { 'gs-alert': true },_defineProperty(_class,'gs-alert-' + _vm.type,!!_vm.type),'has-desc',_vm.desc || _vm.$slots.desc),_class) },[_vm.showIcon ? _c('div',{ staticClass: "gs-alert-icon",class: { "gs-alert-icon-top": !!_vm.desc } },[_vm._t("icon",[_c('gs-icon',{ attrs: { "name": _vm.icon } })])],2) : _vm._e(),_vm._v(" "),_c('div',{ staticClass: "gs-alert-content" },[_vm.title || _vm.$slots.default ? _c('div',{ staticClass: "gs-alert-title" },[_vm._t("default",[_vm._v(_vm._s(_vm.title))])],_vm.desc || _vm.$slots.desc ? _c('div',{ staticClass: "gs-alert-desc" },[_vm._t("desc",[_vm._v(_vm._s(_vm.desc))])],_vm.closable ? _c('div',{ staticClass: "gs-alert-close",on: { "click": _vm.close } },[_vm._t("close",[_vm._v(" " + _vm._s(_vm.closeText) + " "),!_vm.closeText ? _c('gs-icon',{ attrs: { "name": "close" } }) : _vm._e()])],2) : _vm._e()])]) : _vm._e()]);
},staticRenderFns: [],name: 'GsAlert',components: _defineProperty({},Icon.name,Icon),// props
// data

// methods
};

/ istanbul ignore next /
Alert.install = function (Vue) {
Vue.component(Alert.name,Alert);
};

export default Alert;

vue插件把vue组件中的template转成render函数,babel插件做语法转换,因为external的存在,保留了模块关系,整个代码看起来很清晰,很舒服,不像webpack,都会添加一个模块加载函数...

优化后和优化前的体积对比

下面的截图是生产环境的版本,也就是没有了代码提示,也已经压缩混淆后的代码体积对比 左边是优化前,右边是优化后

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程之家。

原文链接:https://www.f2er.com/js/31875.html

猜你在找的JavaScript相关文章