@ecopages/core 0.2.0-alpha.17 → 0.2.0-alpha.18

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
@@ -24,6 +24,7 @@ All notable changes to `@ecopages/core` are documented here.
24
24
 
25
25
  - Fixed mixed-integration page, layout, document, and component rendering to resolve foreign boundaries inside their owning renderer across the built-in integrations.
26
26
  - 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.
27
+ - Fixed Node bootstrap runtime package linking to refresh dangling `.eco/node_modules` symlinks instead of failing with `EEXIST` during page transpilation.
27
28
  - Fixed request-time and static-generation page inspection to preserve integration-specific page loading without reusing the normal render module identity.
28
29
  - Fixed Node preview and static-generation React runtime resolution so app-owned page modules and server rendering share one React module identity.
29
30
  - Fixed Bun browser output normalization so batched multi-entrypoint HMR rebuilds match emitted files to their expected served paths instead of Bun output order.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ecopages/core",
3
- "version": "0.2.0-alpha.17",
3
+ "version": "0.2.0-alpha.18",
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.17",
20
+ "@ecopages/file-system": "0.2.0-alpha.18",
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",
@@ -16,7 +16,6 @@ export interface NodeBootstrapResolutionOptions {
16
16
  * package roots so transpiled Node imports share one package graph.
17
17
  */
18
18
  runtimeNodeModulesDir: string;
19
- preserveImportMetaPaths?: string[];
20
19
  }
21
20
  /**
22
21
  * Builds the user-facing error for Bun-native imports that cannot run on the
@@ -40,6 +39,4 @@ export declare function createNodeBootstrapPlugin(options: NodeBootstrapResoluti
40
39
  * directory so transpiled server modules can externalize packages into one
41
40
  * stable runtime node_modules graph.
42
41
  */
43
- export declare function createAppNodeBootstrapPlugin(appConfig: Pick<EcoPagesAppConfig, 'rootDir' | 'workDir' | 'absolutePaths'>, options?: {
44
- preserveImportMetaPaths?: string[];
45
- }): EcoBuildPlugin;
42
+ export declare function createAppNodeBootstrapPlugin(appConfig: Pick<EcoPagesAppConfig, 'rootDir' | 'workDir' | 'absolutePaths'>): EcoBuildPlugin;
@@ -1,5 +1,5 @@
1
1
  import path from "node:path";
2
- import { existsSync, mkdirSync, readFileSync, realpathSync, rmSync, symlinkSync } from "node:fs";
2
+ import { existsSync, lstatSync, mkdirSync, readFileSync, realpathSync, rmSync, symlinkSync } from "node:fs";
3
3
  import { createRequire } from "node:module";
4
4
  import { fileURLToPath, pathToFileURL } from "node:url";
5
5
  import { resolveInternalExecutionDir } from "../../utils/resolve-work-dir.js";
@@ -27,18 +27,44 @@ function findPackageRoot(resolvedPath) {
27
27
  currentPath = parentPath;
28
28
  }
29
29
  }
