create-yeow 0.2.66 → 0.2.68
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/package.json
CHANGED
|
Binary file
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as esbuild from 'esbuild';
|
|
2
|
-
import { readFileSync, writeFileSync, mkdirSync, existsSync, statSync, readdirSync } from 'fs';
|
|
3
|
-
import { resolve } from 'path';
|
|
2
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync, statSync, readdirSync, rmdirSync, copyFileSync } from 'fs';
|
|
3
|
+
import { resolve, dirname, basename, extname } from 'path';
|
|
4
4
|
import { fileURLToPath } from 'url';
|
|
5
|
+
import { createHash } from 'crypto';
|
|
5
6
|
import AdmZip from 'adm-zip';
|
|
6
7
|
import { execSync } from 'child_process';
|
|
7
8
|
|
|
@@ -11,26 +12,103 @@ const { name, version } = cfg;
|
|
|
11
12
|
const isTs = existsSync(resolve(root, 'src', 'index.ts'));
|
|
12
13
|
const entry = isTs ? 'src/index.ts' : 'src/index.js';
|
|
13
14
|
|
|
14
|
-
// Optional type check for TypeScript projects
|
|
15
15
|
if (isTs && cfg.typecheck !== false) {
|
|
16
16
|
try {
|
|
17
17
|
execSync('npx -p typescript tsc --noEmit', { cwd: root, stdio: 'pipe' });
|
|
18
|
-
console.log('
|
|
18
|
+
console.log(' \u2713 Type check passed');
|
|
19
19
|
} catch (e) {
|
|
20
20
|
const out = e.stdout?.toString().trim();
|
|
21
21
|
const err = e.stderr?.toString().trim();
|
|
22
22
|
if (out) console.error(out);
|
|
23
23
|
if (err) console.error(err);
|
|
24
|
-
if (!out && !err) console.error('
|
|
24
|
+
if (!out && !err) console.error(' \u2717 Type check failed');
|
|
25
25
|
process.exit(1);
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
const outDir = resolve(root, 'dist', '.yeow');
|
|
30
|
-
mkdirSync(outDir, { recursive: true });
|
|
31
|
-
|
|
32
29
|
const apiVer = cfg.api || '1.18';
|
|
33
30
|
const isDev = process.env.YEOW_DEV === 'true';
|
|
31
|
+
const outDir = isDev ? resolve(root, 'dist', '.dev') : resolve(root, 'dist', '.yeow');
|
|
32
|
+
const assetsOutDir = resolve(outDir, '.assets');
|
|
33
|
+
const srcAssetsDir = resolve(root, 'assets');
|
|
34
|
+
|
|
35
|
+
// ── esbuild plugin: __yeow-assets virtual module ──
|
|
36
|
+
// 目录级哈希:目录整体重命名 <name>.<dirHash>/,目录内文件保持原名(内部引用不断)
|
|
37
|
+
// 根级文件独立哈希 <name>.<hash><ext>
|
|
38
|
+
const ASSET_TREE = (() => {
|
|
39
|
+
if (!existsSync(srcAssetsDir)) return { children: {}, hash: null };
|
|
40
|
+
const buildTree = (absDir) => {
|
|
41
|
+
const children = {};
|
|
42
|
+
for (const e of readdirSync(absDir, { withFileTypes: true })) {
|
|
43
|
+
const p = resolve(absDir, e.name);
|
|
44
|
+
if (e.isDirectory()) {
|
|
45
|
+
children[e.name] = buildTree(p);
|
|
46
|
+
} else {
|
|
47
|
+
children[e.name] = { isFile: true, contentHash: createHash('md5').update(readFileSync(p)).digest('hex').slice(0, 8) };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const parts = Object.keys(children).sort().map(k => {
|
|
51
|
+
const c = children[k];
|
|
52
|
+
return k + ':' + (c.isFile ? c.contentHash : c.hash);
|
|
53
|
+
});
|
|
54
|
+
return { children, isFile: false, hash: createHash('md5').update(parts.join(',')).digest('hex').slice(0, 8) };
|
|
55
|
+
};
|
|
56
|
+
return buildTree(srcAssetsDir);
|
|
57
|
+
})();
|
|
58
|
+
|
|
59
|
+
const yeowAssetPlugin = {
|
|
60
|
+
name: 'yeow-assets',
|
|
61
|
+
setup(build) {
|
|
62
|
+
build.onResolve({ filter: /^__yeow-assets$/ }, args => ({
|
|
63
|
+
path: args.path,
|
|
64
|
+
namespace: 'yeow-assets',
|
|
65
|
+
}));
|
|
66
|
+
build.onLoad({ filter: /.*/, namespace: 'yeow-assets' }, async () => {
|
|
67
|
+
const map = {};
|
|
68
|
+
mkdirSync(assetsOutDir, { recursive: true });
|
|
69
|
+
|
|
70
|
+
const deploy = (node, absSrc, origRel, hashedRel) => {
|
|
71
|
+
if (!node.isFile && hashedRel) {
|
|
72
|
+
mkdirSync(resolve(assetsOutDir, hashedRel), { recursive: true });
|
|
73
|
+
}
|
|
74
|
+
for (const [name, child] of Object.entries(node.children || {})) {
|
|
75
|
+
if (child.isFile) {
|
|
76
|
+
// 根级文件:独立哈希;目录内文件:保持原名
|
|
77
|
+
if (hashedRel === '') {
|
|
78
|
+
const ext = extname(name);
|
|
79
|
+
const base = basename(name, ext);
|
|
80
|
+
const dest = base + '.' + child.contentHash + ext;
|
|
81
|
+
copyFileSync(resolve(absSrc, name), resolve(assetsOutDir, dest));
|
|
82
|
+
map[name] = 'assets/' + dest;
|
|
83
|
+
} else {
|
|
84
|
+
copyFileSync(resolve(absSrc, name), resolve(assetsOutDir, hashedRel, name));
|
|
85
|
+
map[origRel + name] = 'assets/' + hashedRel + name;
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
const subHashed = (hashedRel === '' ? '' : hashedRel) + name + '.' + child.hash + '/';
|
|
89
|
+
deploy(child, resolve(absSrc, name), origRel + name + '/', subHashed);
|
|
90
|
+
map[origRel + name + '/'] = 'assets/' + subHashed;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
deploy(ASSET_TREE, srcAssetsDir, '', '');
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
contents: 'const _map = ' + JSON.stringify(map) + ';\n' +
|
|
99
|
+
'function _norm(p) { return p.endsWith("/") ? p.slice(0, -1) : p; }\n' +
|
|
100
|
+
'export function getPath(p) {\n' +
|
|
101
|
+
' if (_map[p]) return _map[p];\n' +
|
|
102
|
+
' const n = _norm(p);\n' +
|
|
103
|
+
' if (_map[n]) return _map[n];\n' +
|
|
104
|
+
' if (_map[n + "/"]) return _map[n + "/"];\n' +
|
|
105
|
+
' return p;\n' +
|
|
106
|
+
'}\n',
|
|
107
|
+
loader: 'js',
|
|
108
|
+
};
|
|
109
|
+
});
|
|
110
|
+
},
|
|
111
|
+
};
|
|
34
112
|
|
|
35
113
|
async function main() {
|
|
36
114
|
await esbuild.build({
|
|
@@ -45,42 +123,52 @@ async function main() {
|
|
|
45
123
|
treeShaking: true,
|
|
46
124
|
minify: false,
|
|
47
125
|
sourcemap: isDev ? 'linked' : false,
|
|
126
|
+
plugins: [yeowAssetPlugin],
|
|
48
127
|
});
|
|
49
128
|
|
|
50
129
|
const size = statSync(resolve(outDir, 'main.js')).size;
|
|
51
|
-
console.log(
|
|
130
|
+
console.log(' \u2713 Bundled (' + (size / 1024).toFixed(1) + ' KB)');
|
|
52
131
|
|
|
53
132
|
const tmplJar = resolve(root, '.yeow', 'assets', 'yeow-template-0.1.0.jar');
|
|
54
133
|
const zip = new AdmZip(tmplJar);
|
|
55
|
-
zip.updateFile('plugin.yml', Buffer.from(
|
|
134
|
+
zip.updateFile('plugin.yml', Buffer.from(
|
|
135
|
+
'name: ' + name + '\n' +
|
|
136
|
+
'version: ' + version + '\n' +
|
|
137
|
+
'main: yeow.template.Bootstrap\n' +
|
|
138
|
+
'api-version: \'' + apiVer + '\'\n' +
|
|
139
|
+
'depend:\n - Yeow-Runtime\n'));
|
|
56
140
|
|
|
57
141
|
if (isDev) {
|
|
58
142
|
const devInfo = {
|
|
59
143
|
name,
|
|
60
144
|
codeFile: resolve(outDir, 'main.js').replace(/\\/g, '/'),
|
|
61
|
-
assetsDir:
|
|
145
|
+
assetsDir: assetsOutDir.replace(/\\/g, '/'),
|
|
62
146
|
};
|
|
63
147
|
writeFileSync(resolve(outDir, 'dev.json'), JSON.stringify(devInfo, null, 2));
|
|
64
|
-
console.log(
|
|
148
|
+
console.log(' \u2713 Dev info written');
|
|
65
149
|
zip.addFile('.yeow/dev.json', readFileSync(resolve(outDir, 'dev.json')));
|
|
66
150
|
} else {
|
|
67
151
|
zip.addFile('.yeow/main.js', readFileSync(resolve(outDir, 'main.js')));
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Pack hashed assets into JAR
|
|
155
|
+
if (existsSync(assetsOutDir)) {
|
|
156
|
+
const files = readdirSync(assetsOutDir, { recursive: true });
|
|
157
|
+
for (const f of files) {
|
|
158
|
+
const fp = resolve(assetsOutDir, f);
|
|
159
|
+
if (statSync(fp).isFile()) {
|
|
160
|
+
zip.addFile('assets/' + f.replace(/\\/g, '/'), readFileSync(fp));
|
|
75
161
|
}
|
|
76
|
-
console.log(' ✓ Assets included');
|
|
77
162
|
}
|
|
163
|
+
console.log(' \u2713 Assets included (' + files.filter(f => statSync(resolve(assetsOutDir, f)).isFile()).length + ' files)');
|
|
78
164
|
}
|
|
79
165
|
|
|
80
166
|
zip.addFile('yeow.json', Buffer.from(JSON.stringify(cfg)));
|
|
81
|
-
const outJar = resolve(root, 'dist',
|
|
167
|
+
const outJar = isDev ? resolve(root, 'dist', 'plugins', name + '-' + version + '.jar')
|
|
168
|
+
: resolve(root, 'dist', name + '-' + version + '.jar');
|
|
169
|
+
mkdirSync(dirname(outJar), { recursive: true });
|
|
82
170
|
zip.writeZip(outJar);
|
|
83
|
-
console.log(
|
|
171
|
+
console.log(' \u2713 Packaged ' + outJar + '\n');
|
|
84
172
|
}
|
|
85
173
|
|
|
86
174
|
main().catch(e => { console.error(e); process.exit(1); });
|
|
@@ -76,27 +76,22 @@ let proc = null;
|
|
|
76
76
|
let wss = null;
|
|
77
77
|
|
|
78
78
|
// ── Graceful shutdown ────────────────────────────────────────────
|
|
79
|
+
let cleaning = false;
|
|
79
80
|
function cleanup() {
|
|
81
|
+
if (cleaning) return;
|
|
82
|
+
cleaning = true;
|
|
83
|
+
if (wss) { try { wss.close(); } catch {} }
|
|
80
84
|
if (proc && !proc.killed) {
|
|
81
85
|
try { proc.stdin.write('stop\n'); } catch {}
|
|
82
|
-
setTimeout(() => { if (proc && !proc.killed) try { proc.kill(); } catch {} },
|
|
86
|
+
const killer = setTimeout(() => { if (proc && !proc.killed) try { proc.kill('SIGKILL'); } catch {} }, 10000);
|
|
87
|
+
proc.on('close', () => { clearTimeout(killer); process.exit(0); });
|
|
88
|
+
} else {
|
|
89
|
+
process.exit(0);
|
|
83
90
|
}
|
|
84
|
-
if (wss) { try { wss.close(); } catch {} }
|
|
85
|
-
process.exit(0);
|
|
86
91
|
}
|
|
87
92
|
process.on('SIGINT', cleanup);
|
|
88
93
|
process.on('SIGTERM', cleanup);
|
|
89
|
-
process.on('
|
|
90
|
-
// Windows Ctrl+C in terminal
|
|
91
|
-
if (process.platform === 'win32') {
|
|
92
|
-
import('readline').then(rl => {
|
|
93
|
-
rl.emitKeypressEvents(process.stdin);
|
|
94
|
-
if (process.stdin.isTTY) process.stdin.setRawMode(true);
|
|
95
|
-
process.stdin.on('keypress', (str, key) => {
|
|
96
|
-
if ((key.ctrl && key.name === 'c') || key.name === 'escape') cleanup();
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
}
|
|
94
|
+
process.on('beforeExit', () => { if (proc && !proc.killed) try { proc.kill(); } catch {} });
|
|
100
95
|
|
|
101
96
|
// ── WebSocket Server ────────────────────────────────────────────
|
|
102
97
|
function startWebSocket() {
|
|
@@ -236,13 +231,14 @@ function startHotReload() {
|
|
|
236
231
|
info('Source changed, rebuilding...');
|
|
237
232
|
try {
|
|
238
233
|
execSync('node .yeow/build.js', { cwd: ROOT, stdio: 'pipe', env: { ...process.env, YEOW_DEV: 'true' } });
|
|
239
|
-
const compiled = resolve(ROOT, 'dist', '.
|
|
234
|
+
const compiled = resolve(ROOT, 'dist', '.dev', 'main.js');
|
|
240
235
|
if (existsSync(compiled)) {
|
|
236
|
+
const devAssets = resolve(ROOT, 'dist', '.dev', '.assets');
|
|
241
237
|
broadcast({
|
|
242
238
|
type: 'hot-reload',
|
|
243
239
|
plugin: cfg.name,
|
|
244
240
|
codeFile: compiled.replace(/\\/g, '/'),
|
|
245
|
-
assetsDir: existsSync(
|
|
241
|
+
assetsDir: existsSync(devAssets) ? devAssets.replace(/\\/g, '/') : null,
|
|
246
242
|
});
|
|
247
243
|
_consumer = null;
|
|
248
244
|
ok('Hot reload sent via WebSocket');
|
|
@@ -294,7 +290,7 @@ async function printFormattedError(err) {
|
|
|
294
290
|
consumer = await getSourceMapConsumer();
|
|
295
291
|
}
|
|
296
292
|
if (hasMainJs && !consumer) {
|
|
297
|
-
|
|
293
|
+
const mapFile = resolve(ROOT, 'dist', '.dev', 'main.js.map');
|
|
298
294
|
out += ` ${c.D}(source-map not found: ${existsSync(mapFile) ? 'exists but failed to parse' : 'missing at ' + mapFile})${c.r}\n`;
|
|
299
295
|
}
|
|
300
296
|
|
|
@@ -365,6 +361,7 @@ function startServer() {
|
|
|
365
361
|
info(`\nStarting Paper ${PAPER_VERSION} server...`);
|
|
366
362
|
proc = spawn('java', [...jvmArgs, '-jar', resolve(SERVER, PAPER_JAR), '--nogui'], { cwd: SERVER, stdio: ['pipe', 'inherit', 'inherit'] });
|
|
367
363
|
proc.on('exit', code => { warn(`Server exited (${code})`); if (wss) wss.close(); process.exit(0); });
|
|
364
|
+
process.stdin.on('data', d => { if (proc && !proc.killed) try { proc.stdin.write(d); } catch {} });
|
|
368
365
|
if (STOP) { info(`Auto-stop in ${STOP}s`); setTimeout(() => { warn('Auto-stop'); cleanup(); }, STOP * 1000); }
|
|
369
366
|
}
|
|
370
367
|
|
|
@@ -378,7 +375,7 @@ async function main() {
|
|
|
378
375
|
await initServer();
|
|
379
376
|
serverProps(cfg.dev?.port || 17367);
|
|
380
377
|
buildPlugin();
|
|
381
|
-
copyToPlugins(resolve(ROOT, 'dist', `${cfg.name}-${cfg.version}.jar`), 'Plugin');
|
|
378
|
+
copyToPlugins(resolve(ROOT, 'dist', 'plugins', `${cfg.name}-${cfg.version}.jar`), 'Plugin');
|
|
382
379
|
copyToPlugins(RUNTIME, 'Runtime');
|
|
383
380
|
|
|
384
381
|
startHotReload();
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "my-yeow-plugin",
|
|
3
3
|
"version": "1.0.0",
|
|
4
|
-
"author": "
|
|
4
|
+
"author": "",
|
|
5
5
|
"description": "A Yeow plugin",
|
|
6
6
|
"api": "1.18",
|
|
7
7
|
"java": 21,
|
|
8
8
|
"typecheck": true,
|
|
9
9
|
"dev": {
|
|
10
10
|
"port": 17367,
|
|
11
|
-
"memory": "4G"
|
|
11
|
+
"memory": "4G",
|
|
12
|
+
"paperJar": "https://fill-data.papermc.io/v1/objects/5ee4f542f628a14c644410b08c94ea42e772ef4d29fe92973636b6813d4eaffc/paper-1.21.4-232.jar"
|
|
12
13
|
}
|
|
13
|
-
}
|
|
14
|
+
}
|