@playcraft/devkit 1.0.18 → 1.0.19

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/core/index.d.ts CHANGED
@@ -183,3 +183,12 @@ export declare function runViteDev(
183
183
  customDefines?: Record<string, any>,
184
184
  viteCustomConfig?: Partial<ViteUserConfig>
185
185
  ): Promise<void>;
186
+
187
+ /** Vite plugin for .json5 file imports */
188
+ export declare function json5Plugin(): import('vite').Plugin;
189
+
190
+ /** Vite plugin for asset inlining (.atlas, .fnt, .xml) */
191
+ export declare function assetInlinePlugin(): import('vite').Plugin;
192
+
193
+ /** Vite plugin for font injection (base64 @font-face in <head>) */
194
+ export declare function fontFamilyPlugin(): import('vite').Plugin;
package/core/index.js CHANGED
@@ -7,7 +7,7 @@ const { DebuggerInjectionPlugin } = require('./plugins/DebuggerInjectionPlugin.j
7
7
  const { ExitAPIInjectorPlugin } = require('./plugins/ExitAPIInjectorPlugin.js');
8
8
  const { runBuild, makeWebpackBuildConfig } = require('./webpack.build.js');
9
9
  const { runDev, makeWebpackDevConfig } = require('./webpack.dev.js');
10
- const { runViteDev, makeViteDevConfig } = require('./vite.dev.js');
10
+ const { runViteDev, makeViteDevConfig, json5Plugin, assetInlinePlugin, fontFamilyPlugin } = require('./vite.dev.js');
11
11
 
12
12
  // 字体注入
13
13
  const { FontInjectionWebpackPlugin } = require('./plugins/FontInjectionWebpackPlugin.js');
@@ -49,6 +49,11 @@ exports.DebuggerInjectionPlugin = DebuggerInjectionPlugin;
49
49
  exports.makeViteDevConfig = makeViteDevConfig;
50
50
  exports.runViteDev = runViteDev;
51
51
 
52
+ // 公共 Vite 插件(供项目 vite.config.ts 直接引用)
53
+ exports.json5Plugin = json5Plugin;
54
+ exports.assetInlinePlugin = assetInlinePlugin;
55
+ exports.fontFamilyPlugin = fontFamilyPlugin;
56
+
52
57
  // 编译前检查器导出
53
58
  exports.runPreBuildChecks = runPreBuildChecks;
54
59
  exports.runTrackingCheck = runTrackingCheck;
package/core/vite.dev.js CHANGED
@@ -6,6 +6,117 @@ const { options } = require('./options.js');
6
6
  const { mergeOptions } = require('./utils/mergeOptions.js');
7
7
  const { buildDefines } = require('./utils/buildDefines.js');
8
8
  const { logOptions } = require('./utils/logOptions.js');
9
+ const { getOrGenerateFontCSS } = require('./utils/fontResolver.js');
10
+
11
+ // ── 公共 Vite 插件(供项目 vite.config.ts 直接引用) ──
12
+
13
+ /** JSON5 文件加载插件 */
14
+ function json5Plugin() {
15
+ return {
16
+ name: 'vite-plugin-json5',
17
+ transform(code, id) {
18
+ if (id.endsWith('.json5')) {
19
+ const JSON5 = require('json5');
20
+ const raw = fs.readFileSync(id, 'utf-8');
21
+ const parsed = JSON5.parse(raw);
22
+ return {
23
+ code: `export default ${JSON.stringify(parsed)};`,
24
+ map: null,
25
+ };
26
+ }
27
+ },
28
+ };
29
+ }
30
+
31
+ /** 资源内联插件(模拟 webpack 的 asset/inline 行为) */
32
+ function assetInlinePlugin() {
33
+ return {
34
+ name: 'vite-plugin-asset-inline',
35
+ enforce: 'pre',
36
+ transform(code, id) {
37
+ // .atlas 文件 -> base64 data URL
38
+ if (id.endsWith('.atlas')) {
39
+ const content = fs.readFileSync(id);
40
+ const base64 = content.toString('base64');
41
+ return {
42
+ code: `export default "data:text/atlas;base64,${base64}";`,
43
+ map: null,
44
+ };
45
+ }
46
+ // .fnt 文件 -> base64 data URL
47
+ if (id.endsWith('.fnt')) {
48
+ const content = fs.readFileSync(id);
49
+ const base64 = content.toString('base64');
50
+ return {
51
+ code: `export default "data:text/plain;base64,${base64}";`,
52
+ map: null,
53
+ };
54
+ }
55
+ // .xml 文件 -> 原始文本
56
+ if (id.endsWith('.xml')) {
57
+ const raw = fs.readFileSync(id, 'utf-8');
58
+ return {
59
+ code: `export default ${JSON.stringify(raw)};`,
60
+ map: null,
61
+ };
62
+ }
63
+ },
64
+ };
65
+ }
66
+
67
+ /** 字体注入插件(dev 模式:读取字体文件 base64 内联到 index.html) */
68
+ function fontFamilyPlugin() {
69
+ let _themeName = null;
70
+ let _themeConfig = null;
71
+
72
+ // 检测当前主题名(与 build.js 中 detectCurrentTheme 逻辑一致)
73
+ function detectTheme() {
74
+ const root = process.cwd();
75
+ const buildsConfigPath = path.join(root, 'builds.config.js');
76
+ let config = { sourceDir: 'src/theme', entryFile: 'src/theme/index.ts' };
77
+ if (fs.existsSync(buildsConfigPath)) {
78
+ try {
79
+ delete require.cache[require.resolve(buildsConfigPath)];
80
+ const buildsConfig = require(buildsConfigPath);
81
+ if (buildsConfig.themes) {
82
+ config = { ...config, ...buildsConfig.themes };
83
+ }
84
+ } catch (_) { /* ignore */ }
85
+ }
86
+ let name = null;
87
+ const entryPath = path.join(root, config.entryFile);
88
+ if (fs.existsSync(entryPath)) {
89
+ const content = fs.readFileSync(entryPath, 'utf8');
90
+ const match = content.match(/from\s+['"]\.\/([^'"]+)['"]/);
91
+ if (match) name = match[1];
92
+ }
93
+ return { themeName: name, themeConfig: config };
94
+ }
95
+
96
+ return {
97
+ name: 'vite-plugin-font-family',
98
+ apply: 'serve',
99
+ transformIndexHtml: {
100
+ order: 'pre',
101
+ handler() {
102
+ if (_themeName === null) {
103
+ const detected = detectTheme();
104
+ _themeName = detected.themeName;
105
+ _themeConfig = detected.themeConfig;
106
+ }
107
+ if (!_themeName) return '';
108
+ const css = getOrGenerateFontCSS({
109
+ projectRoot: process.cwd(),
110
+ themeName: _themeName,
111
+ themeConfig: _themeConfig,
112
+ });
113
+ return css ? [{ tag: 'style', attrs: { 'data-playable-fonts': '' }, children: css.replace(/<\/?style[^>]*>/g, ''), injectTo: 'head' }] : [];
114
+ },
115
+ },
116
+ };
117
+ }
118
+
119
+ // ── makeViteDevConfig / runViteDev ──
9
120
 
10
121
  /**
11
122
  * 创建 Vite 开发配置
@@ -67,113 +178,6 @@ function makeViteDevConfig(customOptions, customDefines, viteCustomConfig) {
67
178
  ...aliasConfig,
68
179
  };
69
180
 
70
- // JSON5 插件
71
- function json5Plugin() {
72
- return {
73
- name: 'vite-plugin-json5',
74
- transform(code, id) {
75
- if (id.endsWith('.json5')) {
76
- const JSON5 = require('json5');
77
- const raw = fs.readFileSync(id, 'utf-8');
78
- const parsed = JSON5.parse(raw);
79
- return {
80
- code: `export default ${JSON.stringify(parsed)};`,
81
- map: null,
82
- };
83
- }
84
- },
85
- };
86
- }
87
-
88
- // 资源内联插件(模拟 webpack 的 asset/inline 行为)
89
- function assetInlinePlugin() {
90
- return {
91
- name: 'vite-plugin-asset-inline',
92
- enforce: 'pre',
93
- transform(code, id) {
94
- // .atlas 文件 -> base64 data URL
95
- if (id.endsWith('.atlas')) {
96
- const content = fs.readFileSync(id);
97
- const base64 = content.toString('base64');
98
- return {
99
- code: `export default "data:text/atlas;base64,${base64}";`,
100
- map: null,
101
- };
102
- }
103
- // .fnt 文件 -> base64 data URL
104
- if (id.endsWith('.fnt')) {
105
- const content = fs.readFileSync(id);
106
- const base64 = content.toString('base64');
107
- return {
108
- code: `export default "data:text/plain;base64,${base64}";`,
109
- map: null,
110
- };
111
- }
112
- // .xml 文件 -> 原始文本
113
- if (id.endsWith('.xml')) {
114
- const raw = fs.readFileSync(id, 'utf-8');
115
- return {
116
- code: `export default ${JSON.stringify(raw)};`,
117
- map: null,
118
- };
119
- }
120
- },
121
- };
122
- }
123
-
124
- // 字体注入插件(dev 模式:读取字体文件 base64 内联到 index.html)
125
- function fontFamilyPlugin() {
126
- const { getOrGenerateFontCSS } = require('./utils/fontResolver');
127
- let _themeName = null;
128
- let _themeConfig = null;
129
-
130
- // 尝试检测当前主题名(与 build.js 中 detectCurrentTheme 逻辑一致)
131
- function detectTheme() {
132
- const root = process.cwd();
133
- const buildsConfigPath = path.join(root, 'builds.config.js');
134
- let config = { sourceDir: 'src/theme', entryFile: 'src/theme/index.ts' };
135
- if (fs.existsSync(buildsConfigPath)) {
136
- try {
137
- delete require.cache[require.resolve(buildsConfigPath)];
138
- const buildsConfig = require(buildsConfigPath);
139
- if (buildsConfig.themes) {
140
- config = { ...config, ...buildsConfig.themes };
141
- }
142
- } catch (_) { /* ignore */ }
143
- }
144
- let name = null;
145
- const entryPath = path.join(root, config.entryFile);
146
- if (fs.existsSync(entryPath)) {
147
- const content = fs.readFileSync(entryPath, 'utf8');
148
- const match = content.match(/from\s+['"]\.\/([^'"]+)['"]/);
149
- if (match) name = match[1];
150
- }
151
- return { themeName: name, themeConfig: config };
152
- }
153
-
154
- return {
155
- name: 'vite-plugin-font-family',
156
- apply: 'serve',
157
- transformIndexHtml: {
158
- order: 'pre',
159
- handler() {
160
- if (_themeName === null) {
161
- const detected = detectTheme();
162
- _themeName = detected.themeName;
163
- _themeConfig = detected.themeConfig;
164
- }
165
- if (!_themeName) return '';
166
- const css = getOrGenerateFontCSS({
167
- projectRoot: process.cwd(),
168
- themeName: _themeName,
169
- themeConfig: _themeConfig,
170
- });
171
- return css ? [{ tag: 'style', attrs: { 'data-playable-fonts': '' }, children: css.replace(/<\/?style[^>]*>/g, ''), injectTo: 'head' }] : [];
172
- },
173
- },
174
- };
175
- }
176
-
177
181
  /** @type {import('vite').UserConfig} */