30
+ function pathEntryExists(filePath) {
31
+ try {
32
+ lstatSync(filePath);
33
+ return true;
34
+ } catch {
35
+ return false;
36
+ }
37
+ }
38
+ function linkPointsToPackage(linkPath, packageRoot) {
39
+ try {
40
+ return realpathSync(linkPath) === realpathSync(packageRoot);
41
+ } catch {
42
+ return false;
43
+ }
44
+ }
30
45
  function ensureRuntimePackageLink(nodeModulesDir, specifier, resolvedPath) {
31
46
  const packageName = getPackageNameFromSpecifier(specifier);
32
47
  const packageRoot = findPackageRoot(resolvedPath);
33
48
  const linkPath = path.join(nodeModulesDir, packageName);
34
- if (existsSync(linkPath)) {
35
- if (realpathSync(linkPath) === realpathSync(packageRoot)) {
49
+ mkdirSync(path.dirname(linkPath), { recursive: true });
50
+ if (pathEntryExists(linkPath)) {
51
+ if (linkPointsToPackage(linkPath, packageRoot)) {
36
52
  return;
37
53
  }
38
54
  rmSync(linkPath, { recursive: true, force: true });
39
55
  }
40
- mkdirSync(path.dirname(linkPath), { recursive: true });
41
- symlinkSync(packageRoot, linkPath, "dir");
56
+ try {
57
+ symlinkSync(packageRoot, linkPath, "dir");
58
+ } catch (error) {
59
+ if (error.code !== "EEXIST") {
60
+ throw error;
61
+ }
62
+ if (linkPointsToPackage(linkPath, packageRoot)) {
63
+ return;
64
+ }
65
+ rmSync(linkPath, { recursive: true, force: true });
66
+ symlinkSync(packageRoot, linkPath, "dir");
67
+ }
42
68
  }
43
69
  function getNodeUnsupportedBuiltinError(specifier, importer) {
44
70
  return `Node bootstrap transpilation does not support Bun builtin specifier ${JSON.stringify(specifier)}${importer ? ` imported from ${importer}` : ""}.`;
@@ -86,26 +112,6 @@ function getBootstrapBuildLoaderForPath(filePath) {
86
112
  return "js";
87
113
  }
88
114
  }
89
- const REEXPORT_FROM_STATEMENT_PATTERN = /^\s*export\s+(?!type\b)(?:\*|\{[\s\S]*?\})\s+from\s+(['"][^'"]+['"])\s*;?\s*$/gm;
90
- function injectBootstrapReexportImports(source) {
91
- const sideEffectImports = [];
92
- const importedSpecifiers = /* @__PURE__ */ new Set();
93
- let importIndex = 0;
94
- const rewrittenSource = source.replace(REEXPORT_FROM_STATEMENT_PATTERN, (statement, specifierLiteral) => {
95
- if (!importedSpecifiers.has(specifierLiteral)) {
96
- importedSpecifiers.add(specifierLiteral);
97
- const importBinding = `__eco_bootstrap_reexport_${importIndex++}`;
98
- sideEffectImports.push(`import * as ${importBinding} from ${specifierLiteral};`);
99
- sideEffectImports.push(`void ${importBinding};`);
100
- }
101
- return statement;
102
- });
103
- if (sideEffectImports.length === 0) {
104
- return source;
105
- }
106
- return `${sideEffectImports.join("\n")}
107
- ${rewrittenSource}`;
108
- }
109
115
  function shouldRewriteBootstrapSource(filePath, projectDir) {
110
116
  const normalizedPath = path.resolve(filePath);
111
117
  const normalizedProjectDir = path.resolve(projectDir);
@@ -154,9 +160,6 @@ function resolveNodeBootstrapDependency(args, options) {
154
160
  }
155
161
  function createNodeBootstrapPlugin(options) {
156
162
  const projectDir = path.resolve(options.projectDir);
157
- const importMetaRewritePaths = new Set(
158
- (options.preserveImportMetaPaths ?? []).map((filePath) => path.resolve(filePath))
159
- );
160
163
  return {
161
164
  name: "node-bootstrap-plugin",
162
165
  setup(build) {
@@ -165,20 +168,12 @@ function createNodeBootstrapPlugin(options) {
165
168
  });
166
169
  build.onLoad({ filter: /\.[cm]?[jt]sx?$/ }, async (args) => {
167
170
  const absolutePath = path.resolve(args.path);
168
- const isProjectSource = shouldRewriteBootstrapSource(absolutePath, projectDir);
169
- const shouldPreserveImportMeta = isProjectSource || importMetaRewritePaths.has(absolutePath);
170
- const shouldRewriteReexports = isProjectSource;
171
- if (!shouldPreserveImportMeta && !shouldRewriteReexports) {
171
+ const shouldRewriteImportMeta = shouldRewriteBootstrapSource(absolutePath, projectDir);
172
+ if (!shouldRewriteImportMeta) {
172
173
  return void 0;
173
174
  }
174
175
  const originalContents = readFileSync(args.path, "utf8");
175
- let contents = originalContents;
176
- if (shouldPreserveImportMeta) {
177
- contents = contents.replaceAll("import.meta.dirname", JSON.stringify(path.dirname(args.path))).replaceAll("import.meta.filename", JSON.stringify(args.path));
178
- }
179
- if (shouldRewriteReexports) {
180
- contents = injectBootstrapReexportImports(contents);
181
- }
176
+ const contents = originalContents.replaceAll("import.meta.dirname", JSON.stringify(path.dirname(args.path))).replaceAll("import.meta.filename", JSON.stringify(args.path));
182
177
  if (contents === originalContents) {
183
178
  return void 0;
184
179
  }
@@ -194,11 +189,10 @@ function createNodeBootstrapPlugin(options) {
194
189
  }
195
190
  };
196
191
  }
197
- function createAppNodeBootstrapPlugin(appConfig, options) {
192
+ function createAppNodeBootstrapPlugin(appConfig) {
198
193
  return createNodeBootstrapPlugin({
199
194
  projectDir: appConfig.rootDir,
200
- runtimeNodeModulesDir: getAppRuntimeNodeModulesDir(appConfig),
201
- preserveImportMetaPaths: options?.preserveImportMetaPaths
195
+ runtimeNodeModulesDir: getAppRuntimeNodeModulesDir(appConfig)
202
196
  });
203
197
  }
204
198
  export {