skinsuite 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -0
- package/dist/vite/dir.d.ts +26 -0
- package/dist/vite/dir.d.ts.map +1 -0
- package/dist/vite/dir.js +77 -0
- package/dist/vite/dir.js.map +1 -0
- package/dist/vite/index.d.ts +35 -0
- package/dist/vite/index.d.ts.map +1 -0
- package/dist/vite/index.js +35 -0
- package/dist/vite/index.js.map +1 -0
- package/dist/vite/plugin.d.ts +24 -0
- package/dist/vite/plugin.d.ts.map +1 -0
- package/dist/vite/plugin.js +348 -0
- package/dist/vite/plugin.js.map +1 -0
- package/docs/onboarding.md +12 -5
- package/package.json +4 -4
- package/src/vite/index.ts +3 -3
- package/src/vite/plugin.ts +5 -5
package/README.md
CHANGED
|
@@ -288,6 +288,22 @@ npm test # 先构建,再用 node:test 跑 dist 产物
|
|
|
288
288
|
|
|
289
289
|
⚠️ `src/` 里的相对 import **必须带 `.js` 后缀**:包以 `moduleResolution: NodeNext` 编译,TS 会把 `.js` 映射回 `.ts` 源码,而产物里的相对说明符是原样保留的 —— 不带后缀浏览器与 Node 的原生 ESM 都解析不到。
|
|
290
290
|
|
|
291
|
+
### 关于 exports:类型统一指向 `src/`,运行时才分 `dist/`
|
|
292
|
+
|
|
293
|
+
```jsonc
|
|
294
|
+
".": { "types": "./src/index.ts", "import": "./dist/index.js" },
|
|
295
|
+
"./vue": { "types": "./src/vue/index.ts", "import": "./src/vue/index.ts" },
|
|
296
|
+
"./vite": { "types": "./src/vite/index.ts", "import": "./src/vite/index.ts" }
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
`./vue` / `./vite` 含 `.vue` 与构建期代码,**只能以源码形态发布**(`tsc` 编不出 SFC)。
|
|
300
|
+
于是根入口的类型也必须指向 `src/index.ts`:若它指向 `dist/index.d.ts`,同一个类型在
|
|
301
|
+
一个程序里会有**两个身份**(dist 的 d.ts 与 vue 层引用的 src),composite 项目做声明
|
|
302
|
+
产出时直接红 —— `TS2883: The inferred type of 'X' cannot be named without a reference
|
|
303
|
+
to '...' from '../../node_modules/skinsuite/src/types'`。
|
|
304
|
+
|
|
305
|
+
`dist/` 仍然保留(`.js` + `.d.ts` + sourcemap),运行时走它,纯 JS 消费者不受影响。
|
|
306
|
+
|
|
291
307
|
---
|
|
292
308
|
|
|
293
309
|
## License
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 缺省主题根目录(相对宿主工程根)
|
|
3
|
+
*
|
|
4
|
+
* 留这个默认值是为了 **CI 与独立克隆**:`.env` 通常被 gitignore,全新 checkout 里
|
|
5
|
+
* 没有它,此时必须仍能构建 —— 否则"没配 env 就构建失败"会把部署门槛抬高。
|
|
6
|
+
* 宿主可通过 `resolveThemeDir(mode, root, { defaultDir })` 覆盖。
|
|
7
|
+
*/
|
|
8
|
+
export declare const DEFAULT_THEME_DIR = "src/theme";
|
|
9
|
+
/** 主题根目录内、主题包的子目录名(固定约定,宿主 `views/*.ts` 的字面量 glob 依赖它稳定) */
|
|
10
|
+
export declare const THEME_PACKAGES_SUBDIR = "themes";
|
|
11
|
+
/** 主题根目录内的版式契约目录名(`views/*.ts`,设备声明 + 页面契约,插件副作用 import 拉齐) */
|
|
12
|
+
export declare const THEME_VIEWS_SUBDIR = "views";
|
|
13
|
+
/** 主题根目录内的清单文件名(插件按它找 `theme.config.ts`) */
|
|
14
|
+
export declare const DEFAULT_THEME_MANIFEST = "theme.config.ts";
|
|
15
|
+
/**
|
|
16
|
+
* 解析主题**根目录**为**绝对路径**
|
|
17
|
+
*
|
|
18
|
+
* @param mode Vite 的 mode(development / production / test …),决定叠加哪个 `.env.<mode>`
|
|
19
|
+
* @param root 以哪个目录为工程根找 `.env`,缺省 `process.cwd()`
|
|
20
|
+
* @param opts 可选覆盖:`defaultDir` 缺省回落目录、`envKey` 环境变量名
|
|
21
|
+
*/
|
|
22
|
+
export declare function resolveThemeDir(mode: string, root?: string, opts?: {
|
|
23
|
+
defaultDir?: string;
|
|
24
|
+
envKey?: string;
|
|
25
|
+
}): string;
|
|
26
|
+
//# sourceMappingURL=dir.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dir.d.ts","sourceRoot":"","sources":["../../src/vite/dir.ts"],"names":[],"mappings":"AAgDA;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,cAAc,CAAC;AAE7C,4DAA4D;AAC5D,eAAO,MAAM,qBAAqB,WAAW,CAAC;AAE9C,+DAA+D;AAC/D,eAAO,MAAM,kBAAkB,UAAU,CAAC;AAE1C,4CAA4C;AAC5C,eAAO,MAAM,sBAAsB,oBAAoB,CAAC;AAExD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,MAAsB,EAC5B,IAAI,GAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GAClD,MAAM,CAOR"}
|
package/dist/vite/dir.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 主题**根目录**的解析入口(构建期,随 `skinsuite/vite` 一起发布)
|
|
3
|
+
*
|
|
4
|
+
* 属于主题库自带的构建能力:任何宿主(Vue / React / 任意 Vite 工程)引入
|
|
5
|
+
* `skinsuite` 后,只要在 `vite.config.ts` 挂上 `themeAssets()` 插件、并把目录解析
|
|
6
|
+
* 交给本文件的 `resolveThemeDir()`,就**不再需要自己写一行扫描/目录代码**。
|
|
7
|
+
*
|
|
8
|
+
* === 为什么走 env 而不是一份 TS 配置文件 ===
|
|
9
|
+
* 目录是**部署事实**(可能整包换掉一套品牌主题、可能放在 monorepo 的另一处),
|
|
10
|
+
* 写进源码就意味着换目录要改代码 + 重新 review。env 是"同一份产物服务多个部署"
|
|
11
|
+
* 的既有通道,目录也走同一条:
|
|
12
|
+
*
|
|
13
|
+
* ```
|
|
14
|
+
* VITE_THEME_DIR=src/theme # 相对宿主工程根;主题**根目录**
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* === `VITE_THEME_DIR` 指向的是「主题根目录」,不是「主题包目录」===
|
|
18
|
+
* 根目录内是**三个固定子目录/文件**(约定俗成、名字固定,换根目录位置时整包跟着走):
|
|
19
|
+
*
|
|
20
|
+
* ```
|
|
21
|
+
* <根目录>/ ← VITE_THEME_DIR(如 src/theme)
|
|
22
|
+
* ├── theme.config.ts 清单:调试开关(契约 = defineThemeManifest)
|
|
23
|
+
* ├── themes/ 主题包目录(一个包 = 一种版式)
|
|
24
|
+
* │ ├── default/ ├── compact/
|
|
25
|
+
* └── views/ 声明目录(devices.ts 设备声明 + login.ts 等页面契约)
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* 于是「主题域」是**一个自足目录**:换根目录位置时,主题包、清单、声明一起走,
|
|
29
|
+
* 宿主要改的只有 `VITE_THEME_DIR` 这一个变量。
|
|
30
|
+
*
|
|
31
|
+
* ⚠️ `themes` 与 `views` 是**固定子目录名**(不是可配置项):构建插件扫包目录与
|
|
32
|
+
* 声明目录都认这两个名字 —— 靠「名字固定」对齐,不靠配置。
|
|
33
|
+
*
|
|
34
|
+
* 而**主题域自己的策略**(调试开关、路由投影)不在这里 —— 那份配置跟着主题域走,
|
|
35
|
+
* 住在根目录的 `theme.config.ts`(契约见 `skinsuite` 的 `defineThemeManifest`)。
|
|
36
|
+
* 分工是「宿主说根目录在哪」/「主题域说自己怎么用」,不是同一类东西。
|
|
37
|
+
*
|
|
38
|
+
* ⚠️ 必须用 `loadEnv()` 读,不能直接 `process.env.VITE_THEME_DIR`:
|
|
39
|
+
* vite.config 执行时 Vite 还没加载 `.env` 文件(那只在 config 解析后发生),
|
|
40
|
+
* 直接读 `process.env` 在 `npm run dev` 下恒 undefined —— 于是永远回落默认值,
|
|
41
|
+
* 看着能用、改 env 却不生效,属于最难发现的一类。
|
|
42
|
+
*
|
|
43
|
+
* @author yijiu2025
|
|
44
|
+
* @since 2026-10-17
|
|
45
|
+
*/
|
|
46
|
+
import path from 'node:path';
|
|
47
|
+
import { loadEnv } from 'vite';
|
|
48
|
+
/**
|
|
49
|
+
* 缺省主题根目录(相对宿主工程根)
|
|
50
|
+
*
|
|
51
|
+
* 留这个默认值是为了 **CI 与独立克隆**:`.env` 通常被 gitignore,全新 checkout 里
|
|
52
|
+
* 没有它,此时必须仍能构建 —— 否则"没配 env 就构建失败"会把部署门槛抬高。
|
|
53
|
+
* 宿主可通过 `resolveThemeDir(mode, root, { defaultDir })` 覆盖。
|
|
54
|
+
*/
|
|
55
|
+
export const DEFAULT_THEME_DIR = 'src/theme';
|
|
56
|
+
/** 主题根目录内、主题包的子目录名(固定约定,宿主 `views/*.ts` 的字面量 glob 依赖它稳定) */
|
|
57
|
+
export const THEME_PACKAGES_SUBDIR = 'themes';
|
|
58
|
+
/** 主题根目录内的版式契约目录名(`views/*.ts`,设备声明 + 页面契约,插件副作用 import 拉齐) */
|
|
59
|
+
export const THEME_VIEWS_SUBDIR = 'views';
|
|
60
|
+
/** 主题根目录内的清单文件名(插件按它找 `theme.config.ts`) */
|
|
61
|
+
export const DEFAULT_THEME_MANIFEST = 'theme.config.ts';
|
|
62
|
+
/**
|
|
63
|
+
* 解析主题**根目录**为**绝对路径**
|
|
64
|
+
*
|
|
65
|
+
* @param mode Vite 的 mode(development / production / test …),决定叠加哪个 `.env.<mode>`
|
|
66
|
+
* @param root 以哪个目录为工程根找 `.env`,缺省 `process.cwd()`
|
|
67
|
+
* @param opts 可选覆盖:`defaultDir` 缺省回落目录、`envKey` 环境变量名
|
|
68
|
+
*/
|
|
69
|
+
export function resolveThemeDir(mode, root = process.cwd(), opts = {}) {
|
|
70
|
+
const envKey = opts.envKey ?? 'VITE_THEME_DIR';
|
|
71
|
+
const defaultDir = opts.defaultDir ?? DEFAULT_THEME_DIR;
|
|
72
|
+
// 第三个参数是前缀白名单:只读 VITE_ 开头的,避免把后端密钥之类带进来
|
|
73
|
+
const env = loadEnv(mode, root, 'VITE_');
|
|
74
|
+
const configured = (env[envKey] ?? '').trim();
|
|
75
|
+
return path.resolve(root, configured || defaultDir);
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=dir.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dir.js","sourceRoot":"","sources":["../../src/vite/dir.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAE/B;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,WAAW,CAAC;AAE7C,4DAA4D;AAC5D,MAAM,CAAC,MAAM,qBAAqB,GAAG,QAAQ,CAAC;AAE9C,+DAA+D;AAC/D,MAAM,CAAC,MAAM,kBAAkB,GAAG,OAAO,CAAC;AAE1C,4CAA4C;AAC5C,MAAM,CAAC,MAAM,sBAAsB,GAAG,iBAAiB,CAAC;AAExD;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAC7B,IAAY,EACZ,OAAe,OAAO,CAAC,GAAG,EAAE,EAC5B,OAAiD,EAAE;IAEnD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,gBAAgB,CAAC;IAC/C,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,iBAAiB,CAAC;IACxD,wCAAwC;IACxC,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACzC,MAAM,UAAU,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9C,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,UAAU,IAAI,UAAU,CAAC,CAAC;AACtD,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `skinsuite/vite` —— 主题库的**构建期适配器**(Vite 插件 + 目录解析)
|
|
3
|
+
*
|
|
4
|
+
* 纯内核(`skinsuite`)与 Vue 绑定(`skinsuite/vue`)都刻意不碰构建器,因为
|
|
5
|
+
* "扫描主题目录"是 Vite 专属的能力(webpack 要写成 `require.context`)。这一半
|
|
6
|
+
* 收在这里,让宿主在 `vite.config.ts` 里三行接完,不必自己抄扫描逻辑:
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { themeAssets, resolveThemeDir } from 'skinsuite/vite';
|
|
10
|
+
* export default defineConfig(({ mode }) => ({
|
|
11
|
+
* plugins: [themeAssets({ dir: resolveThemeDir(mode) })]
|
|
12
|
+
* }));
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* === 为什么这个子路径指向源码 `.ts` 而不是 `dist/` ===
|
|
16
|
+
* `vite.config.ts` 由 Vite 用 esbuild 预打包后执行,裸包说明符会被当外部依赖交给
|
|
17
|
+
* Node `import()`。若指向 `dist/`,就要求"包必须先构建" —— CI 里 `npm ci` 不会
|
|
18
|
+
* 构建工作区包,配置会直接起不来。Vite 自己能转译 TS,源码直供就绕开这个前提,
|
|
19
|
+
* 与 `skinsuite/vue` 同一手法。
|
|
20
|
+
*
|
|
21
|
+
* ⚠️ 本层相对 import **必须用显式 `.ts` 后缀**(`./plugin.ts` 而非 `./plugin` 或
|
|
22
|
+
* `./plugin.js`):
|
|
23
|
+
* 这个入口是**唯一在 vite.config / vitest.config 里被 import 的子路径**,config
|
|
24
|
+
* 被 Node 直接执行(Vite 的 config 加载器只 bundle config 自身),Node 既不自动补
|
|
25
|
+
* 无后缀、也不把 `.js` 映射到 `.ts` 源码。而纯内核(`./tone.js`)走 NodeNext 编译、
|
|
26
|
+
* `skinsuite/vue` 走应用代码的 Vite 转译,两者都用不上这个入口的约束,所以这里
|
|
27
|
+
* 自成一套后缀规则。`.ts` 后缀由宿主的 `allowImportingTsExtensions` + Vite 转译共同消化。
|
|
28
|
+
*
|
|
29
|
+
* @author yijiu2025
|
|
30
|
+
* @since 2026-10-17
|
|
31
|
+
*/
|
|
32
|
+
export { themeAssets } from './plugin.js';
|
|
33
|
+
export type { ThemeAssetsPluginOptions } from './plugin.js';
|
|
34
|
+
export { DEFAULT_THEME_DIR, THEME_PACKAGES_SUBDIR, DEFAULT_THEME_MANIFEST, resolveThemeDir } from './dir.js';
|
|
35
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vite/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,YAAY,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACtB,eAAe,EAChB,MAAM,UAAU,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `skinsuite/vite` —— 主题库的**构建期适配器**(Vite 插件 + 目录解析)
|
|
3
|
+
*
|
|
4
|
+
* 纯内核(`skinsuite`)与 Vue 绑定(`skinsuite/vue`)都刻意不碰构建器,因为
|
|
5
|
+
* "扫描主题目录"是 Vite 专属的能力(webpack 要写成 `require.context`)。这一半
|
|
6
|
+
* 收在这里,让宿主在 `vite.config.ts` 里三行接完,不必自己抄扫描逻辑:
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { themeAssets, resolveThemeDir } from 'skinsuite/vite';
|
|
10
|
+
* export default defineConfig(({ mode }) => ({
|
|
11
|
+
* plugins: [themeAssets({ dir: resolveThemeDir(mode) })]
|
|
12
|
+
* }));
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* === 为什么这个子路径指向源码 `.ts` 而不是 `dist/` ===
|
|
16
|
+
* `vite.config.ts` 由 Vite 用 esbuild 预打包后执行,裸包说明符会被当外部依赖交给
|
|
17
|
+
* Node `import()`。若指向 `dist/`,就要求"包必须先构建" —— CI 里 `npm ci` 不会
|
|
18
|
+
* 构建工作区包,配置会直接起不来。Vite 自己能转译 TS,源码直供就绕开这个前提,
|
|
19
|
+
* 与 `skinsuite/vue` 同一手法。
|
|
20
|
+
*
|
|
21
|
+
* ⚠️ 本层相对 import **必须用显式 `.ts` 后缀**(`./plugin.ts` 而非 `./plugin` 或
|
|
22
|
+
* `./plugin.js`):
|
|
23
|
+
* 这个入口是**唯一在 vite.config / vitest.config 里被 import 的子路径**,config
|
|
24
|
+
* 被 Node 直接执行(Vite 的 config 加载器只 bundle config 自身),Node 既不自动补
|
|
25
|
+
* 无后缀、也不把 `.js` 映射到 `.ts` 源码。而纯内核(`./tone.js`)走 NodeNext 编译、
|
|
26
|
+
* `skinsuite/vue` 走应用代码的 Vite 转译,两者都用不上这个入口的约束,所以这里
|
|
27
|
+
* 自成一套后缀规则。`.ts` 后缀由宿主的 `allowImportingTsExtensions` + Vite 转译共同消化。
|
|
28
|
+
*
|
|
29
|
+
* @author yijiu2025
|
|
30
|
+
* @since 2026-10-17
|
|
31
|
+
*/
|
|
32
|
+
/// <reference path="./theme.d.ts" />
|
|
33
|
+
export { themeAssets } from './plugin.js';
|
|
34
|
+
export { DEFAULT_THEME_DIR, THEME_PACKAGES_SUBDIR, DEFAULT_THEME_MANIFEST, resolveThemeDir } from './dir.js';
|
|
35
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/vite/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,qCAAqC;AAErC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACtB,eAAe,EAChB,MAAM,UAAU,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Plugin } from 'vite';
|
|
2
|
+
export interface ThemeAssetsPluginOptions {
|
|
3
|
+
/** 主题**根目录**:相对 Vite root 或绝对路径(通常来自 `resolveThemeDir()`,已是绝对路径) */
|
|
4
|
+
dir: string;
|
|
5
|
+
/** 虚拟模块 id,缺省 `virtual:theme` */
|
|
6
|
+
moduleId?: string;
|
|
7
|
+
/** 清单文件名,缺省 `theme.config.ts`;设为空串则**不**注入清单 */
|
|
8
|
+
manifestFile?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* 主题域插件
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* // vite.config.ts
|
|
16
|
+
* import { themeAssets, resolveThemeDir } from 'skinsuite/vite';
|
|
17
|
+
*
|
|
18
|
+
* export default defineConfig(({ mode }) => ({
|
|
19
|
+
* plugins: [themeAssets({ dir: resolveThemeDir(mode) })]
|
|
20
|
+
* }));
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare function themeAssets(options: ThemeAssetsPluginOptions): Plugin;
|
|
24
|
+
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/vite/plugin.ts"],"names":[],"mappings":"AAgEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAcnC,MAAM,WAAW,wBAAwB;IACvC,oEAAoE;IACpE,GAAG,EAAE,MAAM,CAAC;IACZ,iCAAiC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAuQD;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,wBAAwB,GAAG,MAAM,CA+CrE"}
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 主题域扫描插件 —— **主题库自带的 Vite 适配器**(随 `skinsuite/vite` 一起发布)
|
|
3
|
+
*
|
|
4
|
+
* 把 `VITE_THEME_DIR` 指向的**主题根目录**扫成一个虚拟模块 `virtual:theme`,它同时产出三样东西:
|
|
5
|
+
*
|
|
6
|
+
* ① **资产**:主题包定义、配色元信息、配色附加样式(惰性)、版式组件加载表 `themeViews`
|
|
7
|
+
* ② **清单**:根目录里那份 `theme.config.ts`(调试开关,见 `defineThemeManifest`)
|
|
8
|
+
* ③ **声明**:`views/*.ts`(设备声明 + 页面契约)以副作用 import 拉齐注册
|
|
9
|
+
*
|
|
10
|
+
* 本模块被 import 的那一刻(模块求值期副作用)自动完成三件装配:
|
|
11
|
+
* `installThemeViews(themeViews)` + `installThemeRegistry(...)` + `installThemeManifest(...)`,
|
|
12
|
+
* 宿主**无需 import `virtual:theme` 再转发**,也无需手动 import 任何 `views/*.ts`。
|
|
13
|
+
*
|
|
14
|
+
* === 目录口径:`VITE_THEME_DIR` 是「主题根目录」,不是「主题包目录」===
|
|
15
|
+
* 根目录内固定三个名字(约定俗成,换根目录位置时整包跟着走):
|
|
16
|
+
* `theme.config.ts` 清单
|
|
17
|
+
* `themes/` 主题包目录(本插件扫这里,出 packages/colors/styles/themeViews)
|
|
18
|
+
* `views/` 声明目录(devices.ts 设备声明 + 页面契约,本插件副作用 import 拉齐注册)
|
|
19
|
+
* 所以本插件在 `dir` 下**再进一层 `themes/`** 扫包、再进一层 `views/` 拉声明,
|
|
20
|
+
* 清单则从 `dir` 根层读。
|
|
21
|
+
*
|
|
22
|
+
* === 为什么它放在库里(而非让每个宿主各写一份)===
|
|
23
|
+
* 它是主题机制的**构建期半边**:内核负责契约(`ThemeManifest`),
|
|
24
|
+
* 这里负责扫描。没有它,「主题目录是配置项」就只实现了一半 —— 每个宿主都得
|
|
25
|
+
* 自己抄一遍一百多行的扫描逻辑,正是"库不够强大"的典型症状。
|
|
26
|
+
*
|
|
27
|
+
* `vite.config.ts` 由 Vite 用 esbuild 预打包后执行,裸包说明符会被当外部依赖交给
|
|
28
|
+
* Node `import()`。因此本入口**刻意用 subpath export 指向源码 `.ts`**(而非 `dist/`),
|
|
29
|
+
* 与 `skinsuite/vue` 同一手法:Vite 自己能转译 TS,源码直供就绕开了
|
|
30
|
+
* "包必须先构建 dist 才能被 config 引用"的脆弱前提(CI 里 `npm ci` 不会构建工作区包)。
|
|
31
|
+
*
|
|
32
|
+
* === 它解决的问题 ===
|
|
33
|
+
* `import.meta.glob` 的模式必须是**字面量**(Vite 在编译期静态展开),所以
|
|
34
|
+
* 「主题目录放在哪」一旦写进 glob 就再也改不了 —— 想换目录只能改源码。
|
|
35
|
+
* 本插件把扫描搬到构建期(Node 侧 `fs`),用**虚拟模块**把结果喂给运行时,
|
|
36
|
+
* 于是目录路径变成 `VITE_THEME_DIR` 这一个环境变量。
|
|
37
|
+
*
|
|
38
|
+
* === 产出形态(资产部分与 `import.meta.glob` 的结果保持一致)===
|
|
39
|
+
* ```ts
|
|
40
|
+
* export const packages: { './default/index.js': Module }
|
|
41
|
+
* export const colors: { './default/mobile/login/colors/white/index.js': Module }
|
|
42
|
+
* export const styles: { './default/mobile/login/colors/white/theme.scss': () => Promise<string> }
|
|
43
|
+
* export const themeViews: { 'login': { './default/mobile/login/index.vue': () => Module } }
|
|
44
|
+
* // 副作用:installThemeViews(themeViews) / installThemeRegistry(...) / installThemeManifest(...)
|
|
45
|
+
* ```
|
|
46
|
+
* 资产键**相对主题包目录**(`themes/`,`./` 开头),值保持「模块命名空间」而非默认导出 ——
|
|
47
|
+
* 这样宿主注册表代码一行都不用改(它按「包/设备/页面/配色」四段解析键)。`styles` 是
|
|
48
|
+
* **惰性**的(`?inline` 动态 import),背景图与字体不会进首屏包。
|
|
49
|
+
*
|
|
50
|
+
* === 为什么不用 codegen 落盘 ===
|
|
51
|
+
* 生成物入库有两个麻烦:`git status` 常脏、以及"忘了重新生成"导致的静默过期。
|
|
52
|
+
* 虚拟模块没有落盘产物,改一个目录下次请求就是新的。
|
|
53
|
+
*
|
|
54
|
+
* === 容错的边界 ===
|
|
55
|
+
* 目录不存在、包写坏、配色缺 `tone` —— 一律**跳过而不是报错**:一个写歪的目录不该
|
|
56
|
+
* 让整站起不来。目录口径的问题由宿主的关卡负责大喊。
|
|
57
|
+
* **唯独清单不跳过**:它一旦写错,`defineThemeManifest` 会在启动时直接抛,
|
|
58
|
+
* 因为「面板不出现」「路由推不出页面」这类症状根本无从归因。
|
|
59
|
+
*
|
|
60
|
+
* @author yijiu2025
|
|
61
|
+
* @since 2026-10-17
|
|
62
|
+
*/
|
|
63
|
+
import { existsSync, readdirSync, statSync } from 'node:fs';
|
|
64
|
+
import { join, resolve, sep } from 'node:path';
|
|
65
|
+
import { DEFAULT_THEME_PACKAGE, THEME_COLOR_DEF_FILE, THEME_COLOR_STYLE_FILE, THEME_COLORS_SEGMENT, THEME_DIR_LEVELS, THEME_PACKAGE_DEF_FILE } from '../constants.js';
|
|
66
|
+
import { DEFAULT_THEME_MANIFEST, THEME_PACKAGES_SUBDIR, THEME_VIEWS_SUBDIR } from './dir.js';
|
|
67
|
+
/** 版式组件的叶子文件名(`themes/<包>/<设备>/<页面>/index.vue`) */
|
|
68
|
+
const VIEW_COMPONENT_FILE = 'index.vue';
|
|
69
|
+
const DEFAULT_MODULE_ID = 'virtual:theme';
|
|
70
|
+
/** 目录不存在 / 没有清单时的产出:空注册表 + 空清单(import 本模块即自动装配) */
|
|
71
|
+
const EMPTY_MODULE = [
|
|
72
|
+
"import { installThemeRegistry, buildThemeRegistry, resolveThemeManifest, installThemeManifest } from 'skinsuite';",
|
|
73
|
+
"import { installThemeViews } from 'skinsuite/vue';",
|
|
74
|
+
'export const packages = {};',
|
|
75
|
+
'export const colors = {};',
|
|
76
|
+
'export const styles = {};',
|
|
77
|
+
'export const themeViews = {};',
|
|
78
|
+
'installThemeViews(themeViews);',
|
|
79
|
+
'installThemeRegistry(buildThemeRegistry({ packages, colors, styles }));',
|
|
80
|
+
'export const themeManifest = resolveThemeManifest(null);',
|
|
81
|
+
'installThemeManifest(themeManifest);'
|
|
82
|
+
].join('\n');
|
|
83
|
+
/** 是否为目录;不存在或不可读一律 false(扫描全程"读不到就跳过") */
|
|
84
|
+
function isDir(path) {
|
|
85
|
+
try {
|
|
86
|
+
return statSync(path).isDirectory();
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function subdirs(path) {
|
|
93
|
+
try {
|
|
94
|
+
return readdirSync(path, { withFileTypes: true })
|
|
95
|
+
.filter(entry => entry.isDirectory())
|
|
96
|
+
.map(entry => entry.name)
|
|
97
|
+
.sort();
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return [];
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/** 目录下的 `.ts` 文件(不含 `.d.ts`);不存在或不可读返回空(读不到就跳过) */
|
|
104
|
+
function tsFiles(path) {
|
|
105
|
+
try {
|
|
106
|
+
return readdirSync(path, { withFileTypes: true })
|
|
107
|
+
.filter(entry => entry.isFile() && entry.name.endsWith('.js') && !entry.name.endsWith('.d.js'))
|
|
108
|
+
.map(entry => entry.name)
|
|
109
|
+
.sort();
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return [];
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* 扫描主题**包目录**(根目录下的 `themes/` 子目录)
|
|
117
|
+
*
|
|
118
|
+
* `dir` 是主题根目录(`VITE_THEME_DIR`),真正的包住在 `dir/themes/` 下 ——
|
|
119
|
+
* 这个子目录名固定,宿主 `views/*.ts` 的 `import.meta.glob` 字面量也认它,两边靠名字对齐。
|
|
120
|
+
*
|
|
121
|
+
* === 目录结构由内核契约驱动,而非手写嵌套 for(2026-10-17)===
|
|
122
|
+
* 「包 / 设备 / 页面 / colors / 配色」这五段里,`colors` 是**固定字面段**、其余四段
|
|
123
|
+
* 是**取值段**(取值由文件系统与宿主设备清单决定,本插件不认识具体值)。这段结构的
|
|
124
|
+
* 唯一来源是 `constants.ts` 的 `THEME_DIR_LEVELS`(取值目录段)+ `THEME_COLORS_SEGMENT`
|
|
125
|
+
* (固定字面段)+ `THEME_COLOR_DEF_FILE` / `THEME_COLOR_STYLE_FILE`(叶子文件)。
|
|
126
|
+
* 本函数用 `walk` 按 `THEME_DIR_LEVELS` 做**通用递归下降**——目录加一层、或 `colors`
|
|
127
|
+
* 改名,只动那一份契约,这里与注册表的 `colorFromKey()` 一起跟着变,不再有
|
|
128
|
+
* "扫得到但解析不出"或反之的静默脱节。
|
|
129
|
+
*
|
|
130
|
+
* 只认内核约定的三种文件,其余一律忽略(清单文件住在根层,不在 `themes/` 里,天然不进这里)。
|
|
131
|
+
*/
|
|
132
|
+
function scan(dir) {
|
|
133
|
+
const packagesDir = join(dir, THEME_PACKAGES_SUBDIR);
|
|
134
|
+
const result = { packages: [], colors: [], styles: [], views: [], decls: [] };
|
|
135
|
+
for (const pkg of subdirs(packagesDir)) {
|
|
136
|
+
const pkgDir = join(packagesDir, pkg);
|
|
137
|
+
if (existsSync(join(pkgDir, THEME_PACKAGE_DEF_FILE))) {
|
|
138
|
+
result.packages.push({
|
|
139
|
+
key: `./${pkg}/${THEME_PACKAGE_DEF_FILE}`,
|
|
140
|
+
file: join(pkgDir, THEME_PACKAGE_DEF_FILE)
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
// 按契约递归下降:取值目录段(THEME_DIR_LEVELS)逐层深入,最后在 `colors/`
|
|
144
|
+
// 固定字面段之下收叶子(index.ts / theme.scss)。
|
|
145
|
+
walk(pkgDir, [pkg], result);
|
|
146
|
+
}
|
|
147
|
+
// 声明目录 `views/*.ts`(设备声明 devices.ts + 页面契约 login/register/forgot-password):
|
|
148
|
+
// 插件以副作用 import 拉齐,宿主 bootstrap/store 不再手动 import。
|
|
149
|
+
for (const name of tsFiles(join(dir, THEME_VIEWS_SUBDIR))) {
|
|
150
|
+
result.decls.push({
|
|
151
|
+
key: `./${THEME_VIEWS_SUBDIR}/${name}`,
|
|
152
|
+
file: join(dir, THEME_VIEWS_SUBDIR, name)
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
return result;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* 按 `THEME_DIR_LEVELS` 递归下降主题包目录
|
|
159
|
+
*
|
|
160
|
+
* `THEME_DIR_LEVELS = ['pkg','device','page','colorId']`,其中 `pkg` 由 `scan()` 的
|
|
161
|
+
* 外层循环进入,本函数递归「设备 → 页面 → 配色」三段;`colorId` 是最后一个取值段,
|
|
162
|
+
* 它的**父目录**是固定字面段 `colors/`(不是一层取值目录),所以到 `colorId` 这层
|
|
163
|
+
* 不再递归子目录,而是直接在 `colors/<配色>/` 下收叶子文件。
|
|
164
|
+
*
|
|
165
|
+
* @param base 当前目录的绝对路径
|
|
166
|
+
* @param segments 已累积的**取值段**值(与 `THEME_DIR_LEVELS` 前缀一一对应,含包名)
|
|
167
|
+
* @param result 累积产物
|
|
168
|
+
*/
|
|
169
|
+
function walk(base, segments, result) {
|
|
170
|
+
// 已累积到「包/设备/页面」三段后,下一层是固定字面段 `colors/` + 最后一个取值段 `colorId`。
|
|
171
|
+
// 判定依据 = `THEME_DIR_LEVELS` 里还剩几段未进入:只剩 `colorId` 一段时收叶子。
|
|
172
|
+
if (segments.length === THEME_DIR_LEVELS.length - 1) {
|
|
173
|
+
// 已到「包/设备/页面」层:版式组件(本页 index.vue)+ colors/ 配色
|
|
174
|
+
const viewFile = join(base, VIEW_COMPONENT_FILE);
|
|
175
|
+
if (existsSync(viewFile)) {
|
|
176
|
+
result.views.push({
|
|
177
|
+
pkg: segments[0],
|
|
178
|
+
page: segments[2],
|
|
179
|
+
key: './' + [...segments, VIEW_COMPONENT_FILE].join('/'),
|
|
180
|
+
file: viewFile
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
const colorsDir = join(base, THEME_COLORS_SEGMENT);
|
|
184
|
+
for (const color of subdirs(colorsDir)) {
|
|
185
|
+
const colorDir = join(colorsDir, color);
|
|
186
|
+
// 键以 `./` 开头(相对主题包目录),段间单斜杠:`./<包>/<设备>/<页面>/colors/<配色>`
|
|
187
|
+
const keyBase = './' + [...segments, THEME_COLORS_SEGMENT, color].join('/');
|
|
188
|
+
if (existsSync(join(colorDir, THEME_COLOR_DEF_FILE))) {
|
|
189
|
+
result.colors.push({
|
|
190
|
+
key: `${keyBase}/${THEME_COLOR_DEF_FILE}`,
|
|
191
|
+
file: join(colorDir, THEME_COLOR_DEF_FILE)
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
if (existsSync(join(colorDir, THEME_COLOR_STYLE_FILE))) {
|
|
195
|
+
result.styles.push({
|
|
196
|
+
key: `${keyBase}/${THEME_COLOR_STYLE_FILE}`,
|
|
197
|
+
file: join(colorDir, THEME_COLOR_STYLE_FILE)
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
// 取值段逐层下降:设备 → 页面。
|
|
204
|
+
for (const name of subdirs(base)) {
|
|
205
|
+
walk(join(base, name), [...segments, name], result);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/** 绝对路径 → 模块说明符(root 内用 `/xxx`,root 外用正斜杠绝对路径) */
|
|
209
|
+
function toSpecifier(abs, root) {
|
|
210
|
+
const absolute = resolve(abs);
|
|
211
|
+
const base = resolve(root);
|
|
212
|
+
if (absolute.startsWith(base + sep)) {
|
|
213
|
+
return '/' + absolute.slice(base.length + 1).split(sep).join('/');
|
|
214
|
+
}
|
|
215
|
+
return absolute.split(sep).join('/');
|
|
216
|
+
}
|
|
217
|
+
/** 生成虚拟模块源码 */
|
|
218
|
+
function render(result, root, manifestSpec) {
|
|
219
|
+
const lines = [
|
|
220
|
+
// 装配依赖(纯内核机制):本模块被 import 时自动装注册表 + 解析清单单例
|
|
221
|
+
"import { installThemeRegistry, buildThemeRegistry, resolveThemeManifest, installThemeManifest } from 'skinsuite';",
|
|
222
|
+
// 版式加载表单例(Vue 绑定层):本模块体把 themeViews 装进内核单例,页面契约惰性解析
|
|
223
|
+
"import { installThemeViews } from 'skinsuite/vue';",
|
|
224
|
+
manifestSpec
|
|
225
|
+
? `import { default as __manifest } from ${JSON.stringify(manifestSpec)};`
|
|
226
|
+
: 'const __manifest = null;',
|
|
227
|
+
// 声明文件副作用 import(views/*.ts):拉齐 defineThemeDevice / defineThemePage 注册。
|
|
228
|
+
// 🔴 必须在 `installThemeViews(themeViews)` 之前**作为 import 语句**存在(ESM import 全部
|
|
229
|
+
// 提升到模块体之前执行),而页面契约现在是惰性解析 loader,不读 themeViews ——
|
|
230
|
+
// 所以这里安全,不再是「页面契约 import virtual:theme」的循环。
|
|
231
|
+
...result.decls.map(entry => `import ${JSON.stringify(toSpecifier(entry.file, root))};`),
|
|
232
|
+
''
|
|
233
|
+
];
|
|
234
|
+
const emit = (entries, exportName) => {
|
|
235
|
+
entries.forEach((entry, index) => {
|
|
236
|
+
lines.push(`import * as __${exportName}${index} from ${JSON.stringify(toSpecifier(entry.file, root))};`);
|
|
237
|
+
});
|
|
238
|
+
lines.push(`export const ${exportName} = {`);
|
|
239
|
+
entries.forEach((entry, index) => {
|
|
240
|
+
lines.push(` ${JSON.stringify(entry.key)}: __${exportName}${index},`);
|
|
241
|
+
});
|
|
242
|
+
lines.push('};');
|
|
243
|
+
};
|
|
244
|
+
emit(result.packages, 'packages');
|
|
245
|
+
emit(result.colors, 'colors');
|
|
246
|
+
lines.push('export const styles = {');
|
|
247
|
+
result.styles.forEach((entry, index) => {
|
|
248
|
+
const spec = JSON.stringify(toSpecifier(entry.file, root) + '?inline');
|
|
249
|
+
lines.push(` ${JSON.stringify(entry.key)}: () => import(${spec}).then(__m${index} => __m${index}.default),`);
|
|
250
|
+
});
|
|
251
|
+
lines.push('};');
|
|
252
|
+
// ---- themeViews:版式组件(按页面分组;内置包 eager 零请求、非内置包惰性)----
|
|
253
|
+
// 🔴 内置包用**同步返回**(`() => __viewN`,eager 静态 import 的模块命名空间),
|
|
254
|
+
// 这样 `ViewRegistry.builtin()` 才能首帧同步拿到内置包版式(零请求、不闪屏)。
|
|
255
|
+
const builtinViews = result.views.filter(v => v.pkg === DEFAULT_THEME_PACKAGE);
|
|
256
|
+
builtinViews.forEach((entry, index) => {
|
|
257
|
+
lines.push(`import * as __view${index} from ${JSON.stringify(toSpecifier(entry.file, root))};`);
|
|
258
|
+
});
|
|
259
|
+
const byPage = new Map();
|
|
260
|
+
for (const entry of result.views) {
|
|
261
|
+
const list = byPage.get(entry.page);
|
|
262
|
+
if (list)
|
|
263
|
+
list.push(entry);
|
|
264
|
+
else
|
|
265
|
+
byPage.set(entry.page, [entry]);
|
|
266
|
+
}
|
|
267
|
+
lines.push('export const themeViews = {');
|
|
268
|
+
for (const [page, entries] of byPage) {
|
|
269
|
+
lines.push(` ${JSON.stringify(page)}: {`);
|
|
270
|
+
entries.forEach(entry => {
|
|
271
|
+
if (entry.pkg === DEFAULT_THEME_PACKAGE) {
|
|
272
|
+
const idx = builtinViews.indexOf(entry);
|
|
273
|
+
lines.push(` ${JSON.stringify(entry.key)}: () => __view${idx},`);
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
const spec = JSON.stringify(toSpecifier(entry.file, root));
|
|
277
|
+
lines.push(` ${JSON.stringify(entry.key)}: () => import(${spec}),`);
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
lines.push(' },');
|
|
281
|
+
}
|
|
282
|
+
lines.push('};');
|
|
283
|
+
// ---- 装配副作用 + 清单单例(import 本模块即自动装版式加载表 + 注册表 + 清单)----
|
|
284
|
+
lines.push('installThemeViews(themeViews);');
|
|
285
|
+
lines.push('installThemeRegistry(buildThemeRegistry({ packages, colors, styles }));');
|
|
286
|
+
lines.push('export const themeManifest = resolveThemeManifest(__manifest);');
|
|
287
|
+
lines.push('installThemeManifest(themeManifest);');
|
|
288
|
+
return lines.join('\n');
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* 主题域插件
|
|
292
|
+
*
|
|
293
|
+
* @example
|
|
294
|
+
* ```ts
|
|
295
|
+
* // vite.config.ts
|
|
296
|
+
* import { themeAssets, resolveThemeDir } from 'skinsuite/vite';
|
|
297
|
+
*
|
|
298
|
+
* export default defineConfig(({ mode }) => ({
|
|
299
|
+
* plugins: [themeAssets({ dir: resolveThemeDir(mode) })]
|
|
300
|
+
* }));
|
|
301
|
+
* ```
|
|
302
|
+
*/
|
|
303
|
+
export function themeAssets(options) {
|
|
304
|
+
const moduleId = options.moduleId ?? DEFAULT_MODULE_ID;
|
|
305
|
+
const virtualId = '\0' + moduleId;
|
|
306
|
+
const manifestFile = options.manifestFile ?? DEFAULT_THEME_MANIFEST;
|
|
307
|
+
let root = process.cwd();
|
|
308
|
+
return {
|
|
309
|
+
name: 'skinsuite:theme-assets',
|
|
310
|
+
// 虚拟模块要抢在 Vite 的内置解析之前
|
|
311
|
+
enforce: 'pre',
|
|
312
|
+
configResolved(config) {
|
|
313
|
+
root = config.root;
|
|
314
|
+
},
|
|
315
|
+
resolveId(id) {
|
|
316
|
+
return id === moduleId ? virtualId : null;
|
|
317
|
+
},
|
|
318
|
+
load(id) {
|
|
319
|
+
if (id !== virtualId)
|
|
320
|
+
return null;
|
|
321
|
+
const dir = resolve(root, options.dir);
|
|
322
|
+
// 根目录不存在 = 还没建主题,给**空注册表 + 空清单**而不是让应用起不来
|
|
323
|
+
if (!isDir(dir))
|
|
324
|
+
return EMPTY_MODULE;
|
|
325
|
+
const manifestPath = manifestFile ? join(dir, manifestFile) : '';
|
|
326
|
+
const manifestSpec = manifestPath && existsSync(manifestPath)
|
|
327
|
+
? toSpecifier(manifestPath, root)
|
|
328
|
+
: null;
|
|
329
|
+
return render(scan(dir), root, manifestSpec);
|
|
330
|
+
},
|
|
331
|
+
configureServer(server) {
|
|
332
|
+
const dir = resolve(root, options.dir);
|
|
333
|
+
const onChange = (file) => {
|
|
334
|
+
if (!file.startsWith(dir))
|
|
335
|
+
return;
|
|
336
|
+
const mod = server.moduleGraph.getModuleById(virtualId);
|
|
337
|
+
if (mod)
|
|
338
|
+
server.moduleGraph.invalidateModule(mod);
|
|
339
|
+
server.ws.send({ type: 'full-reload' });
|
|
340
|
+
};
|
|
341
|
+
// 只监听**增删**:新增/删除主题目录或清单会改变虚拟模块的导出面;
|
|
342
|
+
// 改已有文件的内容由 HMR 自己处理(那是普通模块,不必重建清单)。
|
|
343
|
+
server.watcher.on('add', onChange);
|
|
344
|
+
server.watcher.on('unlink', onChange);
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/vite/plugin.ts"],"names":[],"mappings":"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"}
|
package/docs/onboarding.md
CHANGED
|
@@ -235,16 +235,23 @@ VITE_THEME_DIR=src/theme
|
|
|
235
235
|
|
|
236
236
|
缺省就是 `src/theme`,可不写。**换目录只改这一个变量,不动代码。**
|
|
237
237
|
|
|
238
|
-
### 5.2 tsconfig / env
|
|
238
|
+
### 5.2 tsconfig / env 类型(必做一行)
|
|
239
239
|
|
|
240
|
-
`skinsuite/vite` 自带 `virtual:theme`
|
|
241
|
-
|
|
242
|
-
纳入检查范围,或补一句:
|
|
240
|
+
`skinsuite/vite` 自带 `virtual:theme` 的类型声明(`src/vite/theme.d.ts`),但**类型声明只有在
|
|
241
|
+
被纳入 TS 程序时才有意义**。在你项目的 `src/vite-env.d.ts` 里加一行:
|
|
243
242
|
|
|
244
243
|
```ts
|
|
245
|
-
/// <reference types="
|
|
244
|
+
/// <reference types="vite/client" />
|
|
245
|
+
import "skinsuite/vite"; // 让 theme.d.ts 的 declare module 'virtual:theme' 进程序
|
|
246
246
|
```
|
|
247
247
|
|
|
248
|
+
🔴 **不要写 `/// <reference types="skinsuite/vite" />`**——`reference types` 解析不到包的
|
|
249
|
+
**子路径**入口,症状是 `vue-tsc -b` 报 `Cannot find module or type declarations for side-effect
|
|
250
|
+
import of 'virtual:theme'`(TS2882),而 `vite build` / 浏览器全正常,很容易误判成「只是编辑器问题」。
|
|
251
|
+
|
|
252
|
+
`import` 写在 `.d.ts` 里是**纯类型侧**的:不产生任何运行时代码,也不会把插件打进产物,只是
|
|
253
|
+
把 `src/vite/index.ts` 上的 `/// <reference path="./theme.d.ts" />` 带进程序。
|
|
254
|
+
|
|
248
255
|
---
|
|
249
256
|
|
|
250
257
|
## 六、bootstrap.ts(启动编排,从这开始写)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skinsuite",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "多主题 / 多版式机制的纯内核(零运行时依赖):目录名与默认值的白名单常量、主题包契约类型、明暗 mode 与色系 tone、CSS 变量 token 的安全校验、设备维度 URL 参数读取。不碰 DOM / 构建器 / 路由,可在任意前端(Vue / React / Node / SSR)复用。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
|
-
"types": "./
|
|
11
|
+
"types": "./src/index.ts",
|
|
12
12
|
"import": "./dist/index.js"
|
|
13
13
|
},
|
|
14
14
|
"./vue": {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
},
|
|
18
18
|
"./vite": {
|
|
19
19
|
"types": "./src/vite/index.ts",
|
|
20
|
-
"import": "./
|
|
20
|
+
"import": "./dist/vite/index.js"
|
|
21
21
|
},
|
|
22
22
|
"./package.json": "./package.json"
|
|
23
23
|
},
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"node": ">=18"
|
|
35
35
|
},
|
|
36
36
|
"scripts": {
|
|
37
|
-
"build": "tsc -p tsconfig.build.json",
|
|
37
|
+
"build": "tsc -p tsconfig.build.json && tsc -p tsconfig.vite.json",
|
|
38
38
|
"typecheck": "tsc -p tsconfig.json",
|
|
39
39
|
"test": "npm run build && node --test",
|
|
40
40
|
"prepack": "npm run build"
|
package/src/vite/index.ts
CHANGED
|
@@ -31,11 +31,11 @@
|
|
|
31
31
|
*/
|
|
32
32
|
/// <reference path="./theme.d.ts" />
|
|
33
33
|
|
|
34
|
-
export { themeAssets } from './plugin.
|
|
35
|
-
export type { ThemeAssetsPluginOptions } from './plugin.
|
|
34
|
+
export { themeAssets } from './plugin.js';
|
|
35
|
+
export type { ThemeAssetsPluginOptions } from './plugin.js';
|
|
36
36
|
export {
|
|
37
37
|
DEFAULT_THEME_DIR,
|
|
38
38
|
THEME_PACKAGES_SUBDIR,
|
|
39
39
|
DEFAULT_THEME_MANIFEST,
|
|
40
40
|
resolveThemeDir
|
|
41
|
-
} from './dir.
|
|
41
|
+
} from './dir.js';
|
package/src/vite/plugin.ts
CHANGED
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
*
|
|
38
38
|
* === 产出形态(资产部分与 `import.meta.glob` 的结果保持一致)===
|
|
39
39
|
* ```ts
|
|
40
|
-
* export const packages: { './default/index.
|
|
41
|
-
* export const colors: { './default/mobile/login/colors/white/index.
|
|
40
|
+
* export const packages: { './default/index.js': Module }
|
|
41
|
+
* export const colors: { './default/mobile/login/colors/white/index.js': Module }
|
|
42
42
|
* export const styles: { './default/mobile/login/colors/white/theme.scss': () => Promise<string> }
|
|
43
43
|
* export const themeViews: { 'login': { './default/mobile/login/index.vue': () => Module } }
|
|
44
44
|
* // 副作用:installThemeViews(themeViews) / installThemeRegistry(...) / installThemeManifest(...)
|
|
@@ -70,8 +70,8 @@ import {
|
|
|
70
70
|
THEME_COLORS_SEGMENT,
|
|
71
71
|
THEME_DIR_LEVELS,
|
|
72
72
|
THEME_PACKAGE_DEF_FILE
|
|
73
|
-
} from '../constants.
|
|
74
|
-
import { DEFAULT_THEME_MANIFEST, THEME_PACKAGES_SUBDIR, THEME_VIEWS_SUBDIR } from './dir.
|
|
73
|
+
} from '../constants.js';
|
|
74
|
+
import { DEFAULT_THEME_MANIFEST, THEME_PACKAGES_SUBDIR, THEME_VIEWS_SUBDIR } from './dir.js';
|
|
75
75
|
|
|
76
76
|
/** 版式组件的叶子文件名(`themes/<包>/<设备>/<页面>/index.vue`) */
|
|
77
77
|
const VIEW_COMPONENT_FILE = 'index.vue';
|
|
@@ -149,7 +149,7 @@ function subdirs(path: string): string[] {
|
|
|
149
149
|
function tsFiles(path: string): string[] {
|
|
150
150
|
try {
|
|
151
151
|
return readdirSync(path, { withFileTypes: true })
|
|
152
|
-
.filter(entry => entry.isFile() && entry.name.endsWith('.
|
|
152
|
+
.filter(entry => entry.isFile() && entry.name.endsWith('.js') && !entry.name.endsWith('.d.js'))
|
|
153
153
|
.map(entry => entry.name)
|
|
154
154
|
.sort();
|
|
155
155
|
} catch {
|