目标与何时使用
将模板、种子 JSON、Logo 以及其他随插件包分发的只读文件作为打包资源。应用运行期间创建或更新的内容使用插件数据目录。
- 后端只读 — plugins/<name>/backend/assets/
- 前端 URL — PluginAssets.network(metadata, relativePath)
- 运行时写入 — AppFolder.getPluginDataFolder(metadata.name),不是 asset 目录
1. 前置条件
需要 metadata.name / pluginVersion 一致的插件,以及 AppFolder / PluginAssets 辅助。
- module.metadata.json — name 与 pluginVersion 与已安装包一致
- 后端 — @quan-erp/shared-backend-core(AppFolder)
- 前端 — @quan-erp/shared-frontend-core(PluginAssets)
- 更改打包资源后重建并重新安装(或 watch 刷新)
2. 后端资源
只读文件放在 plugins/<name>/backend/assets/。CLI 会打包到 available/installed 插件中。用 AppFolder 解析路径——不要硬编码 APP_DATA_FOLDER。
- 源码 — plugins/<name>/backend/assets/…
- 运行时路径 — getPluginAssetFolder(name, version)
- 可写运行时文件 — getPluginDataFolder(name)
- 安装后不要写入 asset 目录 — 随版本替换
SHsource layout
1plugins/<plugin-name>/
2└── backend/
3 ├── assets/
4 │ ├── invoice-template.html
5 │ └── seed/
6 │ └── defaults.json
7 └── src/TSXread bundled file
1import { AppFolder } from "@quan-erp/shared-backend-core";
2import metadata from "../../module.metadata.json" with { type: "json" };
3import fs from "node:fs/promises";
4import path from "node:path";
5
6const assetDir = AppFolder.getPluginAssetFolder(
7 metadata.name,
8 metadata.pluginVersion,
9);
10const template = await fs.readFile(
11 path.join(assetDir, "invoice-template.html"),
12 "utf8",
13);TSXwrite runtime data
const dataDir = AppFolder.getPluginDataFolder(metadata.name);
await fs.mkdir(dataDir, { recursive: true });
await fs.writeFile(path.join(dataDir, "export.csv"), csv, "utf8");3. 前端资源
用 @quan-erp/shared-frontend-core 的 PluginAssets.network(metadata, path) 为 UI 构建绝对 URL。保持相对路径稳定,并与打包内容对齐。
- 从 @quan-erp/shared-frontend-core 导入 PluginAssets
- 传入插件其他位置使用的同一 module.metadata.json
- path 相对于栈所暴露的打包前端 / 资源树
TSXPluginAssets
1import { PluginAssets } from "@quan-erp/shared-frontend-core";
2import metadata from "../module.metadata.json" with { type: "json" };
3
4export function PluginLogo() {
5 const src = PluginAssets.network(metadata, "images/logo.png");
6 return <img src={src} alt={metadata.name} />;
7}4. 验证与规则
- watch / build 后 available-plugins(Install 后 installed-plugins)中存在资源
- getPluginAssetFolder 可解析,并对已知相对路径 readFile 成功
- PluginAssets.network 在浏览器中返回可加载 URL
- 资源随插件包版本 — 变更后需重建并重新安装
- 持久生成文件放在 getPluginDataFolder,不是 assets
- 保持相对路径稳定,使后端 AppFolder 与前端 PluginAssets 对齐
- 隔离 — 只写入 getPluginDataFolder(yourPluginName);不要硬编码 /app-data/…
常见错误
- 硬编码 APP_DATA_FOLDER 或 /app-data/... 而不是用 AppFolder
- 运行时把导出 / 报告写入 asset 目录
- 升级后向 getPluginAssetFolder 传入错误的 pluginVersion
- 改资源后未 rebuild / reinstall(或 watch 刷新)
- 前端 path 与打包资源相对路径不一致
- 把持久数据存在应用临时目录