@playcraft/devkit 1.0.31-beta.10 → 1.0.31-beta.11
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 +262 -0
- package/cli/bin/playable-scripts.js +53 -6
- package/cli/commands/build.js +241 -32
- package/cli/commands/builds.js +13 -2
- package/cli/commands/dev.js +22 -1
- package/cli/commands/pack.js +320 -40
- package/cli/commands/vite-dev.js +7 -1
- package/core/artifacts/emit.js +98 -1
- package/core/artifacts/fflate.js +31 -1
- package/core/artifacts/zip.js +39 -1
- package/core/batch-build.js +1261 -147
- package/core/constants.js +20 -2
- package/core/cos-uploader.js +289 -23
- package/core/engines/cocos/clean-cache.js +179 -5
- package/core/engines/cocos/clean-cache.test.js +75 -1
- package/core/engines/cocos/cli-build.js +116 -2
- package/core/engines/cocos/cli.js +38 -1
- package/core/engines/cocos/constants.js +21 -1
- package/core/engines/cocos/creator-cli.js +108 -1
- package/core/engines/cocos/dev-server.js +412 -4
- package/core/engines/cocos/fs.js +105 -1
- package/core/engines/cocos/injects/3x/init.js +438 -19
- package/core/engines/cocos/injects/3x/main.js +52 -2
- package/core/engines/cocos/injects/libs/pako.js +2 -1
- package/core/engines/cocos/mcp-refresh.js +76 -2
- package/core/engines/cocos/merge.js +147 -2
- package/core/engines/cocos/pack.js +187 -1
- package/core/engines/cocos/preview-cache.js +48 -2
- package/core/engines/cocos/preview-cache.test.js +32 -1
- package/core/engines/cocos/preview-concat.js +189 -5
- package/core/engines/cocos/preview-concat.test.js +73 -1
- package/core/engines/cocos/preview-json-hook.js +200 -1
- package/core/engines/cocos/preview-json-pack.js +376 -2
- package/core/engines/cocos/preview-json-pack.test.js +226 -2
- package/core/engines/cocos/preview-proxy.js +132 -1
- package/core/engines/cocos/rebundle-preview.js +54 -2
- package/core/engines/cocos/strip-social-share.js +115 -3
- package/core/engines/cocos/theme-assets.js +161 -2
- package/core/engines/cocos/writable-cli.js +248 -2
- package/core/engines/cocos/writable-cli.test.js +112 -1
- package/core/engines/web/index.js +20 -1
- package/core/engines/web/vite.dev.js +322 -17
- package/core/engines/web/webpack.build.js +522 -65
- package/core/engines/web/webpack.common.js +177 -11
- package/core/engines/web/webpack.dev.js +88 -6
- package/core/index.js +101 -7
- package/core/injectors/apply.js +94 -1
- package/core/injectors/check-channel-matrix.js +130 -2
- package/core/injectors/spec.js +217 -9
- package/core/loaders/gltf-loader.js +74 -28
- package/core/options.js +353 -16
- package/core/plugins/AdikteevInjectorPlugin.js +26 -4
- package/core/plugins/BigoAdsInjectorPlugin.js +21 -4
- package/core/plugins/DAPIInjectorPlugin.js +25 -2
- package/core/plugins/DebuggerInjectionPlugin.js +31 -3
- package/core/plugins/ExitAPIInjectorPlugin.js +56 -3
- package/core/plugins/FflateCompressionPlugin.js +231 -40
- package/core/plugins/FontInjectionWebpackPlugin.js +46 -4
- package/core/plugins/LiftoffInjectorPlugin.js +26 -4
- package/core/plugins/MRAIDInjectorPlugin.js +24 -2
- package/core/plugins/MintegralInjectorPlugin.js +25 -2
- package/core/plugins/PangleInjectorPlugin.js +24 -2
- package/core/plugins/PlaycraftOrientationInjectorPlugin.js +29 -3
- package/core/plugins/SnapchatInjectorPlugin.js +26 -4
- package/core/plugins/SocialMediaInjectorPlugin.js +119 -7
- package/core/plugins/TikTokInjectorPlugin.js +24 -2
- package/core/plugins/UnityInjectorPlugin.js +37 -8
- package/core/plugins/ZipPlugin.js +154 -20
- package/core/plugins/socialMediaVitePlugin.js +108 -2
- package/core/utils/buildDefines.js +30 -2
- package/core/utils/buildTemplateString.js +39 -5
- package/core/utils/date.js +16 -1
- package/core/utils/fontRegistry.js +81 -13
- package/core/utils/fontResolver.js +335 -37
- package/core/utils/generateAdikteevHtmlWebpackPluginConfig.js +42 -7
- package/core/utils/generateBigabidHtmlWebpackPluginConfig.js +30 -3
- package/core/utils/generateInMobiHtmlWebpackPluginConfig.js +43 -7
- package/core/utils/getPlaycraftOrientationSuffix.js +9 -2
- package/core/utils/injectSDKPlugins.js +68 -13
- package/core/utils/logOptions.js +46 -5
- package/core/utils/mergeOptions.js +21 -2
- package/core/utils/parseArgvOptions.js +125 -5
- package/core/utils/resolveChannelFold2Zip.js +15 -3
- package/core/utils/validateThemeData.js +227 -26
- package/core/validators/pre-build-checker.js +287 -25
- package/core/validators/tracking-validator.js +441 -40
- package/core/validators/tracking-validator.test.js +84 -2
- 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 +3 -2
|
@@ -1,2 +1,226 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { describe, it, before, after } = require('node:test');
|
|
4
|
+
const assert = require('node:assert/strict');
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const os = require('os');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const {
|
|
9
|
+
packPreviewJson,
|
|
10
|
+
uuidFromUrl,
|
|
11
|
+
configNameFromUrl,
|
|
12
|
+
HOOK_START,
|
|
13
|
+
} = require('./preview-json-pack.js');
|
|
14
|
+
|
|
15
|
+
describe('packPreviewJson', () => {
|
|
16
|
+
let root;
|
|
17
|
+
const scene = '0a1b2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d';
|
|
18
|
+
const builtin = '970b0598-bcb0-4714-91fb-2e81440dccd8';
|
|
19
|
+
const extra = '11111111-2222-4333-8444-555555555555';
|
|
20
|
+
|
|
21
|
+
before(() => {
|
|
22
|
+
root = fs.mkdtempSync(path.join(os.tmpdir(), 'preview-json-'));
|
|
23
|
+
const writeJson = (dir, uuid, json) => {
|
|
24
|
+
const abs = path.join(dir, uuid.slice(0, 2), `${uuid}.json`);
|
|
25
|
+
fs.mkdirSync(path.dirname(abs), { recursive: true });
|
|
26
|
+
fs.writeFileSync(abs, `${JSON.stringify(json)}\n`);
|
|
27
|
+
};
|
|
28
|
+
writeJson(path.join(root, 'library'), scene, {
|
|
29
|
+
name: 'scene',
|
|
30
|
+
ref: { __uuid__: extra },
|
|
31
|
+
});
|
|
32
|
+
writeJson(path.join(root, 'library'), extra, { name: 'extra' });
|
|
33
|
+
writeJson(path.join(root, 'engine-lib'), builtin, { name: 'effect' });
|
|
34
|
+
fs.mkdirSync(path.join(root, 'temp/programming/preview/systemjs'), { recursive: true });
|
|
35
|
+
fs.writeFileSync(
|
|
36
|
+
path.join(root, 'temp/programming/preview/systemjs/system.js'),
|
|
37
|
+
"(function () { 'use strict'; window.System = {}; })();\n",
|
|
38
|
+
);
|
|
39
|
+
fs.mkdirSync(path.join(root, 'settings'), { recursive: true });
|
|
40
|
+
fs.writeFileSync(
|
|
41
|
+
path.join(root, 'settings/cocos.config.json'),
|
|
42
|
+
JSON.stringify({ builder: { common: { startScene: scene } } }),
|
|
43
|
+
);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
after(() => {
|
|
47
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('parses preview json urls', () => {
|
|
51
|
+
assert.equal(
|
|
52
|
+
uuidFromUrl('/assets/internal/import/97/970b0598-bcb0-4714-91fb-2e81440dccd8.json?t=1'),
|
|
53
|
+
builtin,
|
|
54
|
+
);
|
|
55
|
+
assert.equal(
|
|
56
|
+
uuidFromUrl(`/scene/${scene}.json`),
|
|
57
|
+
scene,
|
|
58
|
+
);
|
|
59
|
+
assert.equal(
|
|
60
|
+
uuidFromUrl(`https://host/api/sandbox-preview/assets/sid/slot/import/97/${builtin}`),
|
|
61
|
+
builtin,
|
|
62
|
+
);
|
|
63
|
+
assert.equal(configNameFromUrl('/assets/internal/config.json'), 'internal');
|
|
64
|
+
assert.equal(
|
|
65
|
+
uuidFromUrl(
|
|
66
|
+
'https://host/api/sandbox-preview/assets/sid/slot/assets/internal/import/a3/a3cd009f-0ab0-420d-9278-b9fdab939bbc.json',
|
|
67
|
+
),
|
|
68
|
+
'a3cd009f-0ab0-420d-9278-b9fdab939bbc',
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('packs uuid closure + configs and injects the xhr hook', async () => {
|
|
73
|
+
const result = await packPreviewJson(root, {
|
|
74
|
+
engineLibraryDirs: [path.join(root, 'engine-lib')],
|
|
75
|
+
settings: {
|
|
76
|
+
engine: { builtinAssets: [builtin] },
|
|
77
|
+
launch: { launchScene: scene },
|
|
78
|
+
assets: { projectBundles: ['internal'] },
|
|
79
|
+
},
|
|
80
|
+
bundleConfigs: {
|
|
81
|
+
internal: {
|
|
82
|
+
name: 'internal',
|
|
83
|
+
uuids: [builtin],
|
|
84
|
+
paths: { [builtin]: ['db://internal/effect', 'cc.EffectAsset'] },
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
assert.equal(result.files, 3);
|
|
89
|
+
assert.equal(result.configs, 1);
|
|
90
|
+
assert.equal(result.hooked, true);
|
|
91
|
+
|
|
92
|
+
const pack = JSON.parse(
|
|
93
|
+
fs.readFileSync(path.join(root, 'temp/programming/preview/systemjs/playcraft-json-pack.json'), 'utf8'),
|
|
94
|
+
);
|
|
95
|
+
assert.equal(pack.assets[scene].name, 'scene');
|
|
96
|
+
assert.equal(pack.assets[extra].name, 'extra');
|
|
97
|
+
assert.equal(pack.assets[builtin].name, 'effect');
|
|
98
|
+
assert.equal(pack.configs.internal.name, 'internal');
|
|
99
|
+
|
|
100
|
+
const systemJs = fs.readFileSync(path.join(root, 'temp/programming/preview/systemjs/system.js'), 'utf8');
|
|
101
|
+
assert.equal(systemJs.includes(HOOK_START), true);
|
|
102
|
+
assert.equal(systemJs.includes('XMLHttpRequest.prototype.send'), true);
|
|
103
|
+
assert.match(systemJs, /window\.System = \{\}/);
|
|
104
|
+
|
|
105
|
+
const again = await packPreviewJson(root, {
|
|
106
|
+
engineLibraryDirs: [path.join(root, 'engine-lib')],
|
|
107
|
+
settings: {
|
|
108
|
+
engine: { builtinAssets: [builtin] },
|
|
109
|
+
launch: { launchScene: scene },
|
|
110
|
+
},
|
|
111
|
+
bundleConfigs: { internal: { name: 'internal', uuids: [builtin], paths: {} } },
|
|
112
|
+
});
|
|
113
|
+
assert.equal(again.hooked, true);
|
|
114
|
+
const injected = fs.readFileSync(path.join(root, 'temp/programming/preview/systemjs/system.js'), 'utf8');
|
|
115
|
+
assert.equal(injected.split(HOOK_START).length - 1, 1);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('serves packed uuid json from the xhr hook without network', async () => {
|
|
119
|
+
await packPreviewJson(root, {
|
|
120
|
+
engineLibraryDirs: [path.join(root, 'engine-lib')],
|
|
121
|
+
settings: {
|
|
122
|
+
engine: { builtinAssets: [builtin] },
|
|
123
|
+
launch: { launchScene: scene },
|
|
124
|
+
},
|
|
125
|
+
bundleConfigs: {
|
|
126
|
+
internal: { name: 'internal', uuids: [builtin], paths: {} },
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
const hook = fs.readFileSync(
|
|
130
|
+
path.join(root, 'temp/programming/preview/systemjs/system.js'),
|
|
131
|
+
'utf8',
|
|
132
|
+
).split("(function () { 'use strict'; window.System")[0];
|
|
133
|
+
const pack = JSON.parse(
|
|
134
|
+
fs.readFileSync(path.join(root, 'temp/programming/preview/systemjs/playcraft-json-pack.json'), 'utf8'),
|
|
135
|
+
);
|
|
136
|
+
const instances = [];
|
|
137
|
+
function FakeXHR() {
|
|
138
|
+
instances.push(this);
|
|
139
|
+
this.readyState = 1;
|
|
140
|
+
this.status = 0;
|
|
141
|
+
this.response = null;
|
|
142
|
+
this.responseType = 'json';
|
|
143
|
+
this.onload = null;
|
|
144
|
+
this.onreadystatechange = null;
|
|
145
|
+
this.__network = false;
|
|
146
|
+
}
|
|
147
|
+
FakeXHR.prototype.open = function (method, url) {
|
|
148
|
+
this.__pcUrl = url;
|
|
149
|
+
};
|
|
150
|
+
FakeXHR.prototype.setRequestHeader = function () {};
|
|
151
|
+
FakeXHR.prototype.send = function () {
|
|
152
|
+
this.__network = true;
|
|
153
|
+
};
|
|
154
|
+
global.performance = { getEntriesByType: () => [] };
|
|
155
|
+
global.document = { currentScript: null, getElementsByTagName: () => [] };
|
|
156
|
+
global.XMLHttpRequest = FakeXHR;
|
|
157
|
+
const originalFetch = globalThis.fetch;
|
|
158
|
+
// eslint-disable-next-line no-eval
|
|
159
|
+
eval(hook.replace(HOOK_START, '').replace('/* playcraft-json-pack:end */', ''));
|
|
160
|
+
|
|
161
|
+
const packXhr = instances[0];
|
|
162
|
+
if (packXhr && String(packXhr.__pcUrl || '').includes('playcraft-json-pack.json')) {
|
|
163
|
+
packXhr.responseText = JSON.stringify(pack);
|
|
164
|
+
packXhr.onload();
|
|
165
|
+
} else {
|
|
166
|
+
assert.equal(hook.includes('var pack = {'), true);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const asset = new FakeXHR();
|
|
170
|
+
let loaded = null;
|
|
171
|
+
asset.onload = function () { loaded = asset.response; };
|
|
172
|
+
XMLHttpRequest.prototype.open.call(asset, 'GET', `/scene/${scene}.json`);
|
|
173
|
+
XMLHttpRequest.prototype.send.call(asset, null);
|
|
174
|
+
assert.equal(asset.__network, false);
|
|
175
|
+
assert.equal(asset.status, 200);
|
|
176
|
+
assert.equal(loaded.name, 'scene');
|
|
177
|
+
|
|
178
|
+
const config = new FakeXHR();
|
|
179
|
+
let configLoaded = null;
|
|
180
|
+
config.onload = function () { configLoaded = config.response; };
|
|
181
|
+
XMLHttpRequest.prototype.open.call(config, 'GET', '/assets/internal/config.json');
|
|
182
|
+
XMLHttpRequest.prototype.send.call(config, null);
|
|
183
|
+
assert.equal(config.__network, false);
|
|
184
|
+
assert.equal(configLoaded.name, 'internal');
|
|
185
|
+
|
|
186
|
+
const ext = new FakeXHR();
|
|
187
|
+
ext.responseType = '';
|
|
188
|
+
let extLoaded = null;
|
|
189
|
+
ext.onload = function () { extLoaded = ext.response; };
|
|
190
|
+
XMLHttpRequest.prototype.open.call(ext, 'GET', `/query-extname/${scene}`);
|
|
191
|
+
XMLHttpRequest.prototype.send.call(ext, null);
|
|
192
|
+
assert.equal(ext.__network, false);
|
|
193
|
+
assert.equal(extLoaded, '.json');
|
|
194
|
+
|
|
195
|
+
const sandboxJson = new FakeXHR();
|
|
196
|
+
let sandboxLoaded = null;
|
|
197
|
+
sandboxJson.onload = function () { sandboxLoaded = sandboxJson.response; };
|
|
198
|
+
XMLHttpRequest.prototype.open.call(
|
|
199
|
+
sandboxJson,
|
|
200
|
+
'GET',
|
|
201
|
+
`https://host/api/sandbox-preview/assets/sid/slot/assets/internal/import/97/${builtin}.json`,
|
|
202
|
+
);
|
|
203
|
+
XMLHttpRequest.prototype.send.call(sandboxJson, null);
|
|
204
|
+
assert.equal(sandboxJson.__network, false);
|
|
205
|
+
assert.equal(sandboxLoaded.name, 'effect');
|
|
206
|
+
|
|
207
|
+
const sandboxExt = new FakeXHR();
|
|
208
|
+
sandboxExt.responseType = '';
|
|
209
|
+
let sandboxExtLoaded = null;
|
|
210
|
+
sandboxExt.onload = function () { sandboxExtLoaded = sandboxExt.response; };
|
|
211
|
+
XMLHttpRequest.prototype.open.call(
|
|
212
|
+
sandboxExt,
|
|
213
|
+
'GET',
|
|
214
|
+
`https://host/api/sandbox-preview/assets/sid/slot/query-extname/${scene}`,
|
|
215
|
+
);
|
|
216
|
+
XMLHttpRequest.prototype.send.call(sandboxExt, null);
|
|
217
|
+
assert.equal(sandboxExt.__network, false);
|
|
218
|
+
assert.equal(sandboxExtLoaded, '.json');
|
|
219
|
+
|
|
220
|
+
delete global.XMLHttpRequest;
|
|
221
|
+
delete global.performance;
|
|
222
|
+
delete global.document;
|
|
223
|
+
if (originalFetch) globalThis.fetch = originalFetch;
|
|
224
|
+
else delete globalThis.fetch;
|
|
225
|
+
});
|
|
226
|
+
});
|
|
@@ -1 +1,132 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const http = require('http');
|
|
4
|
+
const net = require('net');
|
|
5
|
+
const { cacheControlFor } = require('./preview-cache.js');
|
|
6
|
+
|
|
7
|
+
const HOP = new Set([
|
|
8
|
+
'connection',
|
|
9
|
+
'keep-alive',
|
|
10
|
+
'proxy-authenticate',
|
|
11
|
+
'proxy-authorization',
|
|
12
|
+
'te',
|
|
13
|
+
'trailer',
|
|
14
|
+
'transfer-encoding',
|
|
15
|
+
'upgrade',
|
|
16
|
+
]);
|
|
17
|
+
|
|
18
|
+
function findFreePort(exclude = 0) {
|
|
19
|
+
return new Promise((resolve, reject) => {
|
|
20
|
+
const tryListen = () => {
|
|
21
|
+
const server = net.createServer();
|
|
22
|
+
server.unref();
|
|
23
|
+
server.once('error', () => tryListen());
|
|
24
|
+
server.listen(0, '127.0.0.1', () => {
|
|
25
|
+
const addr = server.address();
|
|
26
|
+
const port = addr && addr.port;
|
|
27
|
+
server.close((err) => {
|
|
28
|
+
if (err) {
|
|
29
|
+
reject(err);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (!port || port === exclude) tryListen();
|
|
33
|
+
else resolve(port);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
tryListen();
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function copyHeaders(src) {
|
|
42
|
+
const out = {};
|
|
43
|
+
for (const [key, value] of Object.entries(src || {})) {
|
|
44
|
+
if (HOP.has(key.toLowerCase())) continue;
|
|
45
|
+
if (value == null) continue;
|
|
46
|
+
out[key] = value;
|
|
47
|
+
}
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function applyCacheControl(url, headers) {
|
|
52
|
+
const next = cacheControlFor(url);
|
|
53
|
+
if (!next) return headers;
|
|
54
|
+
const out = { ...headers };
|
|
55
|
+
out['cache-control'] = next;
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function startPreviewProxy({ listenPort, targetPort }) {
|
|
60
|
+
const server = http.createServer((req, res) => {
|
|
61
|
+
const headers = copyHeaders(req.headers);
|
|
62
|
+
headers.host = `127.0.0.1:${targetPort}`;
|
|
63
|
+
const proxyReq = http.request(
|
|
64
|
+
{
|
|
65
|
+
hostname: '127.0.0.1',
|
|
66
|
+
port: targetPort,
|
|
67
|
+
path: req.url,
|
|
68
|
+
method: req.method,
|
|
69
|
+
headers,
|
|
70
|
+
},
|
|
71
|
+
(proxyRes) => {
|
|
72
|
+
const outHeaders = applyCacheControl(req.url, copyHeaders(proxyRes.headers));
|
|
73
|
+
res.writeHead(proxyRes.statusCode || 502, outHeaders);
|
|
74
|
+
proxyRes.pipe(res);
|
|
75
|
+
},
|
|
76
|
+
);
|
|
77
|
+
proxyReq.on('error', () => {
|
|
78
|
+
if (!res.headersSent) {
|
|
79
|
+
res.writeHead(502);
|
|
80
|
+
}
|
|
81
|
+
res.end('preview upstream down');
|
|
82
|
+
});
|
|
83
|
+
req.pipe(proxyReq);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
server.on('upgrade', (req, clientSocket, head) => {
|
|
87
|
+
const headers = copyHeaders(req.headers);
|
|
88
|
+
headers.host = `127.0.0.1:${targetPort}`;
|
|
89
|
+
headers.connection = 'upgrade';
|
|
90
|
+
headers.upgrade = req.headers.upgrade || 'websocket';
|
|
91
|
+
const proxyReq = http.request({
|
|
92
|
+
hostname: '127.0.0.1',
|
|
93
|
+
port: targetPort,
|
|
94
|
+
path: req.url,
|
|
95
|
+
method: req.method,
|
|
96
|
+
headers,
|
|
97
|
+
});
|
|
98
|
+
proxyReq.on('upgrade', (proxyRes, proxySocket, proxyHead) => {
|
|
99
|
+
const lines = ['HTTP/1.1 101 Switching Protocols'];
|
|
100
|
+
for (const [key, value] of Object.entries(proxyRes.headers)) {
|
|
101
|
+
if (value == null) continue;
|
|
102
|
+
const text = Array.isArray(value) ? value.join(', ') : String(value);
|
|
103
|
+
lines.push(`${key}: ${text}`);
|
|
104
|
+
}
|
|
105
|
+
clientSocket.write(`${lines.join('\r\n')}\r\n\r\n`);
|
|
106
|
+
if (head && head.length) proxySocket.write(head);
|
|
107
|
+
if (proxyHead && proxyHead.length) clientSocket.write(proxyHead);
|
|
108
|
+
proxySocket.pipe(clientSocket);
|
|
109
|
+
clientSocket.pipe(proxySocket);
|
|
110
|
+
});
|
|
111
|
+
proxyReq.on('error', () => clientSocket.destroy());
|
|
112
|
+
proxyReq.end();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
return new Promise((resolve, reject) => {
|
|
116
|
+
server.once('error', reject);
|
|
117
|
+
server.listen(listenPort, '127.0.0.1', () => {
|
|
118
|
+
resolve({
|
|
119
|
+
close: () =>
|
|
120
|
+
new Promise((done, fail) => {
|
|
121
|
+
server.close((err) => (err ? fail(err) : done()));
|
|
122
|
+
}),
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
module.exports = {
|
|
129
|
+
findFreePort,
|
|
130
|
+
startPreviewProxy,
|
|
131
|
+
applyCacheControl,
|
|
132
|
+
};
|
|
@@ -1,4 +1,56 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { concatPreviewScripts } = require('./preview-concat.js');
|
|
6
|
+
const { packPreviewJson } = require('./preview-json-pack.js');
|
|
7
|
+
|
|
8
|
+
function previewTargetDir(projectRoot) {
|
|
9
|
+
return path.join(projectRoot, 'temp/programming/packer-driver/targets/preview');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
2
13
|
* Re-apply script concat + JSON pack after a build cleared editor caches.
|
|
3
14
|
* Safe no-op if preview was never compiled.
|
|
4
|
-
*/
|
|
15
|
+
*/
|
|
16
|
+
async function rebundlePreviewMerge(projectRoot, options = {}) {
|
|
17
|
+
const previewDir = previewTargetDir(projectRoot);
|
|
18
|
+
if (!fs.existsSync(path.join(previewDir, 'import-map.json'))) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let scriptResult = null;
|
|
23
|
+
try {
|
|
24
|
+
scriptResult = concatPreviewScripts(projectRoot);
|
|
25
|
+
if (scriptResult) {
|
|
26
|
+
const kb = Math.max(1, Math.round(scriptResult.bytes / 1024));
|
|
27
|
+
console.log(`[cocos] preview scripts ${scriptResult.modules} → 1 bundle (${kb} kB)`);
|
|
28
|
+
}
|
|
29
|
+
} catch (err) {
|
|
30
|
+
console.warn(`[cocos] preview script concat skipped: ${err.message}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let jsonResult = null;
|
|
34
|
+
try {
|
|
35
|
+
const port = options.previewPort || process.env.PREVIEW_PORT;
|
|
36
|
+
const previewOrigin = port ? `http://127.0.0.1:${port}` : options.previewOrigin;
|
|
37
|
+
jsonResult = await packPreviewJson(projectRoot, {
|
|
38
|
+
previewOrigin,
|
|
39
|
+
fetchText: options.fetchText,
|
|
40
|
+
engineLibraryDirs: options.engineLibraryDirs,
|
|
41
|
+
});
|
|
42
|
+
if (jsonResult) {
|
|
43
|
+
const kb = Math.max(1, Math.round(jsonResult.bytes / 1024));
|
|
44
|
+
console.log(`[cocos] preview json ${jsonResult.files} → 1 pack (${kb} kB)`);
|
|
45
|
+
}
|
|
46
|
+
} catch (err) {
|
|
47
|
+
console.warn(`[cocos] preview json pack skipped: ${err.message}`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return { scriptResult, jsonResult };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
module.exports = {
|
|
54
|
+
previewTargetDir,
|
|
55
|
+
rebundlePreviewMerge,
|
|
56
|
+
};
|
|
@@ -1,7 +1,119 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
/** Creator / cocos CLI 会静态解析这次 import(),不能让 social-share 进模块图。 */
|
|
7
|
+
const IMPORT_RE = /import\s*\(\s*["']@playcraft\/ads-tracking\/social-share["']\s*\)/g;
|
|
8
|
+
|
|
9
|
+
/** 审核会扫这些硬编码请求;非社媒产物里必须清掉。 */
|
|
10
|
+
const PACK_TRANSFORMS = [
|
|
11
|
+
[IMPORT_RE, 'Promise.resolve({})'],
|
|
12
|
+
[/["']@playcraft\/ads-tracking\/social-share["']/g, '""'],
|
|
13
|
+
[/https:\/\/static\.aix\.levelinfinite\.com\/sdk\/aix_track_web_sdk_v2\.js/g, ''],
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
const TEXT_EXTS = new Set(['.js', '.mjs', '.cjs', '.html', '.htm']);
|
|
17
|
+
|
|
18
|
+
/** 4.0 预览把 CJS 当严格模块跑,裸 AD_NETWORK 不会落到 window。 */
|
|
19
|
+
const CJS_DEFINE_KEYS = [
|
|
20
|
+
'AD_NETWORK',
|
|
21
|
+
'AD_PROTOCOL',
|
|
22
|
+
'GOOGLE_PLAY_URL',
|
|
23
|
+
'APP_STORE_URL',
|
|
24
|
+
'BUILD_HASH',
|
|
25
|
+
'LANGUAGE',
|
|
26
|
+
'ORIENTATION',
|
|
27
|
+
'APP',
|
|
28
|
+
'NAME',
|
|
29
|
+
'VERSION',
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
const CJS_DEFINE_PAD = CJS_DEFINE_KEYS.map((key) => `var ${key} = globalThis.${key};`).join('\n');
|
|
33
|
+
|
|
34
|
+
function padAdsdkCjsGlobals(src) {
|
|
35
|
+
if (src.includes('var AD_NETWORK = globalThis.AD_NETWORK')) return src;
|
|
36
|
+
if (/^['"]use strict['"];/.test(src)) {
|
|
37
|
+
return src.replace(/^['"]use strict['"];/, (line) => `${line}\n${CJS_DEFINE_PAD}`);
|
|
38
|
+
}
|
|
39
|
+
return `"use strict";\n${CJS_DEFINE_PAD}\n${src}`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function isSocialMediaNetwork(network) {
|
|
43
|
+
return String(network || '').toLowerCase() === 'social_media';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function adsdkCjsPath(projectRoot) {
|
|
47
|
+
return path.join(projectRoot, 'node_modules', '@playcraft', 'adsdk', 'dist', 'index.js');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
2
51
|
* 把 CJS 里的 social-share import() 收成空 Promise,并垫上 AD_NETWORK 等全局别名。
|
|
3
52
|
* Cocos 4.0 预览按严格模块执行 npm CJS,裸标识符不会落到 window。
|
|
4
|
-
*/
|
|
53
|
+
*/
|
|
54
|
+
function stripAdsdkCjsImport(projectRoot) {
|
|
55
|
+
const file = adsdkCjsPath(projectRoot);
|
|
56
|
+
if (!fs.existsSync(file)) {
|
|
57
|
+
return { skipped: true, reason: 'missing', file };
|
|
58
|
+
}
|
|
59
|
+
const src = fs.readFileSync(file, 'utf8');
|
|
60
|
+
const next = padAdsdkCjsGlobals(src.replace(IMPORT_RE, 'Promise.resolve({})'));
|
|
61
|
+
if (src === next) {
|
|
62
|
+
const already = next.includes('Promise.resolve({}).then') && next.includes('var AD_NETWORK = globalThis.AD_NETWORK');
|
|
63
|
+
return { skipped: true, reason: already ? 'already' : 'not-found', file };
|
|
64
|
+
}
|
|
65
|
+
fs.writeFileSync(file, next);
|
|
66
|
+
return { skipped: false, file };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function stripSocialShareFromText(src) {
|
|
70
|
+
let next = src;
|
|
71
|
+
for (const [re, replacement] of PACK_TRANSFORMS) {
|
|
72
|
+
next = next.replace(re, replacement);
|
|
73
|
+
}
|
|
74
|
+
return next;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function walkFiles(dir, out = []) {
|
|
78
|
+
if (!fs.existsSync(dir)) return out;
|
|
79
|
+
for (const name of fs.readdirSync(dir)) {
|
|
80
|
+
const abs = path.join(dir, name);
|
|
81
|
+
let stat;
|
|
82
|
+
try {
|
|
83
|
+
stat = fs.statSync(abs);
|
|
84
|
+
} catch {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (stat.isDirectory()) {
|
|
88
|
+
walkFiles(abs, out);
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (TEXT_EXTS.has(path.extname(name).toLowerCase())) out.push(abs);
|
|
92
|
+
}
|
|
93
|
+
return out;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
5
97
|
* 从引擎产物 / 单文件 HTML 里清掉 social-share 与 AiX URL。
|
|
6
98
|
* 仅非 social_media 渠道调用。
|
|
7
|
-
*/
|
|
99
|
+
*/
|
|
100
|
+
function stripSocialShareFromDir(dir) {
|
|
101
|
+
const files = walkFiles(dir);
|
|
102
|
+
let changed = 0;
|
|
103
|
+
for (const file of files) {
|
|
104
|
+
const src = fs.readFileSync(file, 'utf8');
|
|
105
|
+
const next = stripSocialShareFromText(src);
|
|
106
|
+
if (src === next) continue;
|
|
107
|
+
fs.writeFileSync(file, next);
|
|
108
|
+
changed += 1;
|
|
109
|
+
}
|
|
110
|
+
return { dir, files: files.length, changed };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
module.exports = {
|
|
114
|
+
isSocialMediaNetwork,
|
|
115
|
+
stripAdsdkCjsImport,
|
|
116
|
+
padAdsdkCjsGlobals,
|
|
117
|
+
stripSocialShareFromText,
|
|
118
|
+
stripSocialShareFromDir,
|
|
119
|
+
};
|