@playcraft/devkit 1.0.19 → 1.0.20

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.
Files changed (49) hide show
  1. package/cli/bin/playable-scripts.js +1 -44
  2. package/cli/commands/build.js +18 -130
  3. package/cli/commands/builds.js +2 -13
  4. package/cli/commands/dev.js +1 -7
  5. package/cli/commands/pack.js +39 -308
  6. package/cli/commands/vite-dev.js +1 -7
  7. package/core/batch-build.js +125 -1091
  8. package/core/constants.js +6 -0
  9. package/core/cos-uploader.js +20 -264
  10. package/core/index.js +7 -76
  11. package/core/loaders/gltf-loader.js +28 -74
  12. package/core/options.js +15 -310
  13. package/core/plugins/AdikteevInjectorPlugin.js +4 -26
  14. package/core/plugins/BigoAdsInjectorPlugin.js +4 -21
  15. package/core/plugins/DAPIInjectorPlugin.js +2 -25
  16. package/core/plugins/DebuggerInjectionPlugin.js +3 -31
  17. package/core/plugins/ExitAPIInjectorPlugin.js +3 -57
  18. package/core/plugins/FflateCompressionPlugin.js +37 -225
  19. package/core/plugins/FontInjectionWebpackPlugin.js +4 -46
  20. package/core/plugins/LiftoffInjectorPlugin.js +4 -26
  21. package/core/plugins/MRAIDInjectorPlugin.js +2 -24
  22. package/core/plugins/MintegralInjectorPlugin.js +2 -25
  23. package/core/plugins/PangleInjectorPlugin.js +2 -24
  24. package/core/plugins/SnapchatInjectorPlugin.js +4 -26
  25. package/core/plugins/TikTokInjectorPlugin.js +2 -24
  26. package/core/plugins/UnityInjectorPlugin.js +8 -37
  27. package/core/plugins/ZipPlugin.js +19 -138
  28. package/core/utils/buildDefines.js +2 -29
  29. package/core/utils/buildTemplateString.js +5 -40
  30. package/core/utils/date.js +1 -16
  31. package/core/utils/fontRegistry.js +13 -81
  32. package/core/utils/fontResolver.js +37 -335
  33. package/core/utils/generateAdikteevHtmlWebpackPluginConfig.js +7 -42
  34. package/core/utils/generateBigabidHtmlWebpackPluginConfig.js +3 -30
  35. package/core/utils/generateInMobiHtmlWebpackPluginConfig.js +7 -43
  36. package/core/utils/injectSDKPlugins.js +11 -58
  37. package/core/utils/logOptions.js +4 -37
  38. package/core/utils/mergeOptions.js +2 -19
  39. package/core/utils/parseArgvOptions.js +5 -110
  40. package/core/utils/resolveChannelFold2Zip.js +3 -15
  41. package/core/utils/validateThemeData.js +25 -220
  42. package/core/validators/pre-build-checker.js +21 -201
  43. package/core/validators/tracking-validator.js +40 -358
  44. package/core/vite.dev.js +17 -321
  45. package/core/webpack.build.js +56 -489
  46. package/core/webpack.common.js +11 -177
  47. package/core/webpack.dev.js +5 -82
  48. package/package.json +2 -3
  49. package/README.md +0 -259
