ecopages 0.2.0-alpha.47 → 0.2.0-alpha.49

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/bin/cli.js CHANGED
@@ -169,7 +169,7 @@ function runLaunchPlan(launchPlan) {
169
169
  });
170
170
  child.on("error", (error) => {
171
171
  if (error && error.code === "ENOENT") {
172
- const hint = launchPlan.runtime === "bun" ? "Install Bun from https://bun.sh to continue." : "Reinstall ecopages and its dependencies so the Node entry bridge dependencies are available.";
172
+ const hint = launchPlan.runtime === "bun" ? "Install Bun from https://bun.sh to continue." : "Reinstall Node.js or run with --runtime bun if this app requires Bun.";
173
173
  logger.error(`Command not found: ${launchPlan.command}. ${hint}`);
174
174
  process.exit(1);
175
175
  }
@@ -1,6 +1,7 @@
1
1
  import { existsSync, readFileSync } from "node:fs";
2
2
  import { parseEnv } from "node:util";
3
- import { buildNodeEntryBridge } from "./node-entry-bridge.js";
3
+ const nodeRequirePreload = import.meta.resolve("./node-require-preload.js");
4
+ const tsxLoader = import.meta.resolve("tsx/esm");
4
5
  function getEnvFilePaths(nodeEnv) {
5
6
  const envFiles = [".env", ".env.local"];
6
7
  if (nodeEnv) {
@@ -54,15 +55,14 @@ function buildBunArgs(args, options, entryFile, hasConfig) {
54
55
  }
55
56
  return bunArgs;
56
57
  }
57
- async function createLaunchPlan(args, options = {}, entryFile = "app.ts") {
58
+ function createLaunchPlan(args, options = {}, entryFile = "app.ts") {
58
59
  const { envOverrides, env } = buildLaunchEnv(options);
59
60
  const runtime = detectRuntime(options);
60
61
  if (runtime === "node") {
61
- const nodeEntryBridge = await buildNodeEntryBridge(entryFile);
62
62
  return {
63
63
  runtime,
64
64
  command: process.execPath,
65
- commandArgs: [nodeEntryBridge, ...args],
65
+ commandArgs: ["--import", nodeRequirePreload, "--import", tsxLoader, entryFile, ...args],
66
66
  envOverrides,
67
67
  env
68
68
  };
@@ -0,0 +1,3 @@
1
+ import path from "node:path";
2
+ import { createRequire } from "node:module";
3
+ globalThis.require = createRequire(path.join(process.cwd(), "package.json"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ecopages",
3
- "version": "0.2.0-alpha.47",
3
+ "version": "0.2.0-alpha.49",
4
4
  "description": "CLI utilities for Ecopages",
5
5
  "type": "module",
6
6
  "engines": {
@@ -32,10 +32,10 @@
32
32
  "ecopages": "bin/cli.js"
33
33
  },
34
34
  "dependencies": {
35
- "@ecopages/core": "0.2.0-alpha.47",
35
+ "@ecopages/core": "0.2.0-alpha.49",
36
36
  "@ecopages/logger": "^0.2.3",
37
- "esbuild": "^0.28.0",
38
- "giget": "^2.0.0"
37
+ "giget": "^2.0.0",
38
+ "tsx": "^4.22.3"
39
39
  },
40
40
  "peerDependencies": {
41
41
  "bun-types": "*",
@@ -1,203 +0,0 @@
1
- import { lstatSync, mkdirSync, readFileSync, realpathSync, rmSync, symlinkSync, unlinkSync } from "node:fs";
2
- import { createRequire } from "node:module";
3
- import path from "node:path";
4
- import { pathToFileURL } from "node:url";
5
- import { build } from "esbuild";
6
- function getLoader(filePath) {
7
- const extension = path.extname(filePath).toLowerCase();
8
- if (extension === ".tsx") return "tsx";
9
- if (extension === ".jsx") return "jsx";
10
- if (extension === ".json") return "json";
11
- return extension === ".ts" || extension === ".mts" || extension === ".cts" ? "ts" : "js";
12
- }
13
- function shouldRewriteSource(filePath, rootDir) {
14
- const normalizedPath = path.resolve(filePath);
15
- const normalizedRootDir = path.resolve(rootDir);
16
- return normalizedPath === normalizedRootDir || normalizedPath.startsWith(`${normalizedRootDir}${path.sep}`);
17
- }
18
- function rewriteImportMeta(contents, filePath, entryFile) {
19
- const normalizedPath = path.resolve(filePath);
20
- const normalizedEntryFile = path.resolve(entryFile);
21
- return contents.replaceAll("import.meta.env", "process.env").replaceAll("import.meta.main", normalizedPath === normalizedEntryFile ? "true" : "false").replaceAll("import.meta.url", JSON.stringify(pathToFileURL(filePath).href)).replaceAll("import.meta.dirname", JSON.stringify(path.dirname(filePath))).replaceAll("import.meta.filename", JSON.stringify(filePath)).replaceAll("import.meta.dir", JSON.stringify(path.dirname(filePath))).replaceAll("import.meta.path", JSON.stringify(filePath));
22
- }
23
- function getPackageNameFromSpecifier(specifier) {
24
- if (specifier.startsWith("@")) {
25
- const [scope, name] = specifier.split("/");
26
- return `${scope}/${name}`;
27
- }
28
- return specifier.split("/")[0] ?? specifier;
29
- }
30
- function findPackageRoot(resolvedPath) {
31
- let currentPath = path.dirname(resolvedPath);
32
- while (true) {
33
- const packageJsonPath = path.join(currentPath, "package.json");
34
- try {
35
- lstatSync(packageJsonPath);
36
- return currentPath;
37
- } catch {
38
- }
39
- const parentPath = path.dirname(currentPath);
40
- if (parentPath === currentPath) {
41
- throw new Error(`Could not find package root for resolved dependency path: ${resolvedPath}`);
42
- }
43
- currentPath = parentPath;
44
- }
45
- }
46
- function linkPointsToPackage(linkPath, packageRoot) {
47
- try {
48
- return realpathSync(linkPath) === realpathSync(packageRoot);
49
- } catch {
50
- return false;
51
- }
52
- }
53
- function removeRuntimePackageLink(linkPath) {
54
- try {
55
- const stats = lstatSync(linkPath);
56
- if (stats.isSymbolicLink()) {
57
- unlinkSync(linkPath);
58
- return;
59
- }
60
- } catch {
61
- return;
62
- }
63
- rmSync(linkPath, { recursive: true, force: true });
64
- }
65
- function ensureRuntimePackageLink(nodeModulesDir, specifier, resolvedPath) {
66
- const packageName = getPackageNameFromSpecifier(specifier);
67
- const packageRoot = findPackageRoot(resolvedPath);
68
- const linkPath = path.join(nodeModulesDir, packageName);
69
- mkdirSync(path.dirname(linkPath), { recursive: true });
70
- try {
71
- lstatSync(linkPath);
72
- if (linkPointsToPackage(linkPath, packageRoot)) {
73
- return;
74
- }
75
- removeRuntimePackageLink(linkPath);
76
- } catch {
77
- }
78
- symlinkSync(packageRoot, linkPath, "dir");
79
- }
80
- function readPackageManifest(packageDir) {
81
- const packageJsonPath = path.join(packageDir, "package.json");
82
- try {
83
- return JSON.parse(readFileSync(packageJsonPath, "utf8"));
84
- } catch {
85
- return void 0;
86
- }
87
- }
88
- function isPackageExportedSubpath(specifier, resolvedPath) {
89
- const packageName = getPackageNameFromSpecifier(specifier);
90
- if (specifier === packageName) {
91
- return false;
92
- }
93
- const packageRoot = findPackageRoot(resolvedPath);
94
- const manifest = readPackageManifest(packageRoot);
95
- if (!manifest?.exports || typeof manifest.exports !== "object" || Array.isArray(manifest.exports)) {
96
- return false;
97
- }
98
- const subpath = `.${specifier.slice(packageName.length)}`;
99
- return subpath in manifest.exports;
100
- }
101
- function getNodeExternalSpecifier(specifier, resolvedPath) {
102
- const packageName = getPackageNameFromSpecifier(specifier);
103
- if (specifier === packageName) {
104
- return specifier;
105
- }
106
- if (path.extname(specifier)) {
107
- return specifier;
108
- }
109
- if (isPackageExportedSubpath(specifier, resolvedPath)) {
110
- return specifier;
111
- }
112
- const resolvedExtension = path.extname(resolvedPath);
113
- if (![".js", ".mjs", ".cjs", ".json"].includes(resolvedExtension)) {
114
- return specifier;
115
- }
116
- const packageRoot = findPackageRoot(resolvedPath);
117
- const requestedSubpath = specifier.slice(packageName.length + 1);
118
- const resolvedSubpath = path.relative(packageRoot, resolvedPath);
119
- if (resolvedSubpath === `${requestedSubpath}${resolvedExtension}`) {
120
- return `${specifier}${resolvedExtension}`;
121
- }
122
- return specifier;
123
- }
124
- function createNodeEntryBridgePlugin({ rootDir, entryFile, runtimeNodeModulesDir }) {
125
- return {
126
- name: "ecopages-node-entry-bridge",
127
- setup(buildContext) {
128
- buildContext.onResolve({ filter: /^[@A-Za-z0-9][^:]*$/ }, (args) => {
129
- try {
130
- const resolvedPath = createRequire(path.join(args.resolveDir || rootDir, "package.json")).resolve(
131
- args.path
132
- );
133
- if (!args.path.startsWith("@ecopages/")) {
134
- ensureRuntimePackageLink(runtimeNodeModulesDir, args.path, resolvedPath);
135
- }
136
- if (resolvedPath.endsWith(".node")) {
137
- return {
138
- path: args.path,
139
- external: true
140
- };
141
- }
142
- if (!args.path.startsWith("@ecopages/")) {
143
- return {
144
- path: getNodeExternalSpecifier(args.path, resolvedPath),
145
- external: true
146
- };
147
- }
148
- } catch {
149
- return void 0;
150
- }
151
- return void 0;
152
- });
153
- buildContext.onResolve({ filter: /\.node$/ }, (args) => ({
154
- path: path.isAbsolute(args.path) ? args.path : path.resolve(args.resolveDir, args.path),
155
- external: true
156
- }));
157
- buildContext.onLoad({ filter: /\.[cm]?[jt]sx?$/ }, (args) => {
158
- if (!shouldRewriteSource(args.path, rootDir)) {
159
- return void 0;
160
- }
161
- const contents = rewriteImportMeta(readFileSync(args.path, "utf8"), args.path, entryFile);
162
- return {
163
- contents,
164
- loader: getLoader(args.path),
165
- resolveDir: path.dirname(args.path)
166
- };
167
- });
168
- }
169
- };
170
- }
171
- async function buildNodeEntryBridge(entryFile, options = {}) {
172
- const rootDir = path.resolve(options.rootDir ?? process.cwd());
173
- const absoluteEntryFile = path.resolve(rootDir, entryFile);
174
- const outdir = path.resolve(rootDir, ".eco", "node-entry");
175
- const outfile = path.join(outdir, "app-entry.mjs");
176
- rmSync(outdir, { recursive: true, force: true });
177
- mkdirSync(outdir, { recursive: true });
178
- await build({
179
- absWorkingDir: rootDir,
180
- entryPoints: [absoluteEntryFile],
181
- outfile,
182
- bundle: true,
183
- format: "esm",
184
- platform: "node",
185
- target: "es2022",
186
- sourcemap: "linked",
187
- banner: {
188
- js: 'import { createRequire as __ecopagesCreateRequire } from "node:module"; const require = __ecopagesCreateRequire(import.meta.url);'
189
- },
190
- logLevel: "silent",
191
- plugins: [
192
- createNodeEntryBridgePlugin({
193
- rootDir,
194
- entryFile: absoluteEntryFile,
195
- runtimeNodeModulesDir: path.join(outdir, "node_modules")
196
- })
197
- ]
198
- });
199
- return outfile;
200
- }
201
- export {
202
- buildNodeEntryBridge
203
- };