开发背景
本文中
自定义命名空间
与namespace
相同意思
最近在做一个菜单组件升级的工作,是将vue2版本的菜单组件(基于element ui
的menu等基础组件开发),升级为vue3版本,并且这个组件会在各个部门内使用。
由于使用者众多,需要做样式上的隔离,在vue2版本的时候,之前的开发者使用的是将底层的element ui
改写,重写里面的样式、标签名,封装成一个xx-element ui
,然后由该组件调用。
开发vue3版本时,我注意到element plus出了一个自定义命名空间的概念,相当于仅需几行代码就可以实现样式上的隔离,实在是个利器。
直接使用namespace
没有问题
按照官网的例子,直接改造,样式是可以隔离的,也可以正常显示。
但我这里出现了一个小问题,就是我使用的vite启动vue3项目的时候,原本启动的十分迅速,开启了namespace
之后,本地项目启动会变得卡顿一些
加上按需打包会影响namespace
作为一个供别人使用的组件,肯定是越小越好, element plus
肯定需要做tree shaking
我使用的是element plus的按需导入,具体配置方法可见官方文档。然后打包,走起!
结果:可以打出压缩后的包,但是里面的namespace
丢了,还是最原始的el-
element plus目前不支持两者在一个工作
尝试了一下解决,发现都不生效,去github上搜索相关问题,发现早就有人提过相关问题,其开发人员回复为“暂不支持”
个人解决思路
对我来说,这两者需要都支持的,要不然就没法交差。
对比了namespace
之后与之前的打包文件,发现规律:打包出的js文件,有一个变量记录着namespace
的名称,而css种的属性名称,与这个变量对应。
那这就容易了,在使用其原来按需打包的基础上,在通过脚本讲里面的字符串替换即可。
最终实现
package.json
"scripts": {
"build": "vite build && node build/index.js",
},
build/index.js
/**
* 通过element plus自动的namespace进行样式分离
* 由于目前element plus自动的namespace,无法支持treeshaking
* 因此打包之后,再遍历dist文件夹,替换打包之后的js、css值,实现namespace最终效果
*/
/* eslint-disable no-undef */
const fs = require('fs')
const path = require('path')
const distPath = path.resolve(__dirname, '../dist')
fs.readdir(distPath, function (err, files) {
if (err) return console.error('Error:(spec)', err)
for (const filename of files) {
if (!filename.endsWith('js') && !filename.endsWith('.css')) continue
const filePath = distPath + '/' + filename
fs.readFile(filePath, function (err, data) {
if (err) {
return err
}
let str = data.toString()
// js仅替换namespace key值即可
if (filename.endsWith('js')) {
str = str.replace('"el"', '"xxx"')
}
// css需要替换所有的el-
if (filename.endsWith('.css')) {
str = str.replace(/el-/g, 'xxx-')
}
fs.writeFile(filePath, str, function (err) {
if (err) return err
})
})
}
})
在项目中引入打包后的代码,运行正常,样式正常隔离
后记
估计后面element plus
官网会处理这个兼容问题,但对我来说这个已经不重要了。