package/core/vite.dev.js CHANGED
@@ -1,336 +1,32 @@
1
- 'use strict';
2
-
3
- const path = require('path');
4
- const fs = require('fs');
5
- const { options } = require('./options.js');
6
- const { mergeOptions } = require('./utils/mergeOptions.js');
7
- const { buildDefines } = require('./utils/buildDefines.js');
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 ──
120
-
1
+ "use strict";const path=require("path");const fs=require("fs");const{options}=require("./options.js");const{mergeOptions}=require("./utils/mergeOptions.js");const{buildDefines}=require("./utils/buildDefines.js");const{logOptions}=require("./utils/logOptions.js");const{getOrGenerateFontCSS}=require("./utils/fontResolver.js");// ── 公共 Vite 插件(供项目 vite.config.ts 直接引用) ──
2
+ /** JSON5 文件加载插件 */function json5Plugin(){return{name:"vite-plugin-json5",transform(code,id){if(id.endsWith(".json5")){const JSON5=require("json5");const raw=fs.readFileSync(id,"utf-8");const parsed=JSON5.parse(raw);return{code:`export default ${JSON.stringify(parsed)};`,map:null}}}}}/** 资源内联插件(模拟 webpack 的 asset/inline 行为) */function assetInlinePlugin(){return{name:"vite-plugin-asset-inline",enforce:"pre",transform(code,id){// .atlas 文件 -> base64 data URL
3
+ if(id.endsWith(".atlas")){const content=fs.readFileSync(id);const base64=content.toString("base64");return{code:`export default "data:text/atlas;base64,${base64}";`,map:null}}// .fnt 文件 -> base64 data URL
4
+ if(id.endsWith(".fnt")){const content=fs.readFileSync(id);const base64=content.toString("base64");return{code:`export default "data:text/plain;base64,${base64}";`,map:null}}// .xml 文件 -> 原始文本
5
+ if(id.endsWith(".xml")){const raw=fs.readFileSync(id,"utf-8");return{code:`export default ${JSON.stringify(raw)};`,map:null}}}}}/** 字体注入插件(dev 模式:读取字体文件 base64 内联到 index.html) */function fontFamilyPlugin(){let _themeName=null;let _themeConfig=null;// 检测当前主题名(与 build.js 中 detectCurrentTheme 逻辑一致)
6
+ function detectTheme(){const root=process.cwd();const buildsConfigPath=path.join(root,"builds.config.js");let config={sourceDir:"src/theme",entryFile:"src/theme/index.ts"};if(fs.existsSync(buildsConfigPath)){try{delete require.cache[require.resolve(buildsConfigPath)];const buildsConfig=require(buildsConfigPath);if(buildsConfig.themes){config={...config,...buildsConfig.themes}}}catch(_){/* ignore */}}let name=null;const entryPath=path.join(root,config.entryFile);if(fs.existsSync(entryPath)){const content=fs.readFileSync(entryPath,"utf8");const match=content.match(/from\s+['"]\.\/([^'"]+)['"]/);if(match)name=match[1]}return{themeName:name,themeConfig:config}}return{name:"vite-plugin-font-family",apply:"serve",transformIndexHtml:{order:"pre",handler(){if(_themeName===null){const detected=detectTheme();_themeName=detected.themeName;_themeConfig=detected.themeConfig}if(!_themeName)return"";const css=getOrGenerateFontCSS({projectRoot:process.cwd(),themeName:_themeName,themeConfig:_themeConfig});return css?[{tag:"style",attrs:{"data-playable-fonts":""},children:css.replace(/<\/?style[^>]*>/g,""),injectTo:"head"}]:[]}}}}// ── makeViteDevConfig / runViteDev ──
121
7
  /**
122
8
  * 创建 Vite 开发配置
123
9
  * @param {Partial<import('./index').CLIOptions>} [customOptions] - 自定义选项,会与默认选项合并
124
10
  * @param {Record<string, any>} [customDefines] - 额外的 define 常量
125
11
  * @param {import('vite').UserConfig} [viteCustomConfig] - 自定义 Vite 配置,会与默认配置合并
126
12
  * @returns {import('vite').UserConfig} 最终的 Vite 开发配置
127
- */
128
- function makeViteDevConfig(customOptions, customDefines, viteCustomConfig) {
129
- const devOptions = mergeOptions(options, customOptions);
130
- logOptions(devOptions);
131
- customDefines = customDefines || {};
132
- viteCustomConfig = viteCustomConfig || {};
133
-
134
- // 构建 define 常量(复用 webpack 的 buildDefines 逻辑)
135
- const defines = {
136
- ...buildDefines(),
137
- ...devOptions.defines,
138
- __DEV__: JSON.stringify(devOptions['dev'] === undefined ? true : devOptions['dev']),
139
- ...customDefines,
140
- };
141
-
142
- // 解析 tsconfig/jsconfig 路径别名
143
- const tsConfigPath = path.resolve(devOptions.tsConfig || 'tsconfig.json');
144
- const jsConfigPath = path.resolve(devOptions.jsConfig || 'jsconfig.json');
145
- let aliasConfig = {};
146
-
147
- // 尝试从 tsconfig/jsconfig 中读取 paths 配置
148
- let configFilePath = null;
149
- if (fs.existsSync(tsConfigPath)) {
150
- configFilePath = tsConfigPath;
151
- } else if (fs.existsSync(jsConfigPath)) {
152
- configFilePath = jsConfigPath;
153
- }
154
-
155
- if (configFilePath) {
156
- try {
157
- const JSON5 = require('json5');
158
- const configContent = fs.readFileSync(configFilePath, 'utf-8');
159
- const config = JSON5.parse(configContent);
160
- const paths = config.compilerOptions?.paths || {};
161
- for (const [alias, targets] of Object.entries(paths)) {
162
- // 将 tsconfig paths 格式 "foo/*" -> ["src/foo/*"] 转换为 vite alias
163
- const cleanAlias = alias.replace('/*', '');
164
- const cleanTarget = targets[0]?.replace('/*', '') || '';
165
- if (cleanAlias && cleanTarget) {
166
- aliasConfig[cleanAlias] = path.resolve(cleanTarget);
167
- }
168
- }
169
- } catch (err) {
170
- console.log('\x1b[33m⚠️ 读取路径配置失败: ' + err.message + '\x1b[0m');
171
- }
172
- }
173
-
174
- // 默认别名
175
- aliasConfig = {
176
- assets: path.resolve('assets'),
177
- '@': path.resolve('src'),
178
- ...aliasConfig,
179
- };
180
-
181
- /** @type {import('vite').UserConfig} */
182
- const viteConfig = {
183
- root: '.',
184
- resolve: {
185
- alias: aliasConfig,
186
- },
187
- plugins: [json5Plugin(), assetInlinePlugin(), fontFamilyPlugin()],
188
- define: defines,
189
- server: {
190
- port: devOptions['port'] || 3000,
191
- open: devOptions['open'] || false,
192
- },
193
- build: {
194
- outDir: devOptions['outDir'] || 'dist',
195
- sourcemap: true,
196
- },
197
- };
198
-
199
- // 合并自定义配置
200
- if (viteCustomConfig) {
201
- const { plugins: customPlugins, define: customDefine, resolve: customResolve, server: customServer, build: customBuild, ...rest } = viteCustomConfig;
202
-
203
- if (customPlugins) {
204
- viteConfig.plugins = [...viteConfig.plugins, ...customPlugins];
205
- }
206
- if (customDefine) {
207
- viteConfig.define = { ...viteConfig.define, ...customDefine };
208
- }
209
- if (customResolve) {
210
- viteConfig.resolve = {
211
- ...viteConfig.resolve,
212
- ...customResolve,
213
- alias: { ...viteConfig.resolve.alias, ...(customResolve.alias || {}) },
214
- };
215
- }
216
- if (customServer) {
217
- viteConfig.server = { ...viteConfig.server, ...customServer };
218
- }
219
- if (customBuild) {
220
- viteConfig.build = { ...viteConfig.build, ...customBuild };
221
- }
222
- Object.assign(viteConfig, rest);
223
- }
224
-
225
- return viteConfig;
226
- }
227
-
228
- /**
13
+ */function makeViteDevConfig(customOptions,customDefines,viteCustomConfig){const devOptions=mergeOptions(options,customOptions);logOptions(devOptions);customDefines=customDefines||{};viteCustomConfig=viteCustomConfig||{};// 构建 define 常量(复用 webpack 的 buildDefines 逻辑)
14
+ const defines={...buildDefines(),...devOptions.defines,__DEV__:JSON.stringify(devOptions["dev"]===undefined?true:devOptions["dev"]),...customDefines};// 解析 tsconfig/jsconfig 路径别名
15
+ const tsConfigPath=path.resolve(devOptions.tsConfig||"tsconfig.json");const jsConfigPath=path.resolve(devOptions.jsConfig||"jsconfig.json");let aliasConfig={};// 尝试从 tsconfig/jsconfig 中读取 paths 配置
16
+ let configFilePath=null;if(fs.existsSync(tsConfigPath)){configFilePath=tsConfigPath}else if(fs.existsSync(jsConfigPath)){configFilePath=jsConfigPath}if(configFilePath){try{var _config$compilerOptio;const JSON5=require("json5");const configContent=fs.readFileSync(configFilePath,"utf-8");const config=JSON5.parse(configContent);const paths=((_config$compilerOptio=config.compilerOptions)===null||_config$compilerOptio===void 0?void 0:_config$compilerOptio.paths)||{};for(const[alias,targets]of Object.entries(paths)){var _targets$;// 将 tsconfig paths 格式 "foo/*" -> ["src/foo/*"] 转换为 vite alias
17
+ const cleanAlias=alias.replace("/*","");const cleanTarget=((_targets$=targets[0])===null||_targets$===void 0?void 0:_targets$.replace("/*",""))||"";if(cleanAlias&&cleanTarget){aliasConfig[cleanAlias]=path.resolve(cleanTarget)}}}catch(err){console.log("\x1B[33m\u26A0\uFE0F \u8BFB\u53D6\u8DEF\u5F84\u914D\u7F6E\u5931\u8D25: "+err.message+"\x1B[0m")}}// 默认别名
18
+ aliasConfig={assets:path.resolve("assets"),"@":path.resolve("src"),...aliasConfig};/** @type {import('vite').UserConfig} */const viteConfig={root:".",resolve:{alias:aliasConfig},plugins:[json5Plugin(),assetInlinePlugin(),fontFamilyPlugin()],define:defines,server:{port:devOptions["port"]||3000,open:devOptions["open"]||false},build:{outDir:devOptions["outDir"]||"dist",sourcemap:true}};// 合并自定义配置
19
+ if(viteCustomConfig){const{plugins:customPlugins,define:customDefine,resolve:customResolve,server:customServer,build:customBuild,...rest}=viteCustomConfig;if(customPlugins){viteConfig.plugins=[...viteConfig.plugins,...customPlugins]}if(customDefine){viteConfig.define={...viteConfig.define,...customDefine}}if(customResolve){viteConfig.resolve={...viteConfig.resolve,...customResolve,alias:{...viteConfig.resolve.alias,...(customResolve.alias||{})}}}if(customServer){viteConfig.server={...viteConfig.server,...customServer}}if(customBuild){viteConfig.build={...viteConfig.build,...customBuild}}Object.assign(viteConfig,rest)}return viteConfig}/**
229
20
  * 深度合并两个 Vite 配置对象。override 覆盖 base。
230
21
  * 数组会拼接(plugins),其余字段浅覆盖。
231
- */
232
- function deepMergeViteConfig(base, override) {
233
- if (!override || typeof override !== 'object') return base;
234
- const result = { ...base };
235
- for (const key of Object.keys(override)) {
236
- const bv = base[key];
237
- const ov = override[key];
238
- if (key === 'plugins' && Array.isArray(bv) && Array.isArray(ov)) {
239
- result[key] = [...bv, ...ov];
240
- } else if (
241
- ov !== null && typeof ov === 'object' && !Array.isArray(ov) &&
242
- bv !== null && typeof bv === 'object' && !Array.isArray(bv)
243
- ) {
244
- result[key] = { ...bv, ...ov };
245
- } else {
246
- result[key] = ov;
247
- }
248
- }
249
- return result;
250
- }
251
-
252
- /**
22
+ */function deepMergeViteConfig(base,override){if(!override||typeof override!=="object")return base;const result={...base};for(const key of Object.keys(override)){const bv=base[key];const ov=override[key];if(key==="plugins"&&Array.isArray(bv)&&Array.isArray(ov)){result[key]=[...bv,...ov]}else if(ov!==null&&typeof ov==="object"&&!Array.isArray(ov)&&bv!==null&&typeof bv==="object"&&!Array.isArray(bv)){result[key]={...bv,...ov}}else{result[key]=ov}}return result}/**
253
23
  * 尝试加载项目根目录的 vite.config.ts。
254
- */
255
- async function loadProjectViteConfig(root) {
256
- const candidates = ['vite.config.ts', 'vite.config.js', 'vite.config.mjs'];
257
- let configPath = null;
258
- for (const c of candidates) {
259
- const p = path.join(root, c);
260
- if (fs.existsSync(p)) { configPath = p; break; }
261
- }
262
- if (!configPath) return null;
263
-
264
- const { createRequire } = require('module');
265
- let projRequire;
266
- try {
267
- projRequire = createRequire(path.join(root, 'package.json'));
268
- } catch (_) {
269
- projRequire = createRequire(path.join(root, 'noop.js'));
270
- }
271
-
272
- let loadConfigFromFile;
273
- try {
274
- loadConfigFromFile = projRequire('vite').loadConfigFromFile;
275
- } catch (_) {
276
- try {
277
- loadConfigFromFile = projRequire('vite/dist/node/config').loadConfigFromFile;
278
- } catch (_2) {
279
- console.log('\x1b[33m⚠️ [vite] Cannot load project config (loadConfigFromFile unavailable), using scripts default\x1b[0m');
280
- return null;
281
- }
282
- }
283
-
284
- if (!loadConfigFromFile) return null;
285
-
286
- try {
287
- const result = await loadConfigFromFile(
288
- { command: 'serve', mode: process.env.NODE_ENV || 'development' },
289
- configPath,
290
- root
291
- );
292
- if (result && result.config) {
293
- console.log(`[vite] Loaded project config: ${path.relative(root, configPath)}`);
294
- return result.config;
295
- }
296
- return null;
297
- } catch (err) {
298
- console.log(`\x1b[33m⚠️ [vite] Failed to load ${path.relative(root, configPath)}: ${err.message}, using scripts default\x1b[0m`);
299
- return null;
300
- }
301
- }
302
-
303
- /**
24
+ */async function loadProjectViteConfig(root){const candidates=["vite.config.ts","vite.config.js","vite.config.mjs"];let configPath=null;for(const c of candidates){const p=path.join(root,c);if(fs.existsSync(p)){configPath=p;break}}if(!configPath)return null;const{createRequire}=require("module");let projRequire;try{projRequire=createRequire(path.join(root,"package.json"))}catch(_){projRequire=createRequire(path.join(root,"noop.js"))}let loadConfigFromFile;try{loadConfigFromFile=projRequire("vite").loadConfigFromFile}catch(_){try{loadConfigFromFile=projRequire("vite/dist/node/config").loadConfigFromFile}catch(_2){console.log("\x1B[33m\u26A0\uFE0F [vite] Cannot load project config (loadConfigFromFile unavailable), using scripts default\x1B[0m");return null}}if(!loadConfigFromFile)return null;try{const result=await loadConfigFromFile({command:"serve",mode:process.env.NODE_ENV||"development"},configPath,root);if(result&&result.config){console.log(`[vite] Loaded project config: ${path.relative(root,configPath)}`);return result.config}return null}catch(err){console.log(`\x1b[33m⚠️ [vite] Failed to load ${path.relative(root,configPath)}: ${err.message}, using scripts default\x1b[0m`);return null}}/**
304
25
  * 启动 Vite 开发服务器。
305
26
  *
306
27
  * 配置优先级(从低到高):
307
28
  * 1. makeViteDevConfig 构建的默认配置(fontFamilyPlugin、json5Plugin 等)
308
29
  * 2. 项目根目录的 vite.config.ts(如果存在,覆盖/扩充默认配置)
309
30
  * 3. 传入的 viteConfig / customOptions / customDefines / viteCustomConfig
310
- */
311
- async function runViteDev(viteConfig, customOptions, customDefines, viteCustomConfig) {
312
- if (!viteConfig) {
313
- viteConfig = makeViteDevConfig(customOptions, customDefines, viteCustomConfig);
314
- }
315
-
316
- const projectRoot = process.cwd();
317
- const projectConfig = await loadProjectViteConfig(projectRoot);
318
- if (projectConfig) {
319
- viteConfig = deepMergeViteConfig(viteConfig, projectConfig);
320
- }
321
-
322
- const { createRequire } = require('module');
323
- const projRequire = createRequire(path.join(projectRoot, 'package.json'));
324
- const { createServer } = projRequire('vite');
325
- const server = await createServer({ ...viteConfig, configFile: false });
326
- await server.listen();
327
- server.printUrls();
328
- }
329
-
330
- // ── 导出 ──
331
-
332
- exports.json5Plugin = json5Plugin;
333
- exports.assetInlinePlugin = assetInlinePlugin;
334
- exports.fontFamilyPlugin = fontFamilyPlugin;
335
- exports.makeViteDevConfig = makeViteDevConfig;
336
- exports.runViteDev = runViteDev;
31
+ */async function runViteDev(viteConfig,customOptions,customDefines,viteCustomConfig){if(!viteConfig){viteConfig=makeViteDevConfig(customOptions,customDefines,viteCustomConfig)}const projectRoot=process.cwd();const projectConfig=await loadProjectViteConfig(projectRoot);if(projectConfig){viteConfig=deepMergeViteConfig(viteConfig,projectConfig)}const{createRequire}=require("module");const projRequire=createRequire(path.join(projectRoot,"package.json"));const{createServer}=projRequire("vite");const server=await createServer({...viteConfig,configFile:false});await server.listen();server.printUrls()}// ── 导出 ──
32
+ exports.json5Plugin=json5Plugin;exports.assetInlinePlugin=assetInlinePlugin;exports.fontFamilyPlugin=fontFamilyPlugin;exports.makeViteDevConfig=makeViteDevConfig;exports.runViteDev=runViteDev;