@playcraft/devkit 1.0.31-beta.11 → 1.0.31-beta.12
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/cli/bin/playable-scripts.js +6 -53
- package/cli/commands/build.js +32 -241
- package/cli/commands/builds.js +2 -13
- package/cli/commands/dev.js +1 -22
- package/cli/commands/pack.js +40 -320
- package/cli/commands/vite-dev.js +1 -7
- package/core/artifacts/emit-fonts.test.js +1 -0
- package/core/artifacts/emit.js +4 -98
- package/core/artifacts/fflate.js +1 -31
- package/core/artifacts/zip.js +1 -39
- package/core/batch-build.js +147 -1261
- package/core/constants.js +2 -20
- package/core/cos-uploader.js +23 -289
- package/core/engines/cocos/clean-cache.js +5 -179
- package/core/engines/cocos/clean-cache.test.js +1 -75
- package/core/engines/cocos/cli-build.js +2 -116
- package/core/engines/cocos/cli.js +11 -38
- package/core/engines/cocos/constants.js +1 -21
- package/core/engines/cocos/creator-cli.js +1 -108
- package/core/engines/cocos/dev-server.js +4 -412
- package/core/engines/cocos/fs.js +1 -105
- package/core/engines/cocos/injects/3x/init.js +19 -438
- package/core/engines/cocos/injects/3x/main.js +2 -52
- package/core/engines/cocos/injects/libs/pako.js +1 -2
- package/core/engines/cocos/mcp-refresh.js +2 -76
- package/core/engines/cocos/merge.js +3 -148
- package/core/engines/cocos/pack.js +1 -187
- package/core/engines/cocos/preview-cache.js +2 -48
- package/core/engines/cocos/preview-cache.test.js +1 -32
- package/core/engines/cocos/preview-concat.js +5 -189
- package/core/engines/cocos/preview-concat.test.js +1 -73
- package/core/engines/cocos/preview-json-hook.js +1 -200
- package/core/engines/cocos/preview-json-pack.js +3 -376
- package/core/engines/cocos/preview-json-pack.test.js +2 -226
- package/core/engines/cocos/preview-proxy.js +1 -132
- package/core/engines/cocos/rebundle-preview.js +2 -54
- package/core/engines/cocos/strip-social-share.js +3 -115
- package/core/engines/cocos/theme-assets.js +2 -161
- package/core/engines/cocos/writable-cli.js +2 -248
- package/core/engines/cocos/writable-cli.test.js +1 -112
- package/core/engines/web/index.js +1 -20
- package/core/engines/web/vite.dev.js +17 -322
- package/core/engines/web/webpack.build.js +37 -522
- package/core/engines/web/webpack.common.js +11 -177
- package/core/engines/web/webpack.dev.js +6 -88
- package/core/index.js +7 -101
- package/core/injectors/apply.js +1 -94
- package/core/injectors/check-channel-matrix.js +2 -130
- package/core/injectors/spec.js +9 -217
- package/core/loaders/gltf-loader.js +28 -74
- package/core/options.js +16 -353
- package/core/plugins/AdikteevInjectorPlugin.js +4 -26
- package/core/plugins/BigoAdsInjectorPlugin.js +4 -21
- package/core/plugins/DAPIInjectorPlugin.js +2 -25
- package/core/plugins/DebuggerInjectionPlugin.js +3 -31
- package/core/plugins/ExitAPIInjectorPlugin.js +3 -56
- package/core/plugins/FflateCompressionPlugin.js +40 -231
- package/core/plugins/FontInjectionWebpackPlugin.js +4 -46
- package/core/plugins/LiftoffInjectorPlugin.js +4 -26
- package/core/plugins/MRAIDInjectorPlugin.js +2 -24
- package/core/plugins/MintegralInjectorPlugin.js +2 -25
- package/core/plugins/PangleInjectorPlugin.js +2 -24
- package/core/plugins/PlaycraftOrientationInjectorPlugin.js +3 -29
- package/core/plugins/SnapchatInjectorPlugin.js +4 -26
- package/core/plugins/SocialMediaInjectorPlugin.js +7 -119
- package/core/plugins/TikTokInjectorPlugin.js +2 -24
- package/core/plugins/UnityInjectorPlugin.js +8 -37
- package/core/plugins/ZipPlugin.js +20 -154
- package/core/plugins/socialMediaVitePlugin.js +2 -108
- package/core/utils/buildDefines.js +2 -30
- package/core/utils/buildTemplateString.js +5 -39
- package/core/utils/date.js +1 -16
- package/core/utils/fontRegistry.js +13 -81
- package/core/utils/fontResolver.js +37 -335
- package/core/utils/generateAdikteevHtmlWebpackPluginConfig.js +7 -42
- package/core/utils/generateBigabidHtmlWebpackPluginConfig.js +3 -30
- package/core/utils/generateInMobiHtmlWebpackPluginConfig.js +7 -43
- package/core/utils/getPlaycraftOrientationSuffix.js +2 -9
- package/core/utils/injectSDKPlugins.js +13 -68
- package/core/utils/logOptions.js +5 -46
- package/core/utils/mergeOptions.js +2 -21
- package/core/utils/obfuscateLevels.js +10 -0
- package/core/utils/obfuscateLevels.test.js +10 -0
- package/core/utils/parseArgvOptions.js +5 -125
- package/core/utils/resolveChannelFold2Zip.js +3 -15
- package/core/utils/validateThemeData.js +26 -227
- package/core/validators/pre-build-checker.js +25 -287
- package/core/validators/tracking-validator.js +40 -441
- package/core/validators/tracking-validator.test.js +2 -84
- package/core/vite.dev.js +1 -1
- package/core/webpack.build.js +1 -1
- package/core/webpack.common.js +1 -1
- package/core/webpack.dev.js +1 -1
- package/package.json +2 -3
- package/README.md +0 -262
|
@@ -1,413 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const http = require('http');
|
|
5
|
-
const path = require('path');
|
|
6
|
-
const { spawnCocos, needsXvfb } = require('./cli.js');
|
|
7
|
-
const { syncGeneratedTheme, detectCurrentTheme, themeAssetStamp } = require('./theme-assets.js');
|
|
8
|
-
const { refreshAssets } = require('./mcp-refresh.js');
|
|
9
|
-
const { stripAdsdkCjsImport } = require('./strip-social-share.js');
|
|
10
|
-
const { concatPreviewScripts } = require('./preview-concat.js');
|
|
11
|
-
const { packPreviewJson } = require('./preview-json-pack.js');
|
|
12
|
-
const { findFreePort, startPreviewProxy } = require('./preview-proxy.js');
|
|
13
|
-
|
|
14
|
-
function sleep(ms) {
|
|
15
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function request(url, { method = 'GET', timeout = 8000 } = {}) {
|
|
19
|
-
return new Promise((resolve, reject) => {
|
|
20
|
-
const req = http.request(url, { method, timeout }, (res) => {
|
|
21
|
-
const chunks = [];
|
|
22
|
-
res.on('data', (c) => chunks.push(c));
|
|
23
|
-
res.on('end', () => {
|
|
24
|
-
resolve({
|
|
25
|
-
status: res.statusCode || 0,
|
|
26
|
-
body: Buffer.concat(chunks).toString('utf8'),
|
|
27
|
-
});
|
|
28
|
-
});
|
|
29
|
-
});
|
|
30
|
-
req.on('timeout', () => {
|
|
31
|
-
req.destroy();
|
|
32
|
-
reject(new Error(`timeout ${url}`));
|
|
33
|
-
});
|
|
34
|
-
req.on('error', reject);
|
|
35
|
-
req.end();
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function resolvePreviewScene(projectRoot, explicit) {
|
|
40
|
-
if (explicit) return explicit;
|
|
41
|
-
if (process.env.PREVIEW_SCENE) return process.env.PREVIEW_SCENE;
|
|
42
|
-
try {
|
|
43
|
-
const cfgPath = path.join(projectRoot, 'settings/cocos.config.json');
|
|
44
|
-
if (fs.existsSync(cfgPath)) {
|
|
45
|
-
const cfg = JSON.parse(fs.readFileSync(cfgPath, 'utf8'));
|
|
46
|
-
const fromConfig =
|
|
47
|
-
(cfg.builder && cfg.builder.common && cfg.builder.common.startScene) ||
|
|
48
|
-
(cfg.builder && cfg.builder.platforms && cfg.builder.platforms['web-desktop'] && cfg.builder.platforms['web-desktop'].startScene) ||
|
|
49
|
-
(cfg.builder && cfg.builder.platforms && cfg.builder.platforms['web-mobile'] && cfg.builder.platforms['web-mobile'].startScene);
|
|
50
|
-
if (fromConfig) return fromConfig;
|
|
51
|
-
}
|
|
52
|
-
} catch (_) {}
|
|
53
|
-
const scenesDir = path.join(projectRoot, 'assets/scenes');
|
|
54
|
-
if (fs.existsSync(scenesDir)) {
|
|
55
|
-
const first = fs.readdirSync(scenesDir).find((name) => name.endsWith('.scene'));
|
|
56
|
-
if (first) return `db://assets/scenes/${first}`;
|
|
57
|
-
}
|
|
58
|
-
return '';
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function killSocialShareForDev(projectRoot) {
|
|
62
|
-
const result = stripAdsdkCjsImport(projectRoot);
|
|
63
|
-
if (result.skipped && result.reason === 'missing') {
|
|
64
|
-
console.warn('[dev] adsdk CJS missing, skip social-share strip');
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
if (result.skipped && result.reason === 'already') {
|
|
68
|
-
console.log('[dev] social-share import() already stripped');
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
if (result.skipped) {
|
|
72
|
-
console.warn('[dev] social-share import() not found in CJS');
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
console.log('[dev] stripped social-share import() from adsdk CJS');
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const PREVIEW_MERGE_MARKER = path.join('temp', '.playcraft-preview-merge-ready');
|
|
79
|
-
|
|
80
|
-
function previewMergeMarkerPath(projectRoot) {
|
|
81
|
-
return path.join(projectRoot, PREVIEW_MERGE_MARKER);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function clearPreviewMergeMarker(projectRoot) {
|
|
85
|
-
try {
|
|
86
|
-
fs.unlinkSync(previewMergeMarkerPath(projectRoot));
|
|
87
|
-
} catch {
|
|
88
|
-
// ignore
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function markPreviewMergeReady(projectRoot) {
|
|
93
|
-
const marker = previewMergeMarkerPath(projectRoot);
|
|
94
|
-
fs.mkdirSync(path.dirname(marker), { recursive: true });
|
|
95
|
-
fs.writeFileSync(marker, `${Date.now()}\n`);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function shouldIgnoreWatch(file) {
|
|
99
|
-
if (!file) return false;
|
|
100
|
-
const base = path.basename(file);
|
|
101
|
-
if (base === '.DS_Store' || base === 'theme.generated.ts') return true;
|
|
102
|
-
if (base.startsWith('.') && base !== '.json5') return true;
|
|
103
|
-
const ext = path.extname(file).toLowerCase();
|
|
104
|
-
return ext === '.meta';
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
1
|
+
"use strict";const fs=require("fs");const http=require("http");const path=require("path");const{spawnCocos,needsXvfb}=require("./cli.js");const{syncGeneratedTheme,detectCurrentTheme,themeAssetStamp}=require("./theme-assets.js");const{refreshAssets}=require("./mcp-refresh.js");const{stripAdsdkCjsImport}=require("./strip-social-share.js");const{concatPreviewScripts}=require("./preview-concat.js");const{packPreviewJson}=require("./preview-json-pack.js");const{findFreePort,startPreviewProxy}=require("./preview-proxy.js");function sleep(ms){return new Promise(resolve=>setTimeout(resolve,ms))}function request(url,{method="GET",timeout=8000}={}){return new Promise((resolve,reject)=>{const req=http.request(url,{method,timeout},res=>{const chunks=[];res.on("data",c=>chunks.push(c));res.on("end",()=>{resolve({status:res.statusCode||0,body:Buffer.concat(chunks).toString("utf8")})})});req.on("timeout",()=>{req.destroy();reject(new Error(`timeout ${url}`))});req.on("error",reject);req.end()})}function resolvePreviewScene(projectRoot,explicit){if(explicit)return explicit;if(process.env.PREVIEW_SCENE)return process.env.PREVIEW_SCENE;try{const cfgPath=path.join(projectRoot,"settings/cocos.config.json");if(fs.existsSync(cfgPath)){const cfg=JSON.parse(fs.readFileSync(cfgPath,"utf8"));const fromConfig=cfg.builder&&cfg.builder.common&&cfg.builder.common.startScene||cfg.builder&&cfg.builder.platforms&&cfg.builder.platforms["web-desktop"]&&cfg.builder.platforms["web-desktop"].startScene||cfg.builder&&cfg.builder.platforms&&cfg.builder.platforms["web-mobile"]&&cfg.builder.platforms["web-mobile"].startScene;if(fromConfig)return fromConfig}}catch(_){}const scenesDir=path.join(projectRoot,"assets/scenes");if(fs.existsSync(scenesDir)){const first=fs.readdirSync(scenesDir).find(name=>name.endsWith(".scene"));if(first)return`db://assets/scenes/${first}`}return""}function killSocialShareForDev(projectRoot){const result=stripAdsdkCjsImport(projectRoot);if(result.skipped&&result.reason==="missing"){console.warn("[dev] adsdk CJS missing, skip social-share strip");return}if(result.skipped&&result.reason==="already"){console.log("[dev] social-share import() already stripped");return}if(result.skipped){console.warn("[dev] social-share import() not found in CJS");return}console.log("[dev] stripped social-share import() from adsdk CJS")}const PREVIEW_MERGE_MARKER=path.join("temp",".playcraft-preview-merge-ready");function previewMergeMarkerPath(projectRoot){return path.join(projectRoot,PREVIEW_MERGE_MARKER)}function clearPreviewMergeMarker(projectRoot){try{fs.unlinkSync(previewMergeMarkerPath(projectRoot))}catch{// ignore
|
|
2
|
+
}}function markPreviewMergeReady(projectRoot){const marker=previewMergeMarkerPath(projectRoot);fs.mkdirSync(path.dirname(marker),{recursive:true});fs.writeFileSync(marker,`${Date.now()}\n`)}function shouldIgnoreWatch(file){if(!file)return false;const base=path.basename(file);if(base===".DS_Store"||base==="theme.generated.ts")return true;if(base.startsWith(".")&&base!==".json5")return true;const ext=path.extname(file).toLowerCase();return ext===".meta"}/**
|
|
108
3
|
* 常驻官方 cocos CLI 预览:start-mcp-server(同一端口既有 / 也有 /mcp)。
|
|
109
|
-
*/
|
|
110
|
-
async function
|
|
111
|
-
const projectRoot = opts.projectRoot || process.cwd();
|
|
112
|
-
const port = Number(opts.port || process.env.PREVIEW_PORT || 3000);
|
|
113
|
-
const timeoutMs = Number(opts.timeoutMs || process.env.DEV_TIMEOUT_MS || 180000);
|
|
114
|
-
const debounceMs = Number(opts.debounceMs || process.env.DEV_DEBOUNCE_MS || 400);
|
|
115
|
-
const cmd = opts.cmd || process.argv[2] || 'start';
|
|
116
|
-
const scene = resolvePreviewScene(projectRoot, opts.scene);
|
|
117
|
-
const previewUrl = scene
|
|
118
|
-
? `http://127.0.0.1:${port}/?scene=${encodeURIComponent(scene)}`
|
|
119
|
-
: `http://127.0.0.1:${port}/`;
|
|
120
|
-
const watchDirs = ['assets', 'src/theme'].filter((dir) => fs.existsSync(path.join(projectRoot, dir)));
|
|
121
|
-
|
|
122
|
-
function previewUrlFor(previewPort) {
|
|
123
|
-
return scene
|
|
124
|
-
? `http://127.0.0.1:${previewPort}/?scene=${encodeURIComponent(scene)}`
|
|
125
|
-
: `http://127.0.0.1:${previewPort}/`;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
async function isPreviewUpOn(previewPort) {
|
|
129
|
-
try {
|
|
130
|
-
const res = await request(previewUrlFor(previewPort), { timeout: 1500 });
|
|
131
|
-
return res.status > 0 && res.status < 500;
|
|
132
|
-
} catch {
|
|
133
|
-
return false;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
async function isPreviewUp() {
|
|
138
|
-
return isPreviewUpOn(port);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
async function waitForPreviewOn(previewPort) {
|
|
142
|
-
const url = previewUrlFor(previewPort);
|
|
143
|
-
const start = Date.now();
|
|
144
|
-
let lastLog = 0;
|
|
145
|
-
while (Date.now() - start < timeoutMs) {
|
|
146
|
-
if (await isPreviewUpOn(previewPort)) return;
|
|
147
|
-
if (Date.now() - lastLog >= 5000) {
|
|
148
|
-
console.log(`[dev] waiting for ${url}`);
|
|
149
|
-
lastLog = Date.now();
|
|
150
|
-
}
|
|
151
|
-
await sleep(1000);
|
|
152
|
-
}
|
|
153
|
-
throw new Error(`preview not ready after ${timeoutMs}ms: ${url}`);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
function printBanner(reused) {
|
|
157
|
-
console.log(`[dev] ${reused ? 'reusing cocos CLI' : 'cocos CLI ready'}`);
|
|
158
|
-
console.log(`[dev] iframe → ${previewUrl}`);
|
|
159
|
-
console.log(`[dev] mcp → http://127.0.0.1:${port}/mcp`);
|
|
160
|
-
console.log(`[dev] watch ${watchDirs.map((d) => `${d}/`).join(' ')}`);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function syncThemeOnce() {
|
|
164
|
-
try {
|
|
165
|
-
const result = syncGeneratedTheme(projectRoot);
|
|
166
|
-
if (!result) {
|
|
167
|
-
console.log('[dev] no theme entry; skip generated module');
|
|
168
|
-
return false;
|
|
169
|
-
}
|
|
170
|
-
console.log(`[dev] synced theme ${result.themeName}${result.changed === false ? ' (unchanged)' : ''}`);
|
|
171
|
-
return result.changed !== false;
|
|
172
|
-
} catch (syncErr) {
|
|
173
|
-
console.warn(`[dev] theme sync skipped: ${syncErr.message}`);
|
|
174
|
-
return false;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
async function compile({ fatal = true, previewPort = port } = {}) {
|
|
179
|
-
const origin = previewUrlFor(previewPort);
|
|
180
|
-
if (!(await isPreviewUpOn(previewPort))) {
|
|
181
|
-
console.error(`[dev] preview is down: ${origin}`);
|
|
182
|
-
if (fatal) {
|
|
183
|
-
console.error('[dev] Run npm run dev first.');
|
|
184
|
-
process.exit(1);
|
|
185
|
-
}
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
console.log(`[dev] assets-refresh db://assets`);
|
|
190
|
-
try {
|
|
191
|
-
const res = await refreshAssets(previewPort, 'db://assets');
|
|
192
|
-
const err = res.parsed && (res.parsed.error || (res.parsed.result && res.parsed.result.isError));
|
|
193
|
-
console.log(`[dev] ${res.status}${err ? ' error' : ''}`);
|
|
194
|
-
if (res.status === 404) {
|
|
195
|
-
console.error('[dev] /mcp 不存在。请停掉当前预览,重新 npm run dev(会起 start-mcp-server)');
|
|
196
|
-
}
|
|
197
|
-
if ((res.status >= 400 || err) && fatal) process.exit(1);
|
|
198
|
-
} catch (err) {
|
|
199
|
-
console.error(`[dev] compile failed: ${err.message}`);
|
|
200
|
-
if (fatal) process.exit(1);
|
|
201
|
-
}
|
|
202
|
-
await bundlePreviewAssets({ previewPort });
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
async function bundlePreviewAssets({ previewPort = port } = {}) {
|
|
206
|
-
bundlePreviewScripts();
|
|
207
|
-
try {
|
|
208
|
-
const result = await packPreviewJson(projectRoot, {
|
|
209
|
-
previewOrigin: `http://127.0.0.1:${previewPort}`,
|
|
210
|
-
});
|
|
211
|
-
if (!result) return;
|
|
212
|
-
const kb = Math.max(1, Math.round(result.bytes / 1024));
|
|
213
|
-
console.log(`[dev] preview json ${result.files} → 1 pack (${kb} kB)`);
|
|
214
|
-
markPreviewMergeReady(projectRoot);
|
|
215
|
-
} catch (err) {
|
|
216
|
-
console.warn(`[dev] preview json pack skipped: ${err.message}`);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
function bundlePreviewScripts() {
|
|
221
|
-
try {
|
|
222
|
-
const result = concatPreviewScripts(projectRoot);
|
|
223
|
-
if (!result) return;
|
|
224
|
-
const kb = Math.max(1, Math.round(result.bytes / 1024));
|
|
225
|
-
console.log(`[dev] preview scripts ${result.modules} → 1 bundle (${kb} kB)`);
|
|
226
|
-
} catch (err) {
|
|
227
|
-
console.warn(`[dev] preview script concat skipped: ${err.message}`);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
function watchAndCompile() {
|
|
232
|
-
let timer = null;
|
|
233
|
-
let compiling = false;
|
|
234
|
-
let pending = null;
|
|
235
|
-
|
|
236
|
-
const queue = (rel) => {
|
|
237
|
-
pending = rel;
|
|
238
|
-
if (timer) clearTimeout(timer);
|
|
239
|
-
timer = setTimeout(() => {
|
|
240
|
-
timer = null;
|
|
241
|
-
run();
|
|
242
|
-
}, debounceMs);
|
|
243
|
-
};
|
|
244
|
-
|
|
245
|
-
const run = async () => {
|
|
246
|
-
if (compiling) return;
|
|
247
|
-
const rel = pending;
|
|
248
|
-
pending = null;
|
|
249
|
-
compiling = true;
|
|
250
|
-
if (rel) console.log(`[dev] change ${rel}`);
|
|
251
|
-
try {
|
|
252
|
-
if (
|
|
253
|
-
!rel
|
|
254
|
-
|| rel.startsWith('src/theme')
|
|
255
|
-
|| /resources\/textures\//.test(rel)
|
|
256
|
-
) {
|
|
257
|
-
syncThemeOnce();
|
|
258
|
-
}
|
|
259
|
-
await compile({ fatal: false });
|
|
260
|
-
} finally {
|
|
261
|
-
compiling = false;
|
|
262
|
-
if (pending) queue(pending);
|
|
263
|
-
}
|
|
264
|
-
};
|
|
265
|
-
|
|
266
|
-
for (const dir of watchDirs) {
|
|
267
|
-
const abs = path.join(projectRoot, dir);
|
|
268
|
-
fs.watch(abs, { recursive: true }, (_event, file) => {
|
|
269
|
-
if (shouldIgnoreWatch(file)) return;
|
|
270
|
-
const rel = path.join(dir, file || '').replace(/\\/g, '/');
|
|
271
|
-
queue(rel);
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
const themeName = detectCurrentTheme(projectRoot, {
|
|
276
|
-
sourceDir: 'src/theme',
|
|
277
|
-
entryFile: 'src/theme/index.ts',
|
|
278
|
-
});
|
|
279
|
-
const themeAssetsDir = themeName
|
|
280
|
-
? path.join(projectRoot, 'src/theme', themeName, 'assets')
|
|
281
|
-
: '';
|
|
282
|
-
if (themeAssetsDir && fs.existsSync(themeAssetsDir)) {
|
|
283
|
-
fs.watch(themeAssetsDir, () => {
|
|
284
|
-
queue(path.join('src/theme', themeName, 'assets'));
|
|
285
|
-
});
|
|
286
|
-
let stamp = themeAssetStamp(themeAssetsDir);
|
|
287
|
-
setInterval(() => {
|
|
288
|
-
const next = themeAssetStamp(themeAssetsDir);
|
|
289
|
-
if (next !== stamp) {
|
|
290
|
-
stamp = next;
|
|
291
|
-
queue(path.join('src/theme', themeName, 'assets'));
|
|
292
|
-
}
|
|
293
|
-
}, 1000);
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
function holdUntilExit(child, proxy) {
|
|
298
|
-
const stop = () => {
|
|
299
|
-
if (child && child.exitCode == null) {
|
|
300
|
-
child.kill('SIGTERM');
|
|
301
|
-
}
|
|
302
|
-
if (proxy && proxy.close) {
|
|
303
|
-
Promise.resolve(proxy.close()).finally(() => process.exit(0));
|
|
304
|
-
return;
|
|
305
|
-
}
|
|
306
|
-
process.exit(0);
|
|
307
|
-
};
|
|
308
|
-
process.on('SIGINT', stop);
|
|
309
|
-
process.on('SIGTERM', stop);
|
|
310
|
-
|
|
311
|
-
if (child) {
|
|
312
|
-
child.on('exit', (code, signal) => {
|
|
313
|
-
console.log(`[dev] cocos CLI exited (${signal || code})`);
|
|
314
|
-
if (proxy && proxy.close) {
|
|
315
|
-
Promise.resolve(proxy.close()).finally(() => process.exit(code == null ? 1 : code));
|
|
316
|
-
return;
|
|
317
|
-
}
|
|
318
|
-
process.exit(code == null ? 1 : code);
|
|
319
|
-
});
|
|
320
|
-
return;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
console.log('[dev] CLI already running; Ctrl+C leaves it open');
|
|
324
|
-
setInterval(() => {}, 60 * 1000);
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
async function warmPreviewAfterReady(previewPort) {
|
|
328
|
-
// Cold sandbox: library/ is empty until assets-refresh; skipping compile leaves JSON unpack hooked but empty → 100+ UUID requests.
|
|
329
|
-
syncThemeOnce();
|
|
330
|
-
await compile({ fatal: false, previewPort });
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
async function start() {
|
|
334
|
-
clearPreviewMergeMarker(projectRoot);
|
|
335
|
-
if (await isPreviewUp()) {
|
|
336
|
-
console.warn('[dev] reusing CLI without cache proxy; restart npm run dev to enable long-cache');
|
|
337
|
-
printBanner(true);
|
|
338
|
-
await warmPreviewAfterReady(port);
|
|
339
|
-
watchAndCompile();
|
|
340
|
-
holdUntilExit(null);
|
|
341
|
-
return;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
if (needsXvfb()) {
|
|
345
|
-
console.log('[dev] linux, wrapping xvfb-run -a');
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
const cliPort = await findFreePort(port);
|
|
349
|
-
|
|
350
|
-
const args = [
|
|
351
|
-
'--no-interactive',
|
|
352
|
-
'start-mcp-server',
|
|
353
|
-
'--project',
|
|
354
|
-
projectRoot,
|
|
355
|
-
'--port',
|
|
356
|
-
String(cliPort),
|
|
357
|
-
];
|
|
358
|
-
if (scene) {
|
|
359
|
-
console.log(`[dev] start scene ${scene}`);
|
|
360
|
-
}
|
|
361
|
-
console.log(`[dev] cocos ${args.join(' ')}`);
|
|
362
|
-
|
|
363
|
-
const child = spawnCocos(args, {
|
|
364
|
-
cwd: projectRoot,
|
|
365
|
-
env: process.env,
|
|
366
|
-
stdio: 'inherit',
|
|
367
|
-
});
|
|
368
|
-
|
|
369
|
-
child.on('error', (err) => {
|
|
370
|
-
console.error(err);
|
|
371
|
-
process.exit(1);
|
|
372
|
-
});
|
|
373
|
-
|
|
374
|
-
let proxy;
|
|
375
|
-
try {
|
|
376
|
-
await waitForPreviewOn(cliPort);
|
|
377
|
-
console.log(`[dev] cocos CLI listening on ${cliPort} (public ${port} still closed)`);
|
|
378
|
-
await warmPreviewAfterReady(cliPort);
|
|
379
|
-
proxy = await startPreviewProxy({ listenPort: port, targetPort: cliPort });
|
|
380
|
-
console.log(`[dev] cache proxy ${port} → CLI ${cliPort} (preview merge ready)`);
|
|
381
|
-
} catch (err) {
|
|
382
|
-
console.error(`[dev] ${err.message}`);
|
|
383
|
-
child.kill('SIGTERM');
|
|
384
|
-
if (proxy && proxy.close) await proxy.close();
|
|
385
|
-
process.exit(1);
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
printBanner(false);
|
|
389
|
-
watchAndCompile();
|
|
390
|
-
holdUntilExit(child, proxy);
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
killSocialShareForDev(projectRoot);
|
|
394
|
-
if (cmd === 'compile' || cmd === 'refresh') {
|
|
395
|
-
await compile();
|
|
396
|
-
return;
|
|
397
|
-
}
|
|
398
|
-
if (cmd === 'start' || cmd === 'dev') {
|
|
399
|
-
await start();
|
|
400
|
-
return;
|
|
401
|
-
}
|
|
402
|
-
console.error(`[dev] unknown command: ${cmd}`);
|
|
403
|
-
console.error('[dev] usage: playable-scripts dev [start|compile]');
|
|
404
|
-
process.exit(1);
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
module.exports = {
|
|
408
|
-
runCocosDev,
|
|
409
|
-
previewMergeMarkerPath,
|
|
410
|
-
clearPreviewMergeMarker,
|
|
411
|
-
markPreviewMergeReady,
|
|
412
|
-
PREVIEW_MERGE_MARKER,
|
|
413
|
-
};
|
|
4
|
+
*/async function runCocosDev(opts={}){const projectRoot=opts.projectRoot||process.cwd();const port=Number(opts.port||process.env.PREVIEW_PORT||3000);const timeoutMs=Number(opts.timeoutMs||process.env.DEV_TIMEOUT_MS||180000);const debounceMs=Number(opts.debounceMs||process.env.DEV_DEBOUNCE_MS||400);const cmd=opts.cmd||process.argv[2]||"start";const scene=resolvePreviewScene(projectRoot,opts.scene);const previewUrl=scene?`http://127.0.0.1:${port}/?scene=${encodeURIComponent(scene)}`:`http://127.0.0.1:${port}/`;const watchDirs=["assets","src/theme"].filter(dir=>fs.existsSync(path.join(projectRoot,dir)));function previewUrlFor(previewPort){return scene?`http://127.0.0.1:${previewPort}/?scene=${encodeURIComponent(scene)}`:`http://127.0.0.1:${previewPort}/`}async function isPreviewUpOn(previewPort){try{const res=await request(previewUrlFor(previewPort),{timeout:1500});return res.status>0&&res.status<500}catch{return false}}async function isPreviewUp(){return isPreviewUpOn(port)}async function waitForPreviewOn(previewPort){const url=previewUrlFor(previewPort);const start=Date.now();let lastLog=0;while(Date.now()-start<timeoutMs){if(await isPreviewUpOn(previewPort))return;if(Date.now()-lastLog>=5000){console.log(`[dev] waiting for ${url}`);lastLog=Date.now()}await sleep(1000)}throw new Error(`preview not ready after ${timeoutMs}ms: ${url}`)}function printBanner(reused){console.log(`[dev] ${reused?"reusing cocos CLI":"cocos CLI ready"}`);console.log(`[dev] iframe → ${previewUrl}`);console.log(`[dev] mcp → http://127.0.0.1:${port}/mcp`);console.log(`[dev] watch ${watchDirs.map(d=>`${d}/`).join(" ")}`)}function syncThemeOnce(){try{const result=syncGeneratedTheme(projectRoot);if(!result){console.log("[dev] no theme entry; skip generated module");return false}console.log(`[dev] synced theme ${result.themeName}${result.changed===false?" (unchanged)":""}`);return result.changed!==false}catch(syncErr){console.warn(`[dev] theme sync skipped: ${syncErr.message}`);return false}}async function compile({fatal=true,previewPort=port}={}){const origin=previewUrlFor(previewPort);if(!(await isPreviewUpOn(previewPort))){console.error(`[dev] preview is down: ${origin}`);if(fatal){console.error("[dev] Run npm run dev first.");process.exit(1)}return}console.log(`[dev] assets-refresh db://assets`);try{const res=await refreshAssets(previewPort,"db://assets");const err=res.parsed&&(res.parsed.error||res.parsed.result&&res.parsed.result.isError);console.log(`[dev] ${res.status}${err?" error":""}`);if(res.status===404){console.error("[dev] /mcp \u4E0D\u5B58\u5728\u3002\u8BF7\u505C\u6389\u5F53\u524D\u9884\u89C8\uFF0C\u91CD\u65B0 npm run dev\uFF08\u4F1A\u8D77 start-mcp-server\uFF09")}if((res.status>=400||err)&&fatal)process.exit(1)}catch(err){console.error(`[dev] compile failed: ${err.message}`);if(fatal)process.exit(1)}await bundlePreviewAssets({previewPort})}async function bundlePreviewAssets({previewPort=port}={}){bundlePreviewScripts();try{const result=await packPreviewJson(projectRoot,{previewOrigin:`http://127.0.0.1:${previewPort}`});if(!result)return;const kb=Math.max(1,Math.round(result.bytes/1024));console.log(`[dev] preview json ${result.files} → 1 pack (${kb} kB)`);markPreviewMergeReady(projectRoot)}catch(err){console.warn(`[dev] preview json pack skipped: ${err.message}`)}}function bundlePreviewScripts(){try{const result=concatPreviewScripts(projectRoot);if(!result)return;const kb=Math.max(1,Math.round(result.bytes/1024));console.log(`[dev] preview scripts ${result.modules} → 1 bundle (${kb} kB)`)}catch(err){console.warn(`[dev] preview script concat skipped: ${err.message}`)}}function watchAndCompile(){let timer=null;let compiling=false;let pending=null;const queue=rel=>{pending=rel;if(timer)clearTimeout(timer);timer=setTimeout(()=>{timer=null;run()},debounceMs)};const run=async()=>{if(compiling)return;const rel=pending;pending=null;compiling=true;if(rel)console.log(`[dev] change ${rel}`);try{if(!rel||rel.startsWith("src/theme")||/resources\/textures\//.test(rel)){syncThemeOnce()}await compile({fatal:false})}finally{compiling=false;if(pending)queue(pending)}};for(const dir of watchDirs){const abs=path.join(projectRoot,dir);fs.watch(abs,{recursive:true},(_event,file)=>{if(shouldIgnoreWatch(file))return;const rel=path.join(dir,file||"").replace(/\\/g,"/");queue(rel)})}const themeName=detectCurrentTheme(projectRoot,{sourceDir:"src/theme",entryFile:"src/theme/index.ts"});const themeAssetsDir=themeName?path.join(projectRoot,"src/theme",themeName,"assets"):"";if(themeAssetsDir&&fs.existsSync(themeAssetsDir)){fs.watch(themeAssetsDir,()=>{queue(path.join("src/theme",themeName,"assets"))});let stamp=themeAssetStamp(themeAssetsDir);setInterval(()=>{const next=themeAssetStamp(themeAssetsDir);if(next!==stamp){stamp=next;queue(path.join("src/theme",themeName,"assets"))}},1000)}}function holdUntilExit(child,proxy){const stop=()=>{if(child&&child.exitCode==null){child.kill("SIGTERM")}if(proxy&&proxy.close){Promise.resolve(proxy.close()).finally(()=>process.exit(0));return}process.exit(0)};process.on("SIGINT",stop);process.on("SIGTERM",stop);if(child){child.on("exit",(code,signal)=>{console.log(`[dev] cocos CLI exited (${signal||code})`);if(proxy&&proxy.close){Promise.resolve(proxy.close()).finally(()=>process.exit(code==null?1:code));return}process.exit(code==null?1:code)});return}console.log("[dev] CLI already running; Ctrl+C leaves it open");setInterval(()=>{},60*1000)}async function warmPreviewAfterReady(previewPort){// Cold sandbox: library/ is empty until assets-refresh; skipping compile leaves JSON unpack hooked but empty → 100+ UUID requests.
|
|
5
|
+
syncThemeOnce();await compile({fatal:false,previewPort})}async function start(){clearPreviewMergeMarker(projectRoot);if(await isPreviewUp()){console.warn("[dev] reusing CLI without cache proxy; restart npm run dev to enable long-cache");printBanner(true);await warmPreviewAfterReady(port);watchAndCompile();holdUntilExit(null);return}if(needsXvfb()){console.log("[dev] linux, wrapping xvfb-run -a")}const cliPort=await findFreePort(port);const args=["--no-interactive","start-mcp-server","--project",projectRoot,"--port",String(cliPort)];if(scene){console.log(`[dev] start scene ${scene}`)}console.log(`[dev] cocos ${args.join(" ")}`);const child=spawnCocos(args,{cwd:projectRoot,env:process.env,stdio:"inherit"});child.on("error",err=>{console.error(err);process.exit(1)});let proxy;try{await waitForPreviewOn(cliPort);console.log(`[dev] cocos CLI listening on ${cliPort} (public ${port} still closed)`);await warmPreviewAfterReady(cliPort);proxy=await startPreviewProxy({listenPort:port,targetPort:cliPort});console.log(`[dev] cache proxy ${port} → CLI ${cliPort} (preview merge ready)`)}catch(err){console.error(`[dev] ${err.message}`);child.kill("SIGTERM");if(proxy&&proxy.close)await proxy.close();process.exit(1)}printBanner(false);watchAndCompile();holdUntilExit(child,proxy)}killSocialShareForDev(projectRoot);if(cmd==="compile"||cmd==="refresh"){await compile();return}if(cmd==="start"||cmd==="dev"){await start();return}console.error(`[dev] unknown command: ${cmd}`);console.error("[dev] usage: playable-scripts dev [start|compile]");process.exit(1)}module.exports={runCocosDev,previewMergeMarkerPath,clearPreviewMergeMarker,markPreviewMergeReady,PREVIEW_MERGE_MARKER};
|
package/core/engines/cocos/fs.js
CHANGED
|
@@ -1,105 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const { lookup } = require('mime-types');
|
|
6
|
-
const { ADAPTER_FETCH, TO_STRING_EXTNAME, TO_SKIP_EXTNAME } = require('./constants');
|
|
7
|
-
|
|
8
|
-
function getRealPath(pathStr) {
|
|
9
|
-
return pathStr.indexOf('\\') !== -1 ? pathStr.replace(/\\/g, '/') : pathStr;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function getAllFilesFromDir(dirPath) {
|
|
13
|
-
let files = [];
|
|
14
|
-
if (!fs.existsSync(dirPath)) return files;
|
|
15
|
-
for (const fileName of fs.readdirSync(dirPath)) {
|
|
16
|
-
const filePath = path.join(dirPath, fileName);
|
|
17
|
-
const stat = fs.statSync(filePath);
|
|
18
|
-
if (stat.isDirectory()) files = files.concat(getAllFilesFromDir(filePath));
|
|
19
|
-
else files.push(filePath);
|
|
20
|
-
}
|
|
21
|
-
return files;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function sniffImageMime(buf) {
|
|
25
|
-
if (!buf || buf.length < 12) {
|
|
26
|
-
if (buf && buf.length >= 8 && buf[0] === 0x89 && buf[1] === 0x50 && buf[2] === 0x4e && buf[3] === 0x47) {
|
|
27
|
-
return 'image/png';
|
|
28
|
-
}
|
|
29
|
-
return '';
|
|
30
|
-
}
|
|
31
|
-
if (buf[0] === 0x89 && buf[1] === 0x50 && buf[2] === 0x4e && buf[3] === 0x47) return 'image/png';
|
|
32
|
-
if (buf[0] === 0xff && buf[1] === 0xd8 && buf[2] === 0xff) return 'image/jpeg';
|
|
33
|
-
if (
|
|
34
|
-
buf[0] === 0x52 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x46
|
|
35
|
-
&& buf[8] === 0x57 && buf[9] === 0x45 && buf[10] === 0x42 && buf[11] === 0x50
|
|
36
|
-
) {
|
|
37
|
-
return 'image/webp';
|
|
38
|
-
}
|
|
39
|
-
return '';
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function sniffAudioMime(buf) {
|
|
43
|
-
if (!buf || buf.length < 4) return '';
|
|
44
|
-
if (buf[0] === 0x49 && buf[1] === 0x44 && buf[2] === 0x33) return 'audio/mpeg';
|
|
45
|
-
if (buf[0] === 0xff && (buf[1] & 0xe0) === 0xe0) return 'audio/mpeg';
|
|
46
|
-
if (buf[0] === 0x4f && buf[1] === 0x67 && buf[2] === 0x67 && buf[3] === 0x53) return 'audio/ogg';
|
|
47
|
-
if (buf[0] === 0x52 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x46) {
|
|
48
|
-
if (buf.length >= 12 && buf[8] === 0x57 && buf[9] === 0x45 && buf[10] === 0x42 && buf[11] === 0x50) {
|
|
49
|
-
return '';
|
|
50
|
-
}
|
|
51
|
-
return 'audio/wav';
|
|
52
|
-
}
|
|
53
|
-
if (buf.length >= 8 && buf[4] === 0x66 && buf[5] === 0x74 && buf[6] === 0x79 && buf[7] === 0x70) return 'audio/mp4';
|
|
54
|
-
return '';
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function getBase64FromFile(filePath) {
|
|
58
|
-
const buf = fs.readFileSync(filePath);
|
|
59
|
-
const lookedUp = lookup(filePath) || '';
|
|
60
|
-
const imageMime = lookedUp.startsWith('image/') ? lookedUp : sniffImageMime(buf);
|
|
61
|
-
const mime = imageMime
|
|
62
|
-
|| (lookedUp.startsWith('audio/') ? lookedUp : sniffAudioMime(buf) || lookedUp)
|
|
63
|
-
|| 'application/octet-stream';
|
|
64
|
-
return `data:${mime};base64,${buf.toString('base64')}`;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function getTargetResData(filePath) {
|
|
68
|
-
const fileExtname = path.extname(filePath);
|
|
69
|
-
if (!fileExtname) return '';
|
|
70
|
-
if (TO_STRING_EXTNAME.includes(fileExtname)) {
|
|
71
|
-
return fs.readFileSync(filePath, 'utf-8');
|
|
72
|
-
}
|
|
73
|
-
return getBase64FromFile(filePath);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function removeXMLHttpRequest(codeStr) {
|
|
77
|
-
return codeStr.replace(/XMLHttpRequest/g, ADAPTER_FETCH);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
async function getResourceMapper({ dirPath, rmHttp = false, mountCbFn, skipFiles = [] }) {
|
|
81
|
-
const resMapper = {};
|
|
82
|
-
const readPkgPath = getRealPath(`${dirPath}/`);
|
|
83
|
-
for (const filePath of getAllFilesFromDir(dirPath)) {
|
|
84
|
-
const fileExtname = path.extname(filePath);
|
|
85
|
-
if (TO_SKIP_EXTNAME.includes(fileExtname)) continue;
|
|
86
|
-
if (skipFiles.includes(filePath)) continue;
|
|
87
|
-
|
|
88
|
-
const objKey = getRealPath(filePath).replace(readPkgPath, '');
|
|
89
|
-
let data = getTargetResData(filePath);
|
|
90
|
-
if (mountCbFn) data = mountCbFn(objKey, data);
|
|
91
|
-
if (rmHttp && fileExtname === '.js') data = removeXMLHttpRequest(data);
|
|
92
|
-
resMapper[objKey] = data;
|
|
93
|
-
}
|
|
94
|
-
return { resMapper };
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
module.exports = {
|
|
98
|
-
getRealPath,
|
|
99
|
-
getAllFilesFromDir,
|
|
100
|
-
getBase64FromFile,
|
|
101
|
-
getTargetResData,
|
|
102
|
-
getResourceMapper,
|
|
103
|
-
removeXMLHttpRequest,
|
|
104
|
-
sniffAudioMime,
|
|
105
|
-
};
|
|
1
|
+
"use strict";const fs=require("fs");const path=require("path");const{lookup}=require("mime-types");const{ADAPTER_FETCH,TO_STRING_EXTNAME,TO_SKIP_EXTNAME}=require("./constants");function getRealPath(pathStr){return pathStr.indexOf("\\")!==-1?pathStr.replace(/\\/g,"/"):pathStr}function getAllFilesFromDir(dirPath){let files=[];if(!fs.existsSync(dirPath))return files;for(const fileName of fs.readdirSync(dirPath)){const filePath=path.join(dirPath,fileName);const stat=fs.statSync(filePath);if(stat.isDirectory())files=files.concat(getAllFilesFromDir(filePath));else files.push(filePath)}return files}function sniffImageMime(buf){if(!buf||buf.length<12){if(buf&&buf.length>=8&&buf[0]===137&&buf[1]===80&&buf[2]===78&&buf[3]===71){return"image/png"}return""}if(buf[0]===137&&buf[1]===80&&buf[2]===78&&buf[3]===71)return"image/png";if(buf[0]===255&&buf[1]===216&&buf[2]===255)return"image/jpeg";if(buf[0]===82&&buf[1]===73&&buf[2]===70&&buf[3]===70&&buf[8]===87&&buf[9]===69&&buf[10]===66&&buf[11]===80){return"image/webp"}return""}function sniffAudioMime(buf){if(!buf||buf.length<4)return"";if(buf[0]===73&&buf[1]===68&&buf[2]===51)return"audio/mpeg";if(buf[0]===255&&(buf[1]&224)===224)return"audio/mpeg";if(buf[0]===79&&buf[1]===103&&buf[2]===103&&buf[3]===83)return"audio/ogg";if(buf[0]===82&&buf[1]===73&&buf[2]===70&&buf[3]===70){if(buf.length>=12&&buf[8]===87&&buf[9]===69&&buf[10]===66&&buf[11]===80){return""}return"audio/wav"}if(buf.length>=8&&buf[4]===102&&buf[5]===116&&buf[6]===121&&buf[7]===112)return"audio/mp4";return""}function getBase64FromFile(filePath){const buf=fs.readFileSync(filePath);const lookedUp=lookup(filePath)||"";const imageMime=lookedUp.startsWith("image/")?lookedUp:sniffImageMime(buf);const mime=imageMime||(lookedUp.startsWith("audio/")?lookedUp:sniffAudioMime(buf)||lookedUp)||"application/octet-stream";return`data:${mime};base64,${buf.toString("base64")}`}function getTargetResData(filePath){const fileExtname=path.extname(filePath);if(!fileExtname)return"";if(TO_STRING_EXTNAME.includes(fileExtname)){return fs.readFileSync(filePath,"utf-8")}return getBase64FromFile(filePath)}function removeXMLHttpRequest(codeStr){return codeStr.replace(/XMLHttpRequest/g,ADAPTER_FETCH)}async function getResourceMapper({dirPath,rmHttp=false,mountCbFn,skipFiles=[]}){const resMapper={};const readPkgPath=getRealPath(`${dirPath}/`);for(const filePath of getAllFilesFromDir(dirPath)){const fileExtname=path.extname(filePath);if(TO_SKIP_EXTNAME.includes(fileExtname))continue;if(skipFiles.includes(filePath))continue;const objKey=getRealPath(filePath).replace(readPkgPath,"");let data=getTargetResData(filePath);if(mountCbFn)data=await mountCbFn(objKey,data);if(rmHttp&&fileExtname===".js")data=removeXMLHttpRequest(data);resMapper[objKey]=data}return{resMapper}}module.exports={getRealPath,getAllFilesFromDir,getBase64FromFile,getTargetResData,getResourceMapper,removeXMLHttpRequest,sniffAudioMime};
|