ecopages 0.2.0-alpha.47 → 0.2.0-alpha.48
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 +1 -1
- package/bin/launch-plan.js +3 -4
- package/package.json +4 -4
- package/bin/node-entry-bridge.js +0 -203
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
|
|
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
|
}
|
package/bin/launch-plan.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { parseEnv } from "node:util";
|
|
3
|
-
|
|
3
|
+
const tsxLoader = import.meta.resolve("tsx/esm");
|
|
4
4
|
function getEnvFilePaths(nodeEnv) {
|
|
5
5
|
const envFiles = [".env", ".env.local"];
|
|
6
6
|
if (nodeEnv) {
|
|
@@ -54,15 +54,14 @@ function buildBunArgs(args, options, entryFile, hasConfig) {
|
|
|
54
54
|
}
|
|
55
55
|
return bunArgs;
|
|
56
56
|
}
|
|
57
|
-
|
|
57
|
+
function createLaunchPlan(args, options = {}, entryFile = "app.ts") {
|
|
58
58
|
const { envOverrides, env } = buildLaunchEnv(options);
|
|
59
59
|
const runtime = detectRuntime(options);
|
|
60
60
|
if (runtime === "node") {
|
|
61
|
-
const nodeEntryBridge = await buildNodeEntryBridge(entryFile);
|
|
62
61
|
return {
|
|
63
62
|
runtime,
|
|
64
63
|
command: process.execPath,
|
|
65
|
-
commandArgs: [
|
|
64
|
+
commandArgs: ["--import", tsxLoader, entryFile, ...args],
|
|
66
65
|
envOverrides,
|
|
67
66
|
env
|
|
68
67
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ecopages",
|
|
3
|
-
"version": "0.2.0-alpha.
|
|
3
|
+
"version": "0.2.0-alpha.48",
|
|
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.
|
|
35
|
+
"@ecopages/core": "0.2.0-alpha.48",
|
|
36
36
|
"@ecopages/logger": "^0.2.3",
|
|
37
|
-
"
|
|
38
|
-
"
|
|
37
|
+
"giget": "^2.0.0",
|
|
38
|
+
"tsx": "^4.22.3"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
41
|
"bun-types": "*",
|
package/bin/node-entry-bridge.js
DELETED
|
@@ -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
|
-
};
|