当前位置: 首页 > Web前端 > vue.js

教你vue组件库共享组件不直接打包进代码

时间:2023-03-31 15:05:53 vue.js

@import"yn-button";1.“共享组件没有直接打包到代码中”是什么意思?比如你写一个组件库,有3个组件:Button、Dialog、MessageBox。其中Dialog和MessageBox组件都引用了Button组件,所以Button组件是共享组件。将这三个组件一一打包后,查看打包后的Dialog和MessageBox组件的产品代码,会发现Dialog和MessageBox组件都包含了Button组件的产品代码,这样产品体积就变大了。有什么办法可以让打包后的Dialog和MessageBox组件产品不包含Button组件产品代码?答案是肯定的。比如ant-design-vue和element-ui的打包产品代码中就没有共享组件代码。它们通过import或require加载共享组件。如ant-design-vue打包产品代码:2.如何实现?这个问题也困扰了我很久,直到用esbuild打包我的【vue3bootstrap图标组件库】才解决这个问题。原理很简单:将共享组件作为外部扩展(Externals),通常在打包时将vue设置为外部扩展,那么共享组件为什么不能设置为外部扩展呢?将共享组件设置为外部扩展后,webpack或其他打包工具不会将其打包到产品中,而是以import或require的形式加载。看到这里你应该开悟了!您将编写下一个代码。3、代码实现(vue3)我这里以esbuild打包为例,webpack或者vite的代码类似。首先,需要安装2个关键依赖:npmiesbuildesbuild-plugin-vue-D接下来,安装esbuild并将其打包成依赖:npmiesbuild-plugin-progress-D安装css处理依赖:npmipostcssesbuild-sass-pluginautoprefixerpostcss-preset-envpostcss-import-D目录结构:-my-project+node_modules-src-componentsyn-button.scssYnButton.vueYnDialog.vueYnMessageBox.vueApp.vuemain.jsbuild-lib。jspackage.jsonyn-button.scss.yn-button{transition:all.3s;}YnButton.vue@import"yn-button";YnDialog.vueYnMessageBox.vue3.1、常规打包(共享组件打包到产品中)build-lib.jsconstpath=require('path');constvue=require('esbuild-plugin-vue').default;//处理vue组件constesBuild=require('esbuild');constprogress=require('esbuild-plugin-progress');//esbuild打包进度条//scss、css处理const{sassPlugin}=require('esbuild-sass-plugin');constpostcss=require('postcss');constautoprefixer=require('autoprefixer');constpostcssPresetEnv=require('postcss-preset-env');constpostcssImport=require('postcss-import');functionbuild(entryPoint){esBuild.build({bundle:true,entryPoints:[entryPoint],outdir:'libs',external:['vue'],loader:{'.ts':'ts'},format:'esm',drop:["console","debugger"],//移去控制台、调试器信息treeShaking:true,plugins:[sassPlugin({asynctransform(source){const{css}=awaitpostcss([autoprefixer,postcssPresetEnv(),postcssImport()]).process(source,{from:undefined});returncss;}}),vue(),进度()]});}build(path.resolve(__dirname,'./src/components/YnButton.vue'));build(path.resolve(__dirname,'./src/components/YnDialog.vue'));build(path.resolve(__dirname,'./src/components/YnMessageBox.vue'));在控制台执行node./build-lib.js,会出现6个打包好的产品:有没有发现什么问题?应该打包4个产品,因为YnDialog和YnMessageBox组件根本没有加css,但是打包后多了2个css文件,这也是为什么要把共享组件打包到代码中的问题之一,看打包产品:YnButton.jsYnButton.cssYnDialog.jsYnDialog.css通过查看YnDialog.js产品的内容,发现里面包含了YnButton组件的代码,这显然不是我们想要的。3.2.单独的共享组件代码封装esbuild有一个外部参数可以配置指定的依赖作为外部扩展,但是它是静态的,只适合配置一些全局的外部扩展。不能做需要根据条件判断的动态外部扩展那么有什么办法吗?答案是:插件(plugin)我们可以写一个插件来完成constpath=require('path');constvue=require('esbuild-plugin-vue').default;//处理vue组件constesBuild=require('esbuild');constprogress=require('esbuild-plugin-progress');//esbuild打包进度条//scss,css处理const{sassPlugin}=require('esbuild-sass-plugin');constpostcss=require('postcss');constautoprefixer=require('autoprefixer');constpostcssPresetEnv=require('postcss-preset-env');constpostcssImport=require('postcss-import');functionbuild(entryPoint){esBuild.build({bundle:true,entryPoints:[entryPoint],outdir:'libs',external:['vue'],loader:{'.ts':'ts'},格式:'esm',drop:["console","debugger"],//删除控制台和调试器信息treeShaking:true,plugins:[sassPlugin({asynctransform(source){const{css}=awaitpostcss([autoprefixer,postcssPresetEnv(),postcssImport()]).process(source,{from:undefined});返回CSS;}}),{//自定义外部扩展esbuild插件名称:'my-esbuild-plugin',setup(build){letfilter=/./;/*onResolvehook是路径解析钩子,在esbuild解析路径时触发,即执行import...from...时会调用onResolvehook*/build.onResolve({filter:filter},function(args){//console.log('args',args);letmodulePath=args.importer;letkind=args.kind;letpath=args.path;letfileInComponents=modulePath.includes('/components/');//只有components目录下导入的以.vue结尾的文件才可以认为是外部扩展letexternal=fileInComponents&&kind==='import-statement'&&path.endsWith('.vue');//不需要指定为外部扩展依赖直接returnnullif(!external){returnnull;}/*替换导入路径中的'src/components/'部分进入'./',因为打包后,它们都在同一个文件夹中。打包后产品中的共享组件会以importXXfrom'./YY.vue'的形式导入*///提示:这部分逻辑需??要根据自己的Project目录结构来判断是否这是必要的if(path.startsWith('src/components/')){path=path.replace('src/components/','./');path=path.replace('.vue','.js');}return{path,//是否需要external(如果模块是外部的,esbuild在构建时不会加载模块,而是保留原来的importxxxfrom'yyy'代码)external};});}},vue(),progress()]});}build(path.resolve(__dirname,'./src/components/YnButton.vue'));build(path.resolve(__dirname,'./src/components/YnDialog.vue'));build(path.resolve(__dirname,'./src/components/YnMessageBox.vue'));然后在console.js命令上运行node./build-lib,此时libs目录下只有4个产品:我们再看产品代码:YnButton.jsYnButton.cssYnButton组件打包产品没有变化,没问题YnDialog.jsYnDialog组件封装产品中不包含YnButton组件代码,而是以import的形式引入,这就是我们想要的结果。你完成了!