close
  • 简体中文
  • Solid

    在本文档中,你将学习如何使用 Rslib 构建 Solid 组件库。你也可以在 示例 中查看 Solid 相关演示项目。

    创建 Solid 项目

    你可以使用 create-rslib 创建 Rslib + Solid 项目。只需执行以下命令:

    npm
    yarn
    pnpm
    bun
    npm create rslib@latest

    然后,当提示 "Select template" 时选择 Solid

    在现有 Rslib 项目中使用

    开发 Solid 组件库时,需要在 rslib.config.ts 中将 target 设置为 "web"。这一点至关重要,因为 Rslib 默认将 target 设置为 "node"

    要编译 Solid JSX,你需要同时注册 @rsbuild/plugin-babel@rsbuild/plugin-solid 插件。Solid 插件使用 babel-preset-solid 将 JSX 转换为 Solid 的运行时 DOM 表达式。

    package.json
    {
      "devDependencies": {
        "@rsbuild/plugin-babel": "^2.0.0",
        "@rsbuild/plugin-solid": "^1.2.2",
        "solid-js": "^1.9.9"
      },
      "peerDependencies": {
        "solid-js": "^1.8.0"
      }
    }
    rslib.config.ts
    import { pluginBabel } from '@rsbuild/plugin-babel'; 
    import { pluginSolid } from '@rsbuild/plugin-solid'; 
    import { defineConfig } from '@rslib/core';
    
    export default defineConfig({
      lib: [
        {
          bundle: false,
          dts: true,
          plugins: [
            pluginBabel({
              include: /\.(?:jsx|tsx)$/,
            }),
            pluginSolid(),
          ],
        },
      ],
      output: {
        target: 'web',
      },
    });

    输出产物

    Solid 组件库通常会同时发布两类产物:

    • 预编译产物:JSX 已经通过 babel-preset-solid 转换为 Solid 的运行时调用(例如 template()insert() 等)。使用该组件库的应用项目可以直接引入这类产物,无需额外配置 Solid JSX 编译能力。
    • 保留 JSX 的源码产物:库构建阶段不进行 Solid 编译,而是保留原始 JSX 语法,并通过 package.json 中的 "solid" condition name(条件名称)暴露给应用侧工具链。

    当使用该组件库的应用项目具备 Solid JSX 编译能力时(例如安装了 @rsbuild/plugin-solid 的 Rsbuild 项目),模块解析会命中 "solid" condition name,从而读取保留 JSX 的源码产物,并根据应用自身的运行目标重新编译:浏览器端应用会编译为客户端 DOM 渲染代码(generate: 'dom'),SSR 框架则会编译为服务端渲染代码(generate: 'ssr')。未配置 Solid JSX 编译能力的应用项目会回退到预编译的 "import" 入口。

    rslib.config.ts
    import { pluginBabel } from '@rsbuild/plugin-babel';
    import { pluginSolid } from '@rsbuild/plugin-solid';
    import { defineConfig } from '@rslib/core';
    
    export default defineConfig({
      lib: [
        {
          // 将 JSX 编译为 Solid 运行时调用,例如 template()、insert() 和 delegateEvents()。
          bundle: false,
          dts: true,
          plugins: [
            pluginBabel({
              include: /\.(?:jsx|tsx)$/,
            }),
            pluginSolid(),
          ],
        },
        {
          // 为 "solid" condition name 保留 JSX 语法。
          bundle: false,
          output: {
            filename: {
              js: '[name].jsx',
            },
          },
          tools: {
            swc: {
              detectSyntax: 'auto',
              jsc: {
                transform: {
                  react: {
                    // 保持输出中的 JSX 语法。
                    runtime: 'preserve',
                  },
                },
              },
            },
            rspack: {
              module: {
                parser: {
                  javascript: {
                    // 允许 Rspack 解析保留的 JSX。
                    jsx: true,
                  },
                },
              },
            },
          },
        },
      ],
      output: {
        target: 'web',
      },
    });

    然后在 package.json 中配置 "exports" 字段:

    package.json
    {
      "exports": {
        ".": {
          "solid": "./dist/index.jsx",
          "types": "./dist/index.d.ts",
          "import": "./dist/index.js"
        }
      }
    }

    TypeScript

    对于使用 TypeScript 的 Solid 项目,在 tsconfig.json 中设置 "jsx": "preserve""jsxImportSource": "solid-js"

    tsconfig.json
    {
      "compilerOptions": {
        "jsx": "preserve",
        "jsxImportSource": "solid-js"
      }
    }

    SSR

    大多数 Solid 组件库默认不会单独发布 SSR 构建。下游框架通常会解析 "solid" condition name,拿到保留 JSX 的源码输出,再按自己的目标编译。

    如果你确实需要预编译的 SSR 产物,可以通过 pluginSolidsolid.generate 选项配置为 'ssr'

    rslib.config.ts
    export default defineConfig({
      lib: [
        // ... 已有的 compiled 和 source 入口
        {
          id: 'server',
          bundle: false,
          output: {
            distPath: {
              root: './dist/server',
            },
          },
          plugins: [
            pluginBabel({
              include: /\.(?:jsx|tsx)$/,
            }),
            pluginSolid({
              solid: {
                generate: 'ssr',
                hydratable: true,
              },
            }),
          ],
        },
      ],
    });