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

文章系列

上一章:如何从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

正片开始

安装依赖

bash 复制代码
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 文件。

js 复制代码
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 中新增脚本。

json 复制代码
{
  "scripts": {
    "build": "rollup -c"
  }
}

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

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:

lerna 版本管理

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

json 复制代码
{
  "scripts": {
    "lv": "lerna version"
  }
}

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

lerna 统一发布

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

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 中新增内容。

json 复制代码
{
  "private": true,
  "scripts": {
    "lp": "lerna publish from-git"
  }
}

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

注意事项

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

总结

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

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

相关推荐
华玥作者8 小时前
[特殊字符] VitePress 对接 Algolia AI 问答(DocSearch + AI Search)完整实战(下)
前端·人工智能·ai
Mr Xu_8 小时前
告别冗长 switch-case:Vue 项目中基于映射表的优雅路由数据匹配方案
前端·javascript·vue.js
前端摸鱼匠8 小时前
Vue 3 的toRefs保持响应性:讲解toRefs在解构响应式对象时的作用
前端·javascript·vue.js·前端框架·ecmascript
lang201509288 小时前
JSR-340 :高性能Web开发新标准
java·前端·servlet
好家伙VCC9 小时前
### WebRTC技术:实时通信的革新与实现####webRTC(Web Real-TimeComm
java·前端·python·webrtc
摘星编程10 小时前
React Native鸿蒙版:Image图片占位符
react native·react.js·harmonyos
未来之窗软件服务10 小时前
未来之窗昭和仙君(六十五)Vue与跨地区多部门开发—东方仙盟练气
前端·javascript·vue.js·仙盟创梦ide·东方仙盟·昭和仙君
嘿起屁儿整10 小时前
面试点(网络层面)
前端·网络
VT.馒头10 小时前
【力扣】2721. 并行执行异步函数
前端·javascript·算法·leetcode·typescript
phltxy11 小时前
Vue 核心特性实战指南:指令、样式绑定、计算属性与侦听器
前端·javascript·vue.js