背景
之前我们的组件库都是单个的,现在合并到一个项目中后,我们使用export导出,做到使用方可以通过解构,使用我们一部分组件,看起来像是按需引入的写法,实际上没有解构出来的组件也被项目打包了,并没有做到减少宿主项目体积。
分析
我们组件库里面有多个组件,想要实现按需引入的前提,就是给我们组件库项目设置成多入口打包方式,当宿主项目引入某一个组件的时候,直接上引入的就是以该组件为入口的打包生成的文件,达到按需引入的目的。
- 多入口打包配置
- 抽离组件自身引入的css样式,做到可以独立引入
实际配置
多入口打包配置
多入口配置其实比较简单,在我们的entry对象中手动添加即可,如下:
module.exports = {
configureWebpack: {
entry: {
'xl-number-input: '/Users/administrator/Documents/program/julive_npm/jl_ui/packages/xl-number-input/index.js',
'xl-image-preview': '/Users/administrator/Documents/program/julive_npm/jl_ui/packages/xl-image-preview/index.js'
},
},
}
但是这么写的话,每次新增一个组件就要去一行,灵活性很低,如果开发人员只是添加了组件没有进行打包配置,会导致宿主环境引入失败,所以这里建议用代码的方式自动帮我们导入entry
封装一个方法,用于寻找组件库文件夹下面的所有组件,找到组件库名称并且对应上路径,当然,前提是你的组件库目录都保持一致,否则寻找不成功
const fs = require('fs')
const path = require('path')
const join = path.join
const resolve = (dir) => path.join(__dirname, '../', dir)
getComponentEntries(path) {
// 获取到组件代码所在的文件夹目录下所有文件名称
let files = fs.readdirSync(resolve(path));
const componentEntries = files.reduce((ret, item) => {
// 将文件名转成路径
const itemPath = join(path, item);
const isDir = fs.statSync(itemPath).isDirectory();
if (isDir) {
// 将index拼接到地址后
ret[item] = resolve(join(itemPath, 'index.js'));
}
return ret;
}, {});
return componentEntries;
}
有这个方法后,我们把方法在entry中执行一下
module.exports = {
configureWebpack: {
entry: {
...getComponentEntries('packages')
},
}
}
现在有一个问题是,我们导出所有组件的index.js,实际上是不需要用文件夹包裹起来的,所以我们在entry中单独引入
module.exports = {
configureWebpack: {
entry: {
'/': resolve('packages/index.js'),
...getComponentEntries('packages')
},
}
}
抽离css
最后我们注意把css也单独给每一个组件抽离出来,方便引入的时候单独引入某一个组件的样式
module.exports = {
configureWebpack: {
...
},
css: {
sourceMap: true,
extract: {
filename: '[name]/style.css'
}
}
}
使用
在宿主项目中下载我们的组件库,然后按需引入我们的组件,如下,可以正常使用
import { JlIconSvg } from 'jl_ui';
import 'jl_ui/lib/jl-icon-svg/style.css';
但是向上面那样写,每次都需要手动引入对应的css文件,比较麻烦,我们发现element-ui或者是ant-design都使用插件来引入,所以我们也学习一下,下载babel-plugin-import插件,在babel的配置文件中加入:
module.exports={
"plugins": [
["component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
],
[
"import",
{
"libraryName": "jl_ui",
"style": (name) => {
if (name === "jl_ui/lib/xl-number-input") {
return false;
}
return `${name}/style.css`;
}
},
]
]
}
注意:
看上面的代码,发现xl-number-input组件做了特殊处理,这是因为这个组件没有单独添加样式,也就是打包后,这个组件的文件夹下是没有style.css文件的,这样会导致babel-plugin-import报错,它找不到对应组件的css,所以我们需要手动将xl-number-input组件的css返回false,代码不需要引入