@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 +9 -0
- package/core/index.js +6 -1
- package/core/vite.dev.js +116 -121
- package/package.json +1 -1
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;
|