ecopages 0.2.0-beta.0 → 0.2.0-beta.2
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 +37 -15
- package/bin/launch-plan.js +53 -5
- package/package.json +2 -2
package/bin/cli.js
CHANGED
|
@@ -32,6 +32,10 @@ const sharedServerOptionDefinitions = {
|
|
|
32
32
|
runtime: {
|
|
33
33
|
type: "string"
|
|
34
34
|
},
|
|
35
|
+
"entry-file": {
|
|
36
|
+
type: "string",
|
|
37
|
+
short: "e"
|
|
38
|
+
},
|
|
35
39
|
help: {
|
|
36
40
|
type: "boolean",
|
|
37
41
|
short: "h"
|
|
@@ -57,21 +61,22 @@ function getMainHelpText() {
|
|
|
57
61
|
"",
|
|
58
62
|
"Commands:",
|
|
59
63
|
" init <dir> Initialize a new project from a template",
|
|
60
|
-
" dev
|
|
61
|
-
" dev:watch
|
|
62
|
-
" dev:hot
|
|
63
|
-
" build
|
|
64
|
-
" start
|
|
65
|
-
" preview
|
|
64
|
+
" dev Start the development server",
|
|
65
|
+
" dev:watch Start the development server with watch mode",
|
|
66
|
+
" dev:hot Start the development server with hot reload",
|
|
67
|
+
" build Build the project for production",
|
|
68
|
+
" start Start the production server",
|
|
69
|
+
" preview Preview the production build",
|
|
66
70
|
"",
|
|
67
71
|
"Global options:",
|
|
72
|
+
" -e, --entry-file <file> Entry file (default: app.ts)",
|
|
68
73
|
" -h, --help Show help",
|
|
69
74
|
" --version Show version"
|
|
70
75
|
].join("\n");
|
|
71
76
|
}
|
|
72
77
|
function getServerCommandHelpText(commandName, description) {
|
|
73
78
|
return [
|
|
74
|
-
`Usage: ecopages ${commandName} [
|
|
79
|
+
`Usage: ecopages ${commandName} [options]`,
|
|
75
80
|
"",
|
|
76
81
|
description,
|
|
77
82
|
"",
|
|
@@ -82,12 +87,13 @@ function getServerCommandHelpText(commandName, description) {
|
|
|
82
87
|
" -d, --debug Enable debug logging",
|
|
83
88
|
" -r, --react-fast-refresh Enable React Fast Refresh for Bun HMR",
|
|
84
89
|
" --runtime <runtime> Force bun or node",
|
|
90
|
+
" -e, --entry-file <file> Entry file (default: app.ts)",
|
|
85
91
|
" -h, --help Show help"
|
|
86
92
|
].join("\n");
|
|
87
93
|
}
|
|
88
94
|
function getBuildCommandHelpText() {
|
|
89
95
|
return [
|
|
90
|
-
"Usage: ecopages build [
|
|
96
|
+
"Usage: ecopages build [options]",
|
|
91
97
|
"",
|
|
92
98
|
"Build the project for production.",
|
|
93
99
|
"",
|
|
@@ -98,6 +104,7 @@ function getBuildCommandHelpText() {
|
|
|
98
104
|
" -d, --debug Enable debug logging",
|
|
99
105
|
" -r, --react-fast-refresh Enable React Fast Refresh for Bun HMR",
|
|
100
106
|
" --runtime <runtime> Force bun or node",
|
|
107
|
+
" -e, --entry-file <file> Entry file (default: app.ts)",
|
|
101
108
|
" -h, --help Show help"
|
|
102
109
|
].join("\n");
|
|
103
110
|
}
|
|
@@ -127,11 +134,14 @@ function parseServerCommandArgs(rawArgs, commandName, description, mode = "serve
|
|
|
127
134
|
console.log(mode === "build" ? getBuildCommandHelpText() : getServerCommandHelpText(commandName, description));
|
|
128
135
|
return { help: true };
|
|
129
136
|
}
|
|
130
|
-
if (positionals.length >
|
|
131
|
-
throw new Error(
|
|
137
|
+
if (positionals.length > 0) {
|
|
138
|
+
throw new Error(
|
|
139
|
+
`Positional entry file arguments are not supported for \`${commandName}\`. Use --entry-file <file> instead.`
|
|
140
|
+
);
|
|
132
141
|
}
|
|
142
|
+
const entry = values["entry-file"] ?? "app.ts";
|
|
133
143
|
return {
|
|
134
|
-
entry
|
|
144
|
+
entry,
|
|
135
145
|
options: {
|
|
136
146
|
port: values.port,
|
|
137
147
|
hostname: values.hostname,
|
|
@@ -180,14 +190,15 @@ function runLaunchPlan(launchPlan) {
|
|
|
180
190
|
process.exit(code || 0);
|
|
181
191
|
});
|
|
182
192
|
}
|
|
183
|
-
async function runEntryCommand(args, options = {}, entryFile = "app.ts") {
|
|
193
|
+
async function runEntryCommand(args, options = {}, entryFile = "app.ts", launchMode = "start") {
|
|
184
194
|
let launchPlan;
|
|
185
|
-
|
|
195
|
+
const requiresBuiltBundle = launchMode === "start";
|
|
196
|
+
if (!requiresBuiltBundle && !existsSync(entryFile)) {
|
|
186
197
|
logger.error(`Error: Entry file "${entryFile}" not found in the current directory.`);
|
|
187
198
|
process.exit(1);
|
|
188
199
|
}
|
|
189
200
|
try {
|
|
190
|
-
launchPlan = await createLaunchPlan(args, options, entryFile);
|
|
201
|
+
launchPlan = await createLaunchPlan(args, options, entryFile, launchMode);
|
|
191
202
|
} catch (error) {
|
|
192
203
|
const message = error instanceof Error ? error.message : String(error);
|
|
193
204
|
logger.error(message);
|
|
@@ -230,7 +241,12 @@ async function runServerCommand(rawArgs, definition) {
|
|
|
230
241
|
if (parsed.help) {
|
|
231
242
|
return;
|
|
232
243
|
}
|
|
233
|
-
await runEntryCommand(
|
|
244
|
+
await runEntryCommand(
|
|
245
|
+
definition.entryArgs,
|
|
246
|
+
{ ...parsed.options, ...definition.optionOverrides, entryFile: parsed.entry },
|
|
247
|
+
parsed.entry,
|
|
248
|
+
definition.launchMode ?? definition.name
|
|
249
|
+
);
|
|
234
250
|
}
|
|
235
251
|
async function runCli(rawArgs = process.argv.slice(2)) {
|
|
236
252
|
const [commandName, ...commandArgs] = rawArgs;
|
|
@@ -252,6 +268,7 @@ async function runCli(rawArgs = process.argv.slice(2)) {
|
|
|
252
268
|
name: "dev",
|
|
253
269
|
description: "Start the development server.",
|
|
254
270
|
entryArgs: ["--dev"],
|
|
271
|
+
launchMode: "dev",
|
|
255
272
|
optionOverrides: { nodeEnv: "development" }
|
|
256
273
|
});
|
|
257
274
|
return;
|
|
@@ -260,6 +277,7 @@ async function runCli(rawArgs = process.argv.slice(2)) {
|
|
|
260
277
|
name: "dev:watch",
|
|
261
278
|
description: "Start the development server with watch mode.",
|
|
262
279
|
entryArgs: ["--dev"],
|
|
280
|
+
launchMode: "dev",
|
|
263
281
|
optionOverrides: { watch: true, nodeEnv: "development" }
|
|
264
282
|
});
|
|
265
283
|
return;
|
|
@@ -268,6 +286,7 @@ async function runCli(rawArgs = process.argv.slice(2)) {
|
|
|
268
286
|
name: "dev:hot",
|
|
269
287
|
description: "Start the development server with hot reload.",
|
|
270
288
|
entryArgs: ["--dev"],
|
|
289
|
+
launchMode: "dev",
|
|
271
290
|
optionOverrides: { hot: true, nodeEnv: "development" }
|
|
272
291
|
});
|
|
273
292
|
return;
|
|
@@ -276,6 +295,7 @@ async function runCli(rawArgs = process.argv.slice(2)) {
|
|
|
276
295
|
name: "build",
|
|
277
296
|
description: "Build the project for production.",
|
|
278
297
|
entryArgs: ["--build"],
|
|
298
|
+
launchMode: "build",
|
|
279
299
|
optionOverrides: { nodeEnv: "production" },
|
|
280
300
|
mode: "build"
|
|
281
301
|
});
|
|
@@ -285,6 +305,7 @@ async function runCli(rawArgs = process.argv.slice(2)) {
|
|
|
285
305
|
name: "start",
|
|
286
306
|
description: "Start the production server.",
|
|
287
307
|
entryArgs: [],
|
|
308
|
+
launchMode: "start",
|
|
288
309
|
optionOverrides: { nodeEnv: "production" }
|
|
289
310
|
});
|
|
290
311
|
return;
|
|
@@ -293,6 +314,7 @@ async function runCli(rawArgs = process.argv.slice(2)) {
|
|
|
293
314
|
name: "preview",
|
|
294
315
|
description: "Preview the production build.",
|
|
295
316
|
entryArgs: ["--preview"],
|
|
317
|
+
launchMode: "preview",
|
|
296
318
|
optionOverrides: { nodeEnv: "production" }
|
|
297
319
|
});
|
|
298
320
|
return;
|
package/bin/launch-plan.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
2
3
|
import { parseEnv } from "node:util";
|
|
4
|
+
import { SERVER_BUNDLE_DIR, SERVER_BUNDLE_FILENAME } from "@ecopages/core/utils/resolve-entry-file";
|
|
3
5
|
const nodeRequirePreload = import.meta.resolve("./node-require-preload.js");
|
|
4
6
|
const tsxLoader = import.meta.resolve("tsx/esm");
|
|
5
7
|
function getEnvFilePaths(nodeEnv) {
|
|
@@ -16,6 +18,7 @@ function buildEnvOverrides(options) {
|
|
|
16
18
|
if (options.baseUrl) env.ECOPAGES_BASE_URL = options.baseUrl;
|
|
17
19
|
if (options.debug) env.ECOPAGES_LOGGER_DEBUG = "true";
|
|
18
20
|
if (options.nodeEnv) env.NODE_ENV = options.nodeEnv;
|
|
21
|
+
if (options.entryFile) env.ECOPAGES_ENTRY_FILE = options.entryFile;
|
|
19
22
|
return env;
|
|
20
23
|
}
|
|
21
24
|
function buildLaunchEnv(options) {
|
|
@@ -55,14 +58,59 @@ function buildBunArgs(args, options, entryFile, hasConfig) {
|
|
|
55
58
|
}
|
|
56
59
|
return bunArgs;
|
|
57
60
|
}
|
|
58
|
-
function
|
|
59
|
-
|
|
60
|
-
|
|
61
|
+
function usesProductionBundle(launchMode) {
|
|
62
|
+
return launchMode === "start";
|
|
63
|
+
}
|
|
64
|
+
function inferLaunchMode(args, launchMode) {
|
|
65
|
+
if (launchMode) {
|
|
66
|
+
return launchMode;
|
|
67
|
+
}
|
|
68
|
+
if (args.includes("--build")) {
|
|
69
|
+
return "build";
|
|
70
|
+
}
|
|
71
|
+
if (args.includes("--preview")) {
|
|
72
|
+
return "preview";
|
|
73
|
+
}
|
|
74
|
+
if (args.includes("--dev")) {
|
|
75
|
+
return "dev";
|
|
76
|
+
}
|
|
77
|
+
return "start";
|
|
78
|
+
}
|
|
79
|
+
function createLaunchPlan(args, options, entryFile, launchMode) {
|
|
80
|
+
const resolvedOptions = options ?? {};
|
|
81
|
+
const resolvedEntryFile = entryFile ?? "app.ts";
|
|
82
|
+
const { envOverrides, env } = buildLaunchEnv(resolvedOptions);
|
|
83
|
+
const runtime = detectRuntime(resolvedOptions);
|
|
84
|
+
const resolvedLaunchMode = inferLaunchMode(args, launchMode);
|
|
85
|
+
const distServerApp = path.join(process.cwd(), "dist", SERVER_BUNDLE_DIR, SERVER_BUNDLE_FILENAME);
|
|
86
|
+
const shouldUseBundle = usesProductionBundle(resolvedLaunchMode);
|
|
87
|
+
const useBundle = shouldUseBundle && existsSync(distServerApp);
|
|
88
|
+
if (shouldUseBundle && !useBundle) {
|
|
89
|
+
throw new Error("No production bundle found. Run `ecopages build` before starting in production mode.");
|
|
90
|
+
}
|
|
91
|
+
if (useBundle) {
|
|
92
|
+
if (runtime === "node") {
|
|
93
|
+
return {
|
|
94
|
+
runtime,
|
|
95
|
+
command: process.execPath,
|
|
96
|
+
commandArgs: [distServerApp, ...args],
|
|
97
|
+
envOverrides,
|
|
98
|
+
env
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
runtime,
|
|
103
|
+
command: "bun",
|
|
104
|
+
commandArgs: ["run", distServerApp, ...args],
|
|
105
|
+
envOverrides,
|
|
106
|
+
env
|
|
107
|
+
};
|
|
108
|
+
}
|
|
61
109
|
if (runtime === "node") {
|
|
62
110
|
return {
|
|
63
111
|
runtime,
|
|
64
112
|
command: process.execPath,
|
|
65
|
-
commandArgs: ["--import", nodeRequirePreload, "--import", tsxLoader,
|
|
113
|
+
commandArgs: ["--import", nodeRequirePreload, "--import", tsxLoader, resolvedEntryFile, ...args],
|
|
66
114
|
envOverrides,
|
|
67
115
|
env
|
|
68
116
|
};
|
|
@@ -70,7 +118,7 @@ function createLaunchPlan(args, options = {}, entryFile = "app.ts") {
|
|
|
70
118
|
return {
|
|
71
119
|
runtime,
|
|
72
120
|
command: "bun",
|
|
73
|
-
commandArgs: buildBunArgs(args,
|
|
121
|
+
commandArgs: buildBunArgs(args, resolvedOptions, resolvedEntryFile, existsSync("eco.config.ts")),
|
|
74
122
|
envOverrides,
|
|
75
123
|
env
|
|
76
124
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ecopages",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.2",
|
|
4
4
|
"description": "CLI utilities for Ecopages",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"ecopages": "bin/cli.js"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@ecopages/core": "0.2.0-beta.
|
|
35
|
+
"@ecopages/core": "0.2.0-beta.2",
|
|
36
36
|
"@ecopages/logger": "^0.2.3",
|
|
37
37
|
"giget": "^2.0.0",
|
|
38
38
|
"tsx": "^4.22.3"
|