@ecopages/core 0.2.0-alpha.15 → 0.2.0-alpha.16

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/CHANGELOG.md CHANGED
@@ -23,7 +23,7 @@ All notable changes to `@ecopages/core` are documented here.
23
23
  - Fixed host/runtime module loading, published build-helper exports, asset output normalization, explicit render flows, and static or preview build stability across Bun, Node, Vite, and Nitro.
24
24
  - Fixed request-time and static-generation page inspection to preserve integration-specific page loading without reusing the normal render module identity.
25
25
  - Fixed Node preview and static-generation React runtime resolution so app-owned page modules and server rendering share one React module identity.
26
- - Fixed Bun HMR script output normalization so multi-entrypoint browser builds preserve the expected outbase-relative source paths for emitted files.
26
+ - Fixed Bun browser output normalization so batched multi-entrypoint HMR rebuilds match emitted files to their expected served paths instead of Bun output order.
27
27
  - Fixed render-preparation graph traversal so sparse component dependency arrays do not break custom 404 rendering or file-system response fallback flows.
28
28
 
29
29
  ### Documentation
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ecopages/core",
3
- "version": "0.2.0-alpha.15",
3
+ "version": "0.2.0-alpha.16",
4
4
  "description": "Core package for Ecopages",
5
5
  "keywords": [
6
6
  "ecopages",
@@ -17,7 +17,7 @@
17
17
  "directory": "packages/core"
18
18
  },
