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 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 [entry] Start the development server",
61
- " dev:watch [entry] Start the development server with watch mode",
62
- " dev:hot [entry] Start the development server with hot reload",
63
- " build [entry] Build the project for production",
64
- " start [entry] Start the production server",
65
- " preview [entry] Preview the production build",
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} [entry] [options]`,
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 [entry] [options]",
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 > 1) {
131
- throw new Error(`Too many positional arguments provided for \`${commandName}\`.`);
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: positionals[0] ?? "app.ts",
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
- if (!existsSync(entryFile)) {
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(definition.entryArgs, { ...parsed.options, ...definition.optionOverrides }, parsed.entry);
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;
@@ -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 createLaunchPlan(args, options = {}, entryFile = "app.ts") {
59
- const { envOverrides, env } = buildLaunchEnv(options);
60
- const runtime = detectRuntime(options);
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, entryFile, ...args],
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, options, entryFile, existsSync("eco.config.ts")),
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.0",
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.0",
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"