178
182
  const viteConfig = {
179
183
  root: '.',
@@ -194,7 +198,6 @@ function makeViteDevConfig(customOptions, customDefines, viteCustomConfig) {
194
198
 
195
199
  // 合并自定义配置
196
200
  if (viteCustomConfig) {
197
- // 简单合并:自定义配置中的字段会覆盖默认配置
198
201
  const { plugins: customPlugins, define: customDefine, resolve: customResolve, server: customServer, build: customBuild, ...rest } = viteCustomConfig;
199
202
 
200
203
  if (customPlugins) {
@@ -248,9 +251,6 @@ function deepMergeViteConfig(base, override) {
248
251
 
249
252
  /**
250
253
  * 尝试加载项目根目录的 vite.config.ts。
251
- * 使用 Vite 内置的 loadConfigFromFile API。
252
- * 注意:vite 是项目的 devDependency,不是 scripts 的依赖,
253
- * 因此需要通过 createRequire 从项目根目录解析 require 路径。
254
254
  */
255
255
  async function loadProjectViteConfig(root) {
256
256
  const candidates = ['vite.config.ts', 'vite.config.js', 'vite.config.mjs'];
@@ -261,7 +261,6 @@ async function loadProjectViteConfig(root) {
261
261
  }
262
262
  if (!configPath) return null;
263
263
 
264
- // 从项目根目录创建 require,解决 vite 模块解析路径问题
265
264
  const { createRequire } = require('module');
266
265
  let projRequire;
267
266
  try {
@@ -270,7 +269,6 @@ async function loadProjectViteConfig(root) {
270
269
  projRequire = createRequire(path.join(root, 'noop.js'));
271
270
  }
272
271
 
273
- // 通过项目的 require 路径加载 vite
274
272
  let loadConfigFromFile;
275
273
  try {
276
274
  loadConfigFromFile = projRequire('vite').loadConfigFromFile;
@@ -309,33 +307,30 @@ async function loadProjectViteConfig(root) {
309
307
  * 1. makeViteDevConfig 构建的默认配置(fontFamilyPlugin、json5Plugin 等)
310
308
  * 2. 项目根目录的 vite.config.ts(如果存在,覆盖/扩充默认配置)
311
309
  * 3. 传入的 viteConfig / customOptions / customDefines / viteCustomConfig
312
- *
313
- * @param {import('vite').UserConfig} [viteConfig] - Vite 配置,不传则自动创建
314
- * @param {Partial<import('./index').CLIOptions>} [customOptions] - 自定义选项
315
- * @param {Record<string, any>} [customDefines] - 额外的 define 常量
316
- * @param {import('vite').UserConfig} [viteCustomConfig] - 自定义 Vite 配置
317
310
  */
318
311
  async function runViteDev(viteConfig, customOptions, customDefines, viteCustomConfig) {
319
312
  if (!viteConfig) {
320
313
  viteConfig = makeViteDevConfig(customOptions, customDefines, viteCustomConfig);
321
314
  }
322
315
 
323
- // 加载项目根目录的 vite 配置文件并合并(项目配置覆盖 scripts 默认)
324
316
  const projectRoot = process.cwd();
325
317
  const projectConfig = await loadProjectViteConfig(projectRoot);
326
318
  if (projectConfig) {
327
319
  viteConfig = deepMergeViteConfig(viteConfig, projectConfig);
328
320
  }
329
321
 
330
- // vite 是项目的 devDependency,从项目目录解析
331
322
  const { createRequire } = require('module');
332
323
  const projRequire = createRequire(path.join(projectRoot, 'package.json'));
333
324
  const { createServer } = projRequire('vite');
334
- // configFile: false 防止 Vite 再次加载项目的 vite.config.ts(已经手动合并了)
335
325
  const server = await createServer({ ...viteConfig, configFile: false });
336
326
  await server.listen();
337
327
  server.printUrls();
338
328
  }
339
329
 
330
+ // ── 导出 ──
331
+
332
+ exports.json5Plugin = json5Plugin;
333
+ exports.assetInlinePlugin = assetInlinePlugin;
334
+ exports.fontFamilyPlugin = fontFamilyPlugin;
340
335
  exports.makeViteDevConfig = makeViteDevConfig;
341
336
  exports.runViteDev = runViteDev;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playcraft/devkit",
3
- "version": "1.0.18",
3
+ "version": "1.0.19",
4
4
  "description": "HTML5 Playable Ads 构建工具,支持多广告渠道打包",
5
5
  "main": "core/index.js",
6
6
  "module": "core/index.js",