19
19
  "dependencies": {
20
- "@ecopages/file-system": "0.2.0-alpha.15",
20
+ "@ecopages/file-system": "0.2.0-alpha.16",
21
21
  "@ecopages/logger": "^0.2.3",
22
22
  "@ecopages/scripts-injector": "^0.1.3",
23
23
  "@worker-tools/html-rewriter": "0.1.0-pre.19",
@@ -108,11 +108,14 @@ export declare class BunBuildAdapter implements BuildAdapter {
108
108
  private mapBunFormat;
109
109
  private getOutputExtension;
110
110
  private resolveConcreteOutputPath;
111
+ private normalizePathForMatch;
112
+ private normalizeOutputPathForMatch;
113
+ private extractTemplateHashTokens;
114
+ private applyTemplateHashTokens;
111
115
  private resolveTemplatedOutputPath;
112
116
  private relocateOutputFile;
113
- private createDeterministicOutputReference;
114
- private collectDeterministicOutputReferences;
115
117
  private hasJavaScriptExtension;
118
+ private findOutputMatchForEntrypoint;
116
119
  private normalizeBunOutputs;
117
120
  private rewriteAliasedRuntimeSpecifiers;
118
121
  build(options: BuildOptions): Promise<BuildResult>;
@@ -234,7 +234,52 @@ class BunBuildAdapter {
234
234
  }
235
235
  return path.join(directory, matches[0]);
236
236
  }
237
- resolveTemplatedOutputPath(options, entrypointPath, concreteOutputPath) {
237
+ normalizePathForMatch(filePath) {
238
+ return path.normalize(filePath).split(path.sep).join("/");
239
+ }
240
+ normalizeOutputPathForMatch(outputPath, templatePath) {
241
+ const normalizedOutputPath = path.normalize(outputPath);
242
+ const templateExtension = path.extname(templatePath);
243
+ if (!templateExtension) {
244
+ return normalizedOutputPath;
245
+ }
246
+ if (templateExtension === ".js") {
247
+ if (this.hasJavaScriptExtension(normalizedOutputPath)) {
248
+ return path.normalize(normalizedOutputPath.replace(/\.(?:[cm]?js)$/u, ".js"));
249
+ }
250
+ return path.normalize(`${normalizedOutputPath}.js`);
251
+ }
252
+ if (normalizedOutputPath.endsWith(templateExtension)) {
253
+ return normalizedOutputPath;
254
+ }
255
+ return path.normalize(`${normalizedOutputPath}${templateExtension}`);
256
+ }
257
+ extractTemplateHashTokens(templatePath, candidatePath) {
258
+ const normalizedTemplatePath = this.normalizePathForMatch(templatePath);
259
+ const normalizedCandidatePath = this.normalizePathForMatch(
260
+ this.normalizeOutputPathForMatch(candidatePath, templatePath)
261
+ );
262
+ const matcher = new RegExp(
263
+ `^${this.escapeRegExp(normalizedTemplatePath).replace(/\\\[hash\\\]/g, "([^/]+)")}$`
264
+ );
265
+ const match = normalizedCandidatePath.match(matcher);
266
+ if (!match) {
267
+ return void 0;
268
+ }
269
+ return match.slice(1);
270
+ }
271
+ applyTemplateHashTokens(templatePath, hashTokens) {
272
+ const hashTokenCount = templatePath.match(/\[hash\]/g)?.length ?? 0;
273
+ if (hashTokenCount !== hashTokens.length) {
274
+ return void 0;
275
+ }
276
+ if (hashTokenCount === 0) {
277
+ return templatePath;
278
+ }
279
+ let hashTokenIndex = 0;
280
+ return templatePath.replace(/\[hash\]/g, () => hashTokens[hashTokenIndex++] ?? "");
281
+ }
282
+ resolveTemplatedOutputPath(options, entrypointPath) {
238
283
  if (!options.outdir) {
239
284
  return void 0;
240
285
  }
@@ -252,18 +297,6 @@ class BunBuildAdapter {
252
297
  resolvedPath += outputExtension;
253
298
  }
254
299
  resolvedPath = resolvedPath.replace(/^\.\//, "");
255
- if (resolvedPath.includes("[hash]")) {
256
- if (!concreteOutputPath) {
257
- return path.join(outdir, resolvedPath);
258
- }
259
- const concreteRelativePath = path.relative(outdir, concreteOutputPath).split(path.sep).join("/");
260
- const matcher = new RegExp(`^${this.escapeRegExp(resolvedPath).replace(/\\\[hash\\\]/g, "(.+)")}$`);
261
- const match = concreteRelativePath.match(matcher);
262
- if (!match?.[1]) {
263
- return concreteOutputPath;
264
- }
265
- resolvedPath = resolvedPath.replaceAll("[hash]", match[1]);
266
- }
267
300
  return path.join(outdir, resolvedPath);
268
301
  }
269
302
  relocateOutputFile(currentPath, targetPath) {
@@ -275,55 +308,68 @@ class BunBuildAdapter {
275
308
  fs.renameSync(currentPath, targetPath);
276
309
  return targetPath;
277
310
  }
278
- createDeterministicOutputReference(outputPath) {
279
- return path.normalize(outputPath).replace(/\.(?:[cm]?js)$/u, "");
311
+ hasJavaScriptExtension(outputPath) {
312
+ return /\.(?:[cm]?js)$/u.test(outputPath);
280
313
  }
281
- collectDeterministicOutputReferences(options, entrypointPath) {
282
- const expectedOutputsByReference = /* @__PURE__ */ new Map();
314
+ findOutputMatchForEntrypoint(options, entrypointPath, outputs, usedOutputIndexes) {
283
315
  const expectedOutputPath = this.resolveTemplatedOutputPath(options, entrypointPath);
284
316
  if (!expectedOutputPath) {
285
- return expectedOutputsByReference;
286
- }
287
- expectedOutputsByReference.set(this.createDeterministicOutputReference(expectedOutputPath), expectedOutputPath);
288
- if (!options.outbase) {
289
- return expectedOutputsByReference;
317
+ return void 0;
290
318
  }
291
- const bunRootRelativeOutputPath = this.resolveTemplatedOutputPath(
292
- { ...options, outbase: void 0 },
293
- entrypointPath
294
- );
295
- if (bunRootRelativeOutputPath && bunRootRelativeOutputPath !== expectedOutputPath) {
296
- expectedOutputsByReference.set(
297
- this.createDeterministicOutputReference(bunRootRelativeOutputPath),
298
- expectedOutputPath
319
+ const expectedMatchPaths = [expectedOutputPath];
320
+ if (options.outbase) {
321
+ const bunRootRelativeOutputPath = this.resolveTemplatedOutputPath(
322
+ { ...options, outbase: void 0 },
323
+ entrypointPath
299
324
  );
325
+ if (bunRootRelativeOutputPath && bunRootRelativeOutputPath !== expectedOutputPath) {
326
+ expectedMatchPaths.push(bunRootRelativeOutputPath);
327
+ }
300
328
  }
301
- return expectedOutputsByReference;
302
- }
303
- hasJavaScriptExtension(outputPath) {
304
- return /\.(?:[cm]?js)$/u.test(outputPath);
329
+ for (const [outputIndex, output] of outputs.entries()) {
330
+ if (usedOutputIndexes.has(outputIndex)) {
331
+ continue;
332
+ }
333
+ for (const matchPath of expectedMatchPaths) {
334
+ const hashTokens = this.extractTemplateHashTokens(matchPath, output.concretePath);
335
+ if (!hashTokens) {
336
+ continue;
337
+ }
338
+ const targetPath = this.applyTemplateHashTokens(expectedOutputPath, hashTokens);
339
+ if (!targetPath) {
340
+ continue;
341
+ }
342
+ usedOutputIndexes.add(outputIndex);
343
+ return { outputIndex, targetPath };
344
+ }
345
+ }
346
+ return void 0;
305
347
  }
306
348
  normalizeBunOutputs(result, options) {
307
349
  if (!result.success || result.outputs.length === 0) {
308
350
  return result;
309
351
  }
310
- const normalizedOutputs = [...result.outputs];
311
- const expectedOutputsByReference = /* @__PURE__ */ new Map();
352
+ const normalizedOutputs = result.outputs.map((output) => ({
353
+ concretePath: this.resolveConcreteOutputPath(output.path) ?? output.path
354
+ }));
355
+ const matchedTargetsByIndex = /* @__PURE__ */ new Map();
356
+ const usedOutputIndexes = /* @__PURE__ */ new Set();
312
357
  for (const entrypointPath of options.entrypoints) {
313
- for (const [reference, expectedOutputPath] of this.collectDeterministicOutputReferences(
358
+ const matchedOutput = this.findOutputMatchForEntrypoint(
314
359
  options,
315
- entrypointPath
316
- )) {
317
- expectedOutputsByReference.set(reference, expectedOutputPath);
360
+ entrypointPath,
361
+ normalizedOutputs,
362
+ usedOutputIndexes
363
+ );
364
+ if (matchedOutput) {
365
+ matchedTargetsByIndex.set(matchedOutput.outputIndex, matchedOutput.targetPath);
318
366
  }
319
367
  }
320
368
  return {
321
369
  ...result,
322
- outputs: normalizedOutputs.map((output) => {
323
- const concreteOutputPath = this.resolveConcreteOutputPath(output.path) ?? output.path;
324
- const expectedOutputPath = expectedOutputsByReference.get(
325
- this.createDeterministicOutputReference(concreteOutputPath)
326
- );
370
+ outputs: normalizedOutputs.map((output, index) => {
371
+ const expectedOutputPath = matchedTargetsByIndex.get(index);
372
+ const concreteOutputPath = output.concretePath;
327
373
  if (expectedOutputPath) {
328
374
  return {
329
375
  path: this.relocateOutputFile(concreteOutputPath, expectedOutputPath)