普通视图

发现新文章,点击刷新页面。
昨天以前首页

如何从0到1搭建基于antd的monorepo库——使用rollup进行打包、lerna进行版本管理和发布(六)

作者 Kincy
2025年4月17日 09:58

文章系列

上一章:如何从0到1搭建基于antd的monorepo库——使用dumi进行文档展示(五)

作者有话说

目前已经实现了一部分功能,源代码在 github,欢迎大家 Star 和 PR,一些待实现的功能都在 issue 中,感兴趣的同学可以一起加入进来。

看完这个系列可以收获什么:

  1. 如何使用 pnpm workspace + lerna 搭建 monorepo 仓库
  2. antd 的单个组件怎么进行文件结构的设计
  3. 基于 antd form 实现一个 Json 渲染表单
  4. antd 的打包方式以及如何使用 rollup 实现
  5. 如何发布 monorepo 包到 npm

前瞻

组件库技术选型:

  1. pnpm 10
  2. node 20
  3. lerna 8
  4. react 18
  5. antd 5
  6. dumi 2

正片开始

安装依赖

pnpm add -D rollup @rollup/plugin-typescript rollup-plugin-dts @rollup/plugin-babel @rollup/plugin-commonjs @rollup/plugin-node-resolve rollup-plugin-peer-deps-external rollup-plugin-postcss rollup-plugin-terser

配置 rollup

在子包根目录下新增 rollup.config.mjs 文件。

import babel from '@rollup/plugin-babel';
import commonjs from '@rollup/plugin-commonjs';
import { nodeResolve } from '@rollup/plugin-node-resolve';
import typescript from '@rollup/plugin-typescript';
import { defineConfig } from 'rollup';
import peerDepsExternal from 'rollup-plugin-peer-deps-external';
import postcss from 'rollup-plugin-postcss';
import { terser } from 'rollup-plugin-terser';

const DIR_MAP = {
  ESM: 'es',
  CJS: 'lib',
  UMD: 'dist',
};

// 处理 Ant Design 样式按需加载
const antdStyles = () => ({
  name: 'antd-styles',
  transform(code, id) {
    if (/node_modules\/antd/.test(id) && id.endsWith('.js')) {
      return code.replace(/import\s+['"].*\.less['"]/, '');
    }
    return null;
  },
});

const baseConfig = (tsConfig) => ({
  external: ['react', 'react-dom', 'antd', 'tslib'],
  input: 'src/index.ts',
  plugins: [
    peerDepsExternal(),
    nodeResolve({
      modulesOnly: true,
      extensions: ['.ts', '.tsx', '.js', '.jsx'],
      preferBuiltins: true,
    }),
    commonjs(),
    typescript(tsConfig),
    babel({
      babelHelpers: 'bundled',
      extensions: ['.ts', '.tsx'],
      presets: [
        '@babel/preset-react',
        ['@babel/preset-env', { modules: false }],
      ],
    }),
    postcss({
      extract: true, // 分离 CSS 文件
      modules: false,
      use: ['less'],
      minimize: true,
    }),
    antdStyles(),
  ],
});

const esmConfig = {
  ...baseConfig({
    declaration: true,
    declarationDir: DIR_MAP.ESM,
  }),
  output: {
    dir: DIR_MAP.ESM,
    format: 'esm',
    preserveModules: true,
    preserveModulesRoot: 'src',
  },
};

const cjsConfig = {
  ...baseConfig({
    declaration: true,
    declarationDir: DIR_MAP.CJS,
  }),
  output: {
    dir: DIR_MAP.CJS,
    format: 'cjs',
    exports: 'named',
    preserveModules: true,
    preserveModulesRoot: 'src',
  },
};

const umdConfig = {
  ...baseConfig(),
  output: [
    {
      file: DIR_MAP.UMD + '/index.js',
      format: 'umd',
      name: 'KcComponents',
      globals: {
        react: 'React',
        'react-dom': 'ReactDOM',
        antd: 'antd',
      },
      sourcemap: true,
    },
    {
      file: DIR_MAP.UMD + '/index.min.js',
      format: 'umd',
      name: 'KcComponents',
      plugins: [terser()],
      sourcemap: true,
    },
  ],
};

export default defineConfig([esmConfig, cjsConfig, umdConfig]);

新增 build 脚本

在子包 package.json 中新增脚本。

{
  "scripts": {
    "build": "rollup -c"
  }
}

在父包 package.json 中新增脚本。

{
  "scripts": {
    "build": "pnpm clean:dist && lerna run build",
    "clean": "lerna clean --yes",
    "clean:dist": "lerna exec -- rm -rf dist es lib"
  }
}

打包构建

在父包或者子包运行 pnpm build 即可进行打包,产物有三份,分别用于 ESM、CMJ、UMD:

image.png

lerna 版本管理

在父包 package.json 中新增脚本。

{
  "scripts": {
    "lv": "lerna version"
  }
}

运行 pnpm lv 会进入一个对话命令行,选择你想要的版本。

image.png

lerna 统一发布

在子包 package.json 中新增内容。

{
  "sideEffects": false,
  "main": "lib/index.js",
  "unpkg": "dist/index.min.js",
  "module": "es/index.js",
  "typings": "es/index.d.ts",
  "files": [
    "es",
    "lib",
    "dist"
  ],
  "publishConfig": {
    "access": "public",
    "registry": "https://registry.npmjs.org/"
  }
}

在父包 package.json 中新增内容。

{
  "private": true,
  "scripts": {
    "lp": "lerna publish from-git"
  }
}

在父包根目录下运行 pnpm lp 即可发布 npm。

image.png

image.png

注意事项

  1. 在发布前需要先登录 npm
  2. 发布 monorepo 包需要在 npm 组织中发布,且组织名字为 @ 到 / 之间的内容

总结

至此,一个基于 antd 二次封装且使用 pnpm workspace + lerna 的 monorepo 组件库已经完成,想要查看更多内容可以在我的项目查看,如果感兴趣想要一起开发可以查看 issue,里面会有一些未来准备实现的功能。

如果想提前知道更多内容可以直接查看github,欢迎大家 Star 和 PR,如有疑问可以评论或私信。

❌
❌