create-yeow 0.2.67 → 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-yeow",
3
- "version": "0.2.67",
3
+ "version": "0.2.68",
4
4
  "description": "Scaffold a Yeow plugin project",
5
5
  "type": "module",
6
6
  "bin": {
@@ -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(' Type check passed');
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(' Type check failed');
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(` Bundled (${(size / 1024).toFixed(1)} KB)`);
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(`name: ${name}\nversion: ${version}\nmain: yeow.template.Bootstrap\napi-version: '${apiVer}'\ndepend:\n - Yeow-Runtime\n`));
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: existsSync(resolve(root, 'assets')) ? resolve(root, 'assets').replace(/\\/g, '/') : null,
145
+ assetsDir: assetsOutDir.replace(/\\/g, '/'),
62
146
  };
63
147
  writeFileSync(resolve(outDir, 'dev.json'), JSON.stringify(devInfo, null, 2));
64
- console.log(` Dev info written`);
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
- const assetsDir = resolve(root, 'assets');
69
- if (existsSync(assetsDir)) {
70
- for (const f of readdirSync(assetsDir, { recursive: true })) {
71
- const fp = resolve(assetsDir, f);
72
- if (statSync(fp).isFile()) {
73
- zip.addFile('assets/' + f, readFileSync(fp));
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', `${name}-${version}.jar`);
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(` Packaged ${outJar}\n`);
171
+ console.log(' \u2713 Packaged ' + outJar + '\n');
84
172
  }
85
173
 
86
174
  main().catch(e => { console.error(e); process.exit(1); });
@@ -231,13 +231,14 @@ function startHotReload() {
231
231
  info('Source changed, rebuilding...');
232
232
  try {
233
233
  execSync('node .yeow/build.js', { cwd: ROOT, stdio: 'pipe', env: { ...process.env, YEOW_DEV: 'true' } });
234
- const compiled = resolve(ROOT, 'dist', '.yeow', 'main.js');
234
+ const compiled = resolve(ROOT, 'dist', '.dev', 'main.js');
235
235
  if (existsSync(compiled)) {
236
+ const devAssets = resolve(ROOT, 'dist', '.dev', '.assets');
236
237
  broadcast({
237
238
  type: 'hot-reload',
238
239
  plugin: cfg.name,
239
240
  codeFile: compiled.replace(/\\/g, '/'),
240
- assetsDir: existsSync(assetsDir) ? assetsDir.replace(/\\/g, '/') : null,
241
+ assetsDir: existsSync(devAssets) ? devAssets.replace(/\\/g, '/') : null,
241
242
  });
242
243
  _consumer = null;
243
244
  ok('Hot reload sent via WebSocket');
@@ -289,7 +290,7 @@ async function printFormattedError(err) {
289
290
  consumer = await getSourceMapConsumer();
290
291
  }
291
292
  if (hasMainJs && !consumer) {
292
- const mapFile = resolve(ROOT, 'dist', '.yeow', 'main.js.map');
293
+ const mapFile = resolve(ROOT, 'dist', '.dev', 'main.js.map');
293
294
  out += ` ${c.D}(source-map not found: ${existsSync(mapFile) ? 'exists but failed to parse' : 'missing at ' + mapFile})${c.r}\n`;
294
295
  }
295
296
 
@@ -374,7 +375,7 @@ async function main() {
374
375
  await initServer();
375
376
  serverProps(cfg.dev?.port || 17367);
376
377
  buildPlugin();
377
- copyToPlugins(resolve(ROOT, 'dist', `${cfg.name}-${cfg.version}.jar`), 'Plugin');
378
+ copyToPlugins(resolve(ROOT, 'dist', 'plugins', `${cfg.name}-${cfg.version}.jar`), 'Plugin');
378
379
  copyToPlugins(RUNTIME, 'Runtime');
379
380
 
380
381
  startHotReload();