MatchMaster/assets/test/tests/preview.cjs

95 lines
5.3 KiB
JavaScript

// Run from the project root: node assets/test/tests/preview.cjs [editorPort=7457] [port=7460]
// Uses the installed Cocos 2.4.15 compiler and the running editor's engine/assets.
const fs = require('fs');
const http = require('http');
const path = require('path');
const Module = require('module');
const root = path.resolve(__dirname, '../../..');
function loadTypeScript() {
const editor = process.env.COCOS_EDITOR_HOME || path.join(process.env.ProgramData || 'C:/ProgramData', 'cocos/editors/Creator/2.4.15');
const archive = path.join(editor, 'resources/app.asar');
const fd = fs.openSync(archive, 'r');
try {
const header = Buffer.alloc(16);
fs.readSync(fd, header, 0, 16, 0);
const json = Buffer.alloc(header.readUInt32LE(12));
fs.readSync(fd, json, 0, json.length, 16);
const files = JSON.parse(json).files.node_modules.files.typescript.files.lib.files;
const entry = files['typescript.js'];
const code = Buffer.alloc(entry.size);
fs.readSync(fd, code, 0, code.length, 8 + header.readUInt32LE(4) + Number(entry.offset));
const compiler = new Module(path.join(__dirname, 'cocos-typescript.js'), module);
compiler.filename = path.join(__dirname, 'cocos-typescript.js');
compiler.paths = module.paths;
compiler._compile(code.toString(), compiler.filename);
return compiler.exports;
} finally { fs.closeSync(fd); }
}
function compress(uuid) {
if (uuid.length !== 36) return uuid;
const hex = uuid.replace(/-/g, '');
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
let result = hex.slice(0, 5);
for (let i = 5; i < 32; i += 3) {
const value = parseInt(hex.slice(i, i + 3), 16);
result += chars[value >> 6] + chars[value & 63];
}
return result;
}
function projectScripts(ts) {
let result = 'window.__quick_compile_project__={load:function(done){const modules={};\n';
for (const relative of ['assets/Script/module/Tool/LevelGameplay.ts', 'assets/GameplayIntro/script/GuideCarousel.ts', 'assets/GameplayIntro/script/GameplayIntro.ts', 'assets/test/script/TestLayoutPanel.ts']) {
const file = path.join(root, relative);
const name = path.basename(file, '.ts');
const uuid = compress(JSON.parse(fs.readFileSync(file + '.meta')).uuid);
const code = ts.transpileModule(fs.readFileSync(file, 'utf8'), {
compilerOptions: { experimentalDecorators: true, module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2017 }
}).outputText;
result += `(function(){const module={exports:{}};const exports=module.exports;const require=p=>modules[p.split('/').pop()];cc._RF.push(module,${JSON.stringify(uuid)},${JSON.stringify(name)});\n${code}\ncc._RF.pop();modules[${JSON.stringify(name)}]=module.exports;})();\n`;
}
return result + 'done();}};';
}
function start() {
const ts = loadTypeScript();
const projectSettings = JSON.parse(fs.readFileSync(path.join(root, 'settings/project.json'), 'utf8'));
const editorPort = Number(process.argv[2] || projectSettings['preview-port'] || 7456);
const port = Number(process.argv[3] || 7460);
http.createServer(async (request, response) => {
try {
const pathname = request.url.split('?')[0];
response.setHeader('Cache-Control', 'no-store');
if (pathname === '/preview-scene.json') {
const scene = JSON.parse(fs.readFileSync(path.join(root, 'assets/test/scene/TestLayout.fire')));
scene[6].__type__ = compress(scene[6].__type__);
response.setHeader('Content-Type', 'application/json');
return response.end(JSON.stringify(scene));
}
if (pathname === '/preview-scripts/__quick_compile__.js') {
response.setHeader('Content-Type', 'application/javascript');
return response.end(projectScripts(ts));
}
// This server only reads the editor's preview files; editor mutations stay disabled.
if (request.method !== 'GET' || pathname === '/update-db') { response.statusCode = 405; return response.end(); }
const upstream = await fetch('http://127.0.0.1:' + editorPort + request.url);
let body = Buffer.from(await upstream.arrayBuffer());
response.statusCode = upstream.status;
response.setHeader('Content-Type', upstream.headers.get('content-type') || 'application/octet-stream');
if (pathname === '/settings.js') body = Buffer.from(body.toString().replace(/jsList:\s*\[[\s\S]*?\]/, 'jsList: []'));
if (pathname === '/') body = Buffer.from(body.toString()
.replace('window.__socket_io__ = window.io;', 'window.__socket_io__ = function(){return {on:function(){}}};')
.replace('</head>', '<style>.toolbar{display:none!important}.content{top:0!important}html,body{margin:0;background:#1b202b}</style></head>'));
response.end(body);
} catch (error) {
response.statusCode = 500;
response.end('Test preview failed. Keep this project open in Cocos Creator and check the editor port.\n' + error.message);
}
}).listen(port, '127.0.0.1', () => console.log('TestLayout preview: http://127.0.0.1:' + port));
}
module.exports = { loadTypeScript };
if (require.main === module) start();