打包器集成

用 vite 或 tsdown 把插件打包成 karin 生产可用的纯 JS 产物,ktrBuildPlugin 自动完成注册表同步和 CSS 编译

开发时写的 .tsx 组件和 Tailwind CSS,Node 直接跑不了——发布前必须构建。本页介绍两种生产构建模式:下游打包器集成模式,以及由 ktr 自己完成运行时打包的独立构建模式

下面的 Vite/tsdown 集成模式会产出三样:插件逻辑 JS(src/**/*.ts)、模板注册表 JS(.ktr/template-registry.ts)、模板样式 CSS(style.css),全部落到打包器自己的 outDir(下面示例用 karin 惯例的 lib/,叫什么由你的打包配置决定)。独立构建的产物协议不同,CSS 内嵌在 index.mjs,请以独立构建页面为准。

下游本身已经使用 Vite 或 tsdown 时,在打包配置里挂 ktrBuildPlugin()@karinjs/template-react/plugin)即可。它会在 buildStart 自动刷新 .ktr 注册表,在 generateBundle 把 CSS 编译后以 asset 形式注入打包器自己的 bundle——style.css 会出现在打包器自身的输出文件列表里。下游不想维护打包器入口时,使用独立的 ktr build,详见独立构建模式

方式一:Vite(推荐)

ktr dev 的开发服务器就是 Vite,生产和开发使用相同的 TSX 与 CSS 语义。下游生产构建只需要挂 ktrBuildPlugin();Vite 自身可以转换 TSX,而模板 CSS 会在插件的 generateBundle 阶段通过 ktr 内部的 Tailwind/Vite 管线编译,并作为 asset 注入外层 bundle。

vite.config.ts
import {  } from 'vite'
import {  } from '@karinjs/template-react/plugin'

export default ({
  // ktrBuildPlugin:buildStart 刷新 .ktr 注册表,generateBundle 编译 CSS 并注入 bundle(随输出表列出)
  : [()],
  // 整包模式:除 node-karin(宿主提供)外全部内联,生产环境零安装
  : {
    : true,
    : ['node-karin']
  },
  : {
    : true, // 产物跑在 karin 宿主(Node),不是浏览器
    : 'node18',
    : 'lib',
    : {
      : {
        // 你的插件入口,按需增删(karin 约定 lib/apps 结构)
        'apps/template': 'src/apps/template.ts',
        // createTemplateRenderer 生产态自动发现这个模板注册表
        'template-registry': '.ktr/template-registry.ts'
      },
      : ['es']
    },
    : {
      : [/^node:/, 'node-karin']
    }
  }
})
vite build

CSS 想走别的管线时传 ktrBuildPlugin({ css: false })

什么时候需要额外插件?

@vitejs/plugin-react 主要用于 Vite 开发服务器中的 React Fast Refresh、React Compiler 或自定义 Babel/Oxc 转换;只执行这里的 Node SSR 生产构建时不是必需项。@tailwindcss/vite 只在宿主自己的 Vite 模块图还直接导入其他 Tailwind CSS 时才需要;固定的 ktr/template/style.css 已由 ktrBuildPlugin() 内部编译,不要重复挂载。

模板 CSS 入口使用标准的 @import 'tailwindcss';,并保留显式 @source './**/*.{ts,tsx}';。ktr 会在内部构建阶段限制 Tailwind 只扫描这些显式源码,不需要在下游 CSS 中写 Tailwind 专用的 import modifier。

模板 CSS 的内容完全由 ktr 内部的独立 Vite 管线决定(不读下游的 vite.config.ts):CSS 里 url() 引用的静态资源按 Vite 默认的 assetsInlineLimit 处理——4KB 以下内联为 base64,超过的输出为 assets/[name]-[hash] 文件并随 CSS 一起注入 bundle。想调整这类 行为(比如加大内联阈值、追加 PostCSS 插件),在 karin.template.tsvite 字段里扩展内层 构建配置,而不是改外层的打包配置;外层 vite.config.ts 只决定 CSS 产物的落盘位置(build.outDir)和它在输出列表里的展示。

方式二:tsdown(备选)

pnpm add -D tsdown
tsdown.config.ts
import {  } from 'tsdown'
import {  } from '@karinjs/template-react/plugin'

export default ({
  : {
    // 入口路径必须带 ./ 前缀,否则会被当成 npm 包名解析
    'apps/template': './src/apps/template.ts',
    'template-registry': './.ktr/template-registry.ts'
  },
  : [()],
  : ['esm'],
  : 'node',
  : 'node18',
  : 'lib',
  // 注册表发现按 .js 文件名查找,ESM 产物也要固定为 .js,不要用默认的 .mjs
  : () => ({ : '.js', : '.d.ts' }),
  : {
    // 只有 node-karin(宿主提供)保持外部
    : ['node-karin']
  }
})
tsdown

mock-registry 不是生产必需入口

正常生产渲染的数据由调用方直接传给渲染函数,createTemplateRenderer() 只会加载 template-registry.js,不会读取 mock。 只有生产代码明确调用 loadMockRegistry()、需要把示例数据作为运行时功能发布时,才额外加入 'mock-registry': './.ktr/mock-registry.ts'。开发面板会直接读取模板旁的 mock.tsdata/*.json,也不依赖打包后的 mock-registry.js

验证

构建后在 karin 里触发一次模板渲染指令,能正常出图即链路完整。ktr 的集成测试会用同一份含 React Hook 的 TSX 模板分别执行 Vite 和 tsdown 构建,并比较最终完整 HTML,确保模板内容、主题上下文和编译后 CSS 一致。

两条硬性要求:node-karin 必须保持外部(由宿主提供);产物里只能有一份 React(link 本地 ktr 开发时出现两份时,用 resolve.dedupe: ['react', 'react-dom'] 去重)。

渲染器怎么找到产物

createTemplateRenderer 按约定自动发现,不需要配置:

  • 注册表:渲染器自身跑在下游 bundle 里时(生产构建插件在产物 chunk 注入 __KTR_BUNDLED__ 标记)直接用打包产物,不读 .ktr 源码也不加载 karin.template.ts;否则(ktr 作为 npm 包被开发态引用).ktr 源文件优先,缺失时回退产物。产物按 bundledDir 选项 → package.jsonmain/exports 入口目录 → 根目录扫描发现。
  • 样式:开发态读 dev server 实时编译的缓存,生产态默认按 karin 惯例读 lib/style.css。产物 CSS 与 dev 缓存同时存在时,resolveTemplateStyle 按 mtime 取较新的一份——重新构建后又跑过 dev server 时缓存会胜出,反之则用新构建的产物,避免两边不同步。

产物目录不叫 lib/ 时显式指定:

const  = (import.meta., {
  : 'dist', // 注册表产物目录
  : { : .('dist/style.css') } // CSS 产物路径
})

On this page