ecopages 0.1.105 → 0.2.0-alpha.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.
Files changed (3) hide show
  1. package/README.md +13 -15
  2. package/bin/cli.js +155 -48
  3. package/package.json +43 -43
package/README.md CHANGED
@@ -71,21 +71,19 @@ import { kitajsPlugin } from '@ecopages/kitajs';
71
71
 
72
72
  ### Available Packages
73
73
 
74
- | Package | Description | JSR Link |
75
- | :-------------------------------- | :-------------------------------------------------------- | :---------------------------------------------------- |
76
- | `@ecopages/browser-router` | Client-side navigation and view transitions for Ecopages. | [JSR](https://jsr.io/@ecopages/browser-router) |
77
- | `@ecopages/bun-inline-css-plugin` | Bun plugin to process CSS files using CSS Processors. | [JSR](https://jsr.io/@ecopages/bun-inline-css-plugin) |
78
- | `@ecopages/bun-mdx-kitajs-loader` | Bun loader to load MDX files with KitaJS. | [JSR](https://jsr.io/@ecopages/bun-mdx-kitajs-loader) |
79
- | `@ecopages/bun-postcss-loader` | Bun loader to load PostCSS files. | [JSR](https://jsr.io/@ecopages/bun-postcss-loader) |
80
- | `@ecopages/core` | Foundational layer of the Ecopages ecosystem. | [JSR](https://jsr.io/@ecopages/core) |
81
- | `@ecopages/file-system` | Runtime-agnostic file system utilities (Bun/Node.js). | [JSR](https://jsr.io/@ecopages/file-system) |
82
- | `@ecopages/image-processor` | Image processing library for optimized responsive images. | [JSR](https://jsr.io/@ecopages/image-processor) |
83
- | `@ecopages/kitajs` | KitaJS plugin for Ecopages integration. | [JSR](https://jsr.io/@ecopages/kitajs) |
84
- | `@ecopages/lit` | Lit plugin for Ecopages integration. | [JSR](https://jsr.io/@ecopages/lit) |
85
- | `@ecopages/mdx` | MDX plugin for Ecopages integration. | [JSR](https://jsr.io/@ecopages/mdx) |
86
- | `@ecopages/postcss-processor` | Utility functions for processing CSS with PostCSS. | [JSR](https://jsr.io/@ecopages/postcss-processor) |
87
- | `@ecopages/react` | React plugin for Ecopages integration. | [JSR](https://jsr.io/@ecopages/react) |
88
- | `@ecopages/react-router` | Client-side SPA router for Ecopages React apps. | [JSR](https://jsr.io/@ecopages/react-router) |
74
+ | Package | Description | JSR Link |
75
+ | :------------------------- | :-------------------------------------------------------- | :--------------------------------------------- |
76
+ | `@ecopages/browser-router` | Client-side navigation and view transitions for Ecopages. | [JSR](https://jsr.io/@ecopages/browser-router) |
77
+
78
+ | `@ecopages/core` | Foundational layer of the Ecopages ecosystem. | [JSR](https://jsr.io/@ecopages/core) |
79
+ | `@ecopages/file-system` | Runtime-agnostic file system utilities (Bun/Node.js). | [JSR](https://jsr.io/@ecopages/file-system) |
80
+ | `@ecopages/image-processor` | Image processing library for optimized responsive images. | [JSR](https://jsr.io/@ecopages/image-processor) |
81
+ | `@ecopages/kitajs` | KitaJS plugin for Ecopages integration. | [JSR](https://jsr.io/@ecopages/kitajs) |
82
+ | `@ecopages/lit` | Lit plugin for Ecopages integration. | [JSR](https://jsr.io/@ecopages/lit) |
83
+ | `@ecopages/mdx` | MDX plugin for Ecopages integration. | [JSR](https://jsr.io/@ecopages/mdx) |
84
+ | `@ecopages/postcss-processor` | Utility functions for processing CSS with PostCSS. | [JSR](https://jsr.io/@ecopages/postcss-processor) |
85
+ | `@ecopages/react` | React plugin for Ecopages integration. | [JSR](https://jsr.io/@ecopages/react) |
86
+ | `@ecopages/react-router` | Client-side SPA router for Ecopages React apps. | [JSR](https://jsr.io/@ecopages/react-router) |
89
87
 
90
88
  Explore all packages at [jsr.io/@ecopages](https://jsr.io/@ecopages).
91
89
 
package/bin/cli.js CHANGED
@@ -1,8 +1,9 @@
1
- #!/usr/bin/env bun
1
+ #!/usr/bin/env node
2
2
 
3
3
  import { Command } from 'commander';
4
- import { existsSync, readFileSync } from 'node:fs';
4
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
5
5
  import { spawn } from 'node:child_process';
6
+ import { join } from 'node:path';
6
7
  import tiged from 'tiged';
7
8
  import { Logger } from '@ecopages/logger';
8
9
 
@@ -13,36 +14,47 @@ const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url),
13
14
 
14
15
  program.name('ecopages').description('Ecopages CLI utilities').version(pkg.version);
15
16
 
16
- program
17
- .command('init <dir>')
18
- .description('Initialize a new project from a template')
19
- .option('--template <name>', 'Template name from ecopages/examples/', 'starter-jsx')
20
- .option('--repo <repo>', 'GitHub repo (user/repo)', 'ecopages/ecopages')
21
- .action(async (dir, opts) => {
22
- const { template, repo } = opts;
23
- const targetDir = dir;
17
+ async function handleInit(dir, opts) {
18
+ const { template, repo } = opts;
19
+ const targetDir = dir;
24
20
 
25
- if (existsSync(targetDir)) {
26
- logger.error(`Target directory already exists: ${targetDir}`);
27
- process.exit(1);
28
- }
21
+ if (existsSync(targetDir)) {
22
+ logger.error(`Target directory already exists: ${targetDir}`);
23
+ process.exit(1);
24
+ }
29
25
 
30
- logger.info(`Creating target directory '${targetDir}'...`);
26
+ logger.info(`Creating target directory '${targetDir}'...`);
31
27
 
32
- try {
33
- const emitter = tiged(`${repo}/examples/${template}`, {
34
- disableCache: true,
35
- force: true,
36
- verbose: false,
37
- });
28
+ try {
29
+ const emitter = tiged(`${repo}/examples/${template}`, {
30
+ disableCache: true,
31
+ force: true,
32
+ verbose: false,
33
+ });
38
34
 
39
- await emitter.clone(targetDir);
40
- logger.info('Project initialized! Run `bun install && bun dev` to start.');
41
- } catch (err) {
42
- logger.error(`Failed to fetch template: ${err.message}`);
43
- process.exit(1);
35
+ await emitter.clone(targetDir);
36
+
37
+ const pkgPath = join(targetDir, 'package.json');
38
+ if (existsSync(pkgPath)) {
39
+ const projectPkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
40
+ projectPkg.name = dir;
41
+ writeFileSync(pkgPath, JSON.stringify(projectPkg, null, 2) + '\n');
42
+ logger.info(`Renamed project to '${dir}'`);
44
43
  }
45
- });
44
+
45
+ logger.info('Project initialized! Run `bun install && bun dev` to start.');
46
+ } catch (err) {
47
+ logger.error(`Failed to fetch template: ${err.message}`);
48
+ process.exit(1);
49
+ }
50
+ }
51
+
52
+ program
53
+ .command('init <dir>')
54
+ .description('Initialize a new project from a template')
55
+ .option('--template <name>', 'Template name from ecopages/examples/', 'starter-jsx')
56
+ .option('--repo <repo>', 'GitHub repo (user/repo)', 'ecopages/ecopages')
57
+ .action(handleInit);
46
58
 
47
59
  /**
48
60
  * Build environment variables from CLI options
@@ -57,21 +69,36 @@ function buildEnvOverrides(options) {
57
69
  return env;
58
70
  }
59
71
 
60
- /**
61
- * Execute a bun command with the given arguments and options.
62
- * Automatically detects eco.config.ts and applies preloads.
63
- * @param {string[]} args - Arguments to pass to the entry file
64
- * @param {object} options - CLI options (watch, hot, port, hostname, etc.)
65
- * @param {string} entryFile - Entry file to run
66
- */
67
- function runBunCommand(args, options = {}, entryFile = 'app.ts') {
68
- const hasConfig = existsSync('eco.config.ts');
69
- if (!existsSync(entryFile)) {
70
- logger.error(`Error: Entry file "${entryFile}" not found in the current directory.`);
71
- process.exit(1);
72
+ function detectRuntime(options = {}) {
73
+ if (options.runtime === 'bun' || options.runtime === 'node') {
74
+ return options.runtime;
75
+ }
76
+
77
+ const userAgent = process.env.npm_config_user_agent || '';
78
+
79
+ /**
80
+ * If explicitly launched via bun (e.g., `bun run ...`)
81
+ */
82
+ if (userAgent.startsWith('bun/')) {
83
+ return 'bun';
84
+ }
85
+
86
+ /**
87
+ * Catch when CLI is run directly by Bun without a package manager command
88
+ */
89
+ if (typeof Bun !== 'undefined') {
90
+ return 'bun';
72
91
  }
73
92
 
93
+ /**
94
+ * Default to node for npm, pnpm, yarn, or direct execution
95
+ */
96
+ return 'node';
97
+ }
98
+
99
+ function buildBunArgs(args, options, entryFile, hasConfig) {
74
100
  const bunArgs = [];
101
+
75
102
  if (options.watch) bunArgs.push('--watch');
76
103
  if (options.hot) bunArgs.push('--hot');
77
104
 
@@ -80,27 +107,105 @@ function runBunCommand(args, options = {}, entryFile = 'app.ts') {
80
107
  if (hasConfig) {
81
108
  bunArgs.push('--preload', 'eco.config.ts');
82
109
  }
110
+
83
111
  bunArgs.push(entryFile, ...args);
84
112
 
85
113
  if (options.reactFastRefresh) {
86
114
  bunArgs.push('--react-fast-refresh');
87
115
  }
88
116
 
89
- /** Merge CLI overrides with current environment */
117
+ return bunArgs;
118
+ }
119
+
120
+ function buildNodeArgs(args, options, entryFile) {
121
+ const tsxArgs = [];
122
+
123
+ if (options.watch) tsxArgs.push('watch');
124
+
125
+ tsxArgs.push(entryFile, ...args);
126
+
127
+ if (options.reactFastRefresh) {
128
+ tsxArgs.push('--react-fast-refresh');
129
+ }
130
+
131
+ return tsxArgs;
132
+ }
133
+
134
+ function createLaunchPlan(args, options = {}, entryFile = 'app.ts') {
135
+ const hasConfig = existsSync('eco.config.ts');
90
136
  const envOverrides = buildEnvOverrides(options);
91
- const env = { ...process.env, ...envOverrides };
137
+ const runtime = detectRuntime(options);
138
+
139
+ if (runtime === 'node') {
140
+ return {
141
+ runtime,
142
+ executionStrategy: 'tsx',
143
+ command: 'tsx',
144
+ commandArgs: buildNodeArgs(args, options, entryFile),
145
+ envOverrides,
146
+ env: { ...process.env, ...envOverrides },
147
+ };
148
+ }
149
+
150
+ return {
151
+ runtime,
152
+ executionStrategy: 'direct-runtime',
153
+ command: 'bun',
154
+ commandArgs: buildBunArgs(args, options, entryFile, hasConfig),
155
+ envOverrides,
156
+ env: { ...process.env, ...envOverrides },
157
+ };
158
+ }
92
159
 
93
- if (Object.keys(envOverrides).length > 0) {
94
- logger.info(`Environment overrides: ${JSON.stringify(envOverrides)}`);
160
+ function runLaunchPlan(launchPlan) {
161
+ if (Object.keys(launchPlan.envOverrides).length > 0) {
162
+ logger.info(`Environment overrides: ${JSON.stringify(launchPlan.envOverrides)}`);
95
163
  }
96
- logger.info(`Running: bun ${bunArgs.join(' ')}`);
97
164
 
98
- const child = spawn('bun', bunArgs, { stdio: 'inherit', env });
165
+ logger.info(`Runtime: ${launchPlan.runtime}`);
166
+ logger.info(`Running: ${launchPlan.command} ${launchPlan.commandArgs.join(' ')}`);
167
+
168
+ const child = spawn(launchPlan.command, launchPlan.commandArgs, {
169
+ stdio: 'inherit',
170
+ env: launchPlan.env,
171
+ });
172
+
173
+ child.on('error', (error) => {
174
+ if (error && error.code === 'ENOENT') {
175
+ const hint =
176
+ launchPlan.command === 'bun'
177
+ ? 'Install Bun from https://bun.sh to continue.'
178
+ : 'Install tsx (`npm i -g tsx` or add it as a devDependency) to continue.';
179
+ logger.error(`Command not found: ${launchPlan.command}. ${hint}`);
180
+ process.exit(1);
181
+ }
182
+
183
+ logger.error(`Failed to run command: ${error.message}`);
184
+ process.exit(1);
185
+ });
186
+
99
187
  child.on('exit', (code) => {
100
188
  process.exit(code || 0);
101
189
  });
102
190
  }
103
191
 
192
+ /**
193
+ * Execute a bun command with the given arguments and options.
194
+ * Automatically detects eco.config.ts and applies preloads.
195
+ * @param {string[]} args - Arguments to pass to the entry file
196
+ * @param {object} options - CLI options (watch, hot, port, hostname, etc.)
197
+ * @param {string} entryFile - Entry file to run
198
+ */
199
+ function runBunCommand(args, options = {}, entryFile = 'app.ts') {
200
+ if (!existsSync(entryFile)) {
201
+ logger.error(`Error: Entry file "${entryFile}" not found in the current directory.`);
202
+ process.exit(1);
203
+ }
204
+
205
+ const launchPlan = createLaunchPlan(args, options, entryFile);
206
+ runLaunchPlan(launchPlan);
207
+ }
208
+
104
209
  /**
105
210
  * Add shared server options to a command.
106
211
  * @param {import('commander').Command} cmd - The command to add options to
@@ -112,7 +217,8 @@ const serverOptions = (cmd) =>
112
217
  .option('-n, --hostname <hostname>', 'Override ECOPAGES_HOSTNAME')
113
218
  .option('-b, --base-url <url>', 'Override ECOPAGES_BASE_URL')
114
219
  .option('-d, --debug', 'Enable debug logging (ECOPAGES_LOGGER_DEBUG=true)')
115
- .option('-r, --react-fast-refresh', 'Enable React Fast Refresh for HMR');
220
+ .option('-r, --react-fast-refresh', 'Enable React Fast Refresh for HMR')
221
+ .option('--runtime <runtime>', 'Force a specific runtime (bun or node)');
116
222
 
117
223
  serverOptions(
118
224
  program.command('dev').description('Start the development server').argument('[entry]', 'Entry file', 'app.ts'),
@@ -142,8 +248,9 @@ program
142
248
  .command('build')
143
249
  .description('Build the project for production')
144
250
  .argument('[entry]', 'Entry file', 'app.ts')
145
- .action((entry) => {
146
- runBunCommand(['--build'], { nodeEnv: 'production' }, entry);
251
+ .option('--runtime <runtime>', 'Force a specific runtime (bun or node)')
252
+ .action((entry, opts) => {
253
+ runBunCommand(['--build'], { nodeEnv: 'production', ...opts }, entry);
147
254
  });
148
255
 
149
256
  serverOptions(
package/package.json CHANGED
@@ -1,45 +1,45 @@
1
1
  {
2
- "name": "ecopages",
3
- "version": "0.1.105",
4
- "description": "CLI utilities for Ecopages",
5
- "type": "module",
6
- "license": "MIT",
7
- "author": "Ecopages Team",
8
- "repository": {
9
- "type": "git",
10
- "url": "git+https://github.com/ecopages/ecopages.git",
11
- "directory": "npm/ecopages"
12
- },
13
- "homepage": "https://github.com/ecopages/ecopages#readme",
14
- "bugs": {
15
- "url": "https://github.com/ecopages/ecopages/issues"
16
- },
17
- "keywords": [
18
- "ecopages",
19
- "bun",
20
- "web-framework",
21
- "ssr",
22
- "static-site-generator",
23
- "react",
24
- "kitajs",
25
- "lit",
26
- "mdx"
27
- ],
28
- "bin": {
29
- "ecopages": "bin/cli.js"
30
- },
31
- "files": [
32
- "bin/",
33
- "css/",
34
- "README.md"
35
- ],
36
- "dependencies": {
37
- "commander": "^12.1.0",
38
- "tiged": "^2.12.7",
39
- "@ecopages/logger": "^0.2.2"
40
- },
41
- "peerDependencies": {
42
- "bun-types": "latest",
43
- "typescript": "^5"
44
- }
2
+ "name": "ecopages",
3
+ "version": "0.2.0-alpha.2",
4
+ "description": "CLI utilities for Ecopages",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "Ecopages Team",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/ecopages/ecopages.git",
11
+ "directory": "packages/ecopages"
12
+ },
13
+ "homepage": "https://github.com/ecopages/ecopages#readme",
14
+ "bugs": {
15
+ "url": "https://github.com/ecopages/ecopages/issues"
16
+ },
17
+ "keywords": [
18
+ "ecopages",
19
+ "bun",
20
+ "web-framework",
21
+ "ssr",
22
+ "static-site-generator",
23
+ "react",
24
+ "kitajs",
25
+ "lit",
26
+ "mdx"
27
+ ],
28
+ "bin": {
29
+ "ecopages": "bin/cli.js"
30
+ },
31
+ "files": [
32
+ "bin/",
33
+ "css/",
34
+ "README.md"
35
+ ],
36
+ "dependencies": {
37
+ "commander": "^12.1.0",
38
+ "tiged": "^2.12.7",
39
+ "@ecopages/logger": "^0.2.2"
40
+ },
41
+ "peerDependencies": {
42
+ "bun-types": "*",
43
+ "typescript": "^5"
44
+ }
45
45
  }