打包器集成
用 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。
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 buildCSS 想走别的管线时传 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.ts 的 vite 字段里扩展内层
构建配置,而不是改外层的打包配置;外层 vite.config.ts 只决定 CSS 产物的落盘位置(build.outDir)和它在输出列表里的展示。
方式二:tsdown(备选)
pnpm add -D tsdownimport { } 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']
}
})tsdownmock-registry 不是生产必需入口
正常生产渲染的数据由调用方直接传给渲染函数,createTemplateRenderer() 只会加载 template-registry.js,不会读取 mock。
只有生产代码明确调用 loadMockRegistry()、需要把示例数据作为运行时功能发布时,才额外加入 'mock-registry': './.ktr/mock-registry.ts'。开发面板会直接读取模板旁的 mock.ts 和 data/*.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.json的main/exports入口目录 → 根目录扫描发现。 - 样式:开发态读 dev server 实时编译的缓存,生产态默认按 karin 惯例读
lib/style.css。产物 CSS 与 dev 缓存同时存在时,resolveTemplateStyle按 mtime 取较新的一份——重新构建后又跑过 dev server 时缓存会胜出,反之则用新构建的产物,避免两边不同步。
产物目录不叫 lib/ 时显式指定:
const = (import.meta., {
: 'dist', // 注册表产物目录
: { : .('dist/style.css') } // CSS 产物路径
})