组件库的一种打包方式的探索

285 阅读4分钟

简介

最近看了Svelte的小黑子ui组件库打包方式有点小想法,索性自己探索一下
主要实现的功能是每个组件单独打包 单独发包

启动

  1. 首先包采用pnpm monorepo的管理方式自行百度教程不少
    pnpm-workspace.yaml配置如下
packages:
  - packages/*
  - playground/*
  - docs
  - internal/*
  1. 然后新建internal文件夹做内部包管理,在改文件夹下新建build文件夹
    package.json
"bin": {
    "bee": "./index.js"
  },

在package.json中增加如上配置,意为该包提供的命令,在安装时会讲命令名称bee安装到node_modules/.bin文件夹下 index.js

try {
  require('./dist/index.cjs')
} catch (error) {
  console.log(error);
}

引用打包后的文件 3. 然后下载必须的依赖

pnpm i @rollup/plugin-node-resolve @rollup/plugin-commonjs rollup-plugin-esbuild vite-plugin-solid cac rollup unbuild -D
  1. 编写打包 build.config.ts配置如下
import { defineBuildConfig } from 'unbuild'

export default defineBuildConfig({
  entries: ['src/index'],
  clean: true,
  declaration: true,
  rollup: {
    emitCJS: true
  },
})
  1. 编写入口文件 src/index.ts
import cac from 'cac';
import { build } from './build';

const cli = cac('bee');

cli.command('[root]', 'Build the project')
  .action(() => {
    console.log('hello bee...')
  })

cli.command('build', 'build mode')
  .option('-c, --config', 'Production mode')
  .option('-i, --input', 'input path')
  .action(async (ars) => {
    const root = process.cwd();
    await build(root, ars);
  })

cli.help();
cli.parse();

上述代码主要实现bee命令 bee build 其参数为config配置文件、input入口文件路径 更多api可以去npmjs搜索cac
7. 编写build脚本 src/build.ts

import commonjs from '@rollup/plugin-commonjs';
import nodeResolve from '@rollup/plugin-node-resolve';
import path from 'node:path';
import { InputPluginOption, OutputOptions, RollupBuild, rollup } from 'rollup';
import solidPlugin from 'vite-plugin-solid';
import { DEFAULT, generateExternal, resolveBuildConfig, target } from './ustils';
import esbuild from 'rollup-plugin-esbuild';
export interface Options {
  /**
   * @description
   */
  input?: string;
  sourceMap?: boolean;
  dts?: boolean;
  dtsDir?: string;
  tsconfig?: string;
}

export async function build(root: string, options: Options = {}) {
  const {
    input = DEFAULT,
    sourceMap = false,
  } = options;
  const inputPath = path.resolve(root, input)
  const plugins = [
    nodeResolve({ extensions: ['.js', '.jsx', '.ts', '.tsx'] }),
    commonjs(),
    solidPlugin(),
    esbuild({
      sourceMap,
      target,
      minify: true,
    }),
  ] as unknown as InputPluginOption[];

  const bundle = await rollup({
    input: inputPath,
    plugins,
    treeshake: true,
    external: await generateExternal(root),
  })

  await writeBundles(bundle, resolveBuildConfig(root).map(([module, config]): OutputOptions => {
    return {
      format: config.format,
      dir: config.output.path,
      exports: module === 'cjs' ? 'named' : undefined,
      sourcemap: sourceMap,
    }
  }))
}

async function writeBundles(bundle: RollupBuild, options: OutputOptions[]) {
  return Promise.all(options.map(option => bundle.write(option)))
}

上述代码主要实现对rollup打包逻辑的一个封装,从命令行中获取参数,然后拼接入口文件路径,排除dependencies包含的三放包,使用esbuild加速、使用node-resolve插件解析三方包的引用。最后输出到dist以esm的格式

  1. 创建软连接
    下文中的@bees-ui/build为internal/build对应的包名
pnpm i @bees-ui/build -wD

这样在项目根目录下的node_modules/.bin可以找到bee对应的命令
9. 在packages下新建button文件夹
package.json增加如下片段

"scripts": {
    "build": "pnpm bee build"
},

因为bee命令在根目录安装如果使用npm或者yarn会找不到命令此处涉及到node包管理中命令的寻找逻辑,详情可自行搜索

验证

  1. 编写代码 src/index.ts
import { button } from './button';
import { customElement } from 'solid-element';

customElement('solid-button', button);

src/button.tsx

export const button = () =>{
    return (
      <button>Click me</button>
    )
}

使用solidjs编写button组件然后使用solid-element注册为web component
2. 运行build命令查看是否生产dist/es 与lib。在package.json增加代码表述包内容 package.json

  "main": "./dist/lib/index.js",
  "module": "./dist/es/index.js",
  "types": "./dist/types/index.d.ts",
  "exports": {
    ".": {
      "default": "./dist/es/index.js",
      "require": "./dist/lib/index.js",
      "import": "./dist/es/index.js",
      "types": "./dist/types/index.d.ts"
    }
  },
  "files": [
    "dist"
  ],
  1. 新建playground然后用create-vite脚手架新建几个项目,项目根目录下运行
pnpm i @bees-ui/button

使用就在对应页面引入

import '@bees-ui/button'

然后将注册的组件名solid-button称当作普通的H5标签用就行

涉及到的包与其作用

  1. @rollup/plugin-node-resolve

  2. @rollup/plugin-commonjs

    • 作用:将 CommonJS 模块转换为 ES6 模块,以便在 Rollup 中使用。
    • 文档:rollup-plugin-commonjs
  3. rollup-plugin-esbuild

    • 作用:使用 esbuild 进行快速的 Rollup 转译,以提高构建性能。
    • 文档:rollup-plugin-esbuild
  4. vite-plugin-solid

    • 作用:Vite 插件,用于支持 Solid.js 在 Vite 中的开发。
    • 文档:vite-plugin-solid
  5. cac

    • 作用:一个简单的命令行解析库,通常用于创建命令行工具。
    • 文档:cac
  6. rollup

    • 作用:JavaScript 模块打包工具,用于将模块打包成浏览器可用的格式。
    • 文档:Rollup
  7. unbuild

    • 作用:unbuild 是一个基于 rollup 的打包工具,使用 jiti 开发过程中只需要一次编译之后的改动都可以实时同步调试。
    • 文档:unbuild
  8. solid-element

    • 作用:Solid.js 的一部分,用于创建基于 Web Components 标准的组件。
    • 文档:solid-element
  9. solid-js

    • 作用:现代的 JavaScript 框架,用于构建可维护且高性能的前端应用程序。
    • 文档:Solid.js

最后

代码在github.com/ikunOrg/bee…
如果觉得写的还不错请点赞+收藏
新人多多关照哈哈 如果你想变强b站 掘金搜索小满zs!