背景

之前我们的组件库都是单个的,现在合并到一个项目中后,我们使用export导出,做到使用方可以通过解构,使用我们一部分组件,看起来像是按需引入的写法,实际上没有解构出来的组件也被项目打包了,并没有做到减少宿主项目体积。

分析

我们组件库里面有多个组件,想要实现按需引入的前提,就是给我们组件库项目设置成多入口打包方式,当宿主项目引入某一个组件的时候,直接上引入的就是以该组件为入口的打包生成的文件,达到按需引入的目的。

  1. 多入口打包配置
  2. 抽离组件自身引入的css样式,做到可以独立引入

实际配置

多入口打包配置

多入口配置其实比较简单,在我们的entry对象中手动添加即可,如下:

  1. module.exports = {
  2. configureWebpack: {
  3. entry: {
  4. 'xl-number-input: '/Users/administrator/Documents/program/julive_npm/jl_ui/packages/xl-number-input/index.js',
  5. 'xl-image-preview': '/Users/administrator/Documents/program/julive_npm/jl_ui/packages/xl-image-preview/index.js'
  6. },
  7. },
  8. }

但是这么写的话,每次新增一个组件就要去一行,灵活性很低,如果开发人员只是添加了组件没有进行打包配置,会导致宿主环境引入失败,所以这里建议用代码的方式自动帮我们导入entry
封装一个方法,用于寻找组件库文件夹下面的所有组件,找到组件库名称并且对应上路径,当然,前提是你的组件库目录都保持一致,否则寻找不成功

  1. const fs = require('fs')
  2. const path = require('path')
  3. const join = path.join
  4. const resolve = (dir) => path.join(__dirname, '../', dir)
  5. getComponentEntries(path) {
  6. // 获取到组件代码所在的文件夹目录下所有文件名称
  7. let files = fs.readdirSync(resolve(path));
  8. const componentEntries = files.reduce((ret, item) => {
  9. // 将文件名转成路径
  10. const itemPath = join(path, item);
  11. const isDir = fs.statSync(itemPath).isDirectory();
  12. if (isDir) {
  13. // 将index拼接到地址后
  14. ret[item] = resolve(join(itemPath, 'index.js'));
  15. }
  16. return ret;
  17. }, {});
  18. return componentEntries;
  19. }

有这个方法后,我们把方法在entry中执行一下

  1. module.exports = {
  2. configureWebpack: {
  3. entry: {
  4. ...getComponentEntries('packages')
  5. },
  6. }
  7. }

现在有一个问题是,我们导出所有组件的index.js,实际上是不需要用文件夹包裹起来的,所以我们在entry中单独引入

  1. module.exports = {
  2. configureWebpack: {
  3. entry: {
  4. '/': resolve('packages/index.js'),
  5. ...getComponentEntries('packages')
  6. },
  7. }
  8. }

抽离css

最后我们注意把css也单独给每一个组件抽离出来,方便引入的时候单独引入某一个组件的样式

  1. module.exports = {
  2. configureWebpack: {
  3. ...
  4. },
  5. css: {
  6. sourceMap: true,
  7. extract: {
  8. filename: '[name]/style.css'
  9. }
  10. }
  11. }

最后打包后看到的效果如图:
image.png

使用

在宿主项目中下载我们的组件库,然后按需引入我们的组件,如下,可以正常使用

  1. import { JlIconSvg } from 'jl_ui';
  2. import 'jl_ui/lib/jl-icon-svg/style.css';

但是向上面那样写,每次都需要手动引入对应的css文件,比较麻烦,我们发现element-ui或者是ant-design都使用插件来引入,所以我们也学习一下,下载babel-plugin-import插件,在babel的配置文件中加入:

  1. module.exports={
  2. "plugins": [
  3. ["component",
  4. {
  5. "libraryName": "element-ui",
  6. "styleLibraryName": "theme-chalk"
  7. }
  8. ],
  9. [
  10. "import",
  11. {
  12. "libraryName": "jl_ui",
  13. "style": (name) => {
  14. if (name === "jl_ui/lib/xl-number-input") {
  15. return false;
  16. }
  17. return `${name}/style.css`;
  18. }
  19. },
  20. ]
  21. ]
  22. }

注意:
看上面的代码,发现xl-number-input组件做了特殊处理,这是因为这个组件没有单独添加样式,也就是打包后,这个组件的文件夹下是没有style.css文件的,这样会导致babel-plugin-import报错,它找不到对应组件的css,所以我们需要手动将xl-number-input组件的css返回false,代码不需要引入