组件库打包---答疑篇

组件库打包---答疑篇

九月 27, 2021 本文共计: 1.2k 字 预计阅读时长: 4分钟

作为九月的收尾文章,分享一下我已经应用于若干生产项目的组件库打包方案以及难题解决~

以下的每个问题点,都以Topic的形式展开讲述。

组件库的样式怎么解决?

其实在之前的文章中有分享过组件库的样式解决方案,但是还是有一些问题的,不过经历了一个多星期的钻研尝试,总算是找到了样式解决方案的最优解~

怎么处理第三方样式?

拿目前的antd样式来看,为了避免打包过程中产生额外的三方库样式赘余,所以我们使用按需&peer依赖方案

具体对应到rollup配置里,我们可能会这么做:

const external = [
    'react',
    'react/jsx-runtime',
    'antd',
];

export default {
    // 省略若干配置
    external,
    // 省略若干配置
}

其次,对应到babel.config中,我们可能会这么做:

module.exports = {
    presets: [
        ['@babel/preset-env', { loose: true }],
        [
            '@babel/preset-react',
            {
                runtime: 'automatic',
            },
        ],
    ],
    plugins: [
        '@babel/plugin-transform-runtime',
        // 下面的配置是要点!
        [
            'import',
            {
                libraryName: 'antd',
                libraryDirectory: 'es',
                style: true,
            },
        ],
    ],
};

告诉工具,我们的打包配置是按需的,其次,我们的样式走的是less文件。为了保证不和项目中的antd css产生冲突,那么我们同样需要在项目中做相同的处理

项目中的配置

{
  "babel": {
    "plugins": [
      [
        "@babel/plugin-proposal-decorators",
        {
          "legacy": true
        }
      ],
      [
        "import",
        {
          "libraryName": "antd",
          "libraryDirectory": "es",
          "style": true
        }
      ]
    ],
    "presets": [
      "react-app"
    ]
  }
}

当然这里是需要借助webpackless loader做一些事情的:

需要在 less options中添加如下配置:

{
    lessOptions: {
        javascriptEnabled: true
    }
}

保证和组件库的配置依赖保持一致,让组件库的按需es能够找得到项目中的按需样式,这样就可以做到样式不丢失

多个组件包的管理怎么处理

工具

最常见的使用工具,当然是lerna了,我们可以配置lerna

lerna的配置详细规则,这里不再做过多的阐述,重点我们去解决下面的问题:

lerna管理多个包,怎么处理包的碰撞log,也就是不相关的包会触发版本升级

# **Note:** Version bump only for package xxx

上面的内容就是包版本发生碰撞之后的changelog内容,怎么解决呢?

我个人想了一个比较好的方案:

解决痛点:lerna只能一次性控制所有的包打包构建,那么单独精确控制呢?

思路:提供可视化的打包选择shell,提供更加语意化的commit信息

第一步

解析命令行:

const { Command } = require('commander');

program.parse(process.argv);
第二步

获取lerna管理项目的所有包信息:

const shell = require('shelljs');

const res = shell.exec(` lerna ls --json`, { silent: true });

上面的silent的意思是,控制命令行执行不输出语句,因为我们更希望我们的shell是干净的。

第三步

命令行答询

const inquirer = require('inquirer');

inquirer
    .prompt([
        {
            type: 'checkbox',
            message: 'Please select your want publish packages',
            name: 'packages',
            choices: [new inquirer.Separator(' = Lerna All Packages = '), ...JSON.parse(res.stdout)],
        },
    ])
    .catch(error => {
        if (error.isTtyError) {
            // Prompt couldn't be rendered in the current environment
        } else {
            // Something else went wrong
        }
    });

上面的文档,其实在人家github仓库中已经给了案例了,这里做一个传送门:

传送门 : https://github.com/SBoudrias/Inquirer.js/tree/master/packages/inquirer/examples

选择自己适合的方案去做。

第四步

借助lerna命令去遍历精确打包;

const inquirer = require('inquirer');

inquirer
    .prompt([
        {
            type: 'checkbox',
            message: 'Please select your want publish packages',
            name: 'packages',
            choices: [new inquirer.Separator(' = Lerna All Packages = '), ...JSON.parse(res.stdout)],
        },
    ])
    .then(answers => {
        answers.packages?.forEach(item => {
            shell.exec(`lerna run --scope ${item} build`);
        });
    })

其实lerna的官方文档里有说明lerna run --scope [包名] [script 命令] 可以做到精确控制某个包的命令执行,那我们遍历就可以做一个宏观并行处理

第五步

借助commitizen控制发布信息的规范化

const path = require('path');

const starderedCommmit = () => {
    shell.exec(`git add .`);
    const bootstrap = require('commitizen/dist/cli/git-cz').bootstrap;
    bootstrap({
        cliPath: path.join(__dirname, '../node_modules/commitizen'),
        config: {
            path: 'cz-conventional-changelog',
        },
    });
};

这个东西呢,在的官方文档里也有写:

传送门 : https://www.npmjs.com/package/@marionebl/git-cz

解释一下,为什么这么做呢?

因为,这么做的原因是,在shell中如果执行git cz是无法触发交互的,是因为shell开启了子进程做的命令执行。

最后,我们想实现的效果可能就是这样:

小结

最后,小结一下吧,其实每一个问题都是可以解决的,我们欠缺的并不是实现技术的细节,而是一个思路。

有思路就代表可行,或者可以尝试下,这样我们有路才会选择去走还是坐飞机,还是坐火车,骑车……