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.
- package/README.md +13 -15
- package/bin/cli.js +155 -48
- 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
|
|
75
|
-
|
|
|
76
|
-
| `@ecopages/browser-router`
|
|
77
|
-
|
|
78
|
-
| `@ecopages/
|
|
79
|
-
| `@ecopages/
|
|
80
|
-
| `@ecopages/
|
|
81
|
-
| `@ecopages/
|
|
82
|
-
| `@ecopages/
|
|
83
|
-
| `@ecopages/
|
|
84
|
-
| `@ecopages/
|
|
85
|
-
| `@ecopages/
|
|
86
|
-
| `@ecopages/
|
|
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
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
21
|
+
if (existsSync(targetDir)) {
|
|
22
|
+
logger.error(`Target directory already exists: ${targetDir}`);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
29
25
|
|
|
30
|
-
|
|
26
|
+
logger.info(`Creating target directory '${targetDir}'...`);
|
|
31
27
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
28
|
+
try {
|
|
29
|
+
const emitter = tiged(`${repo}/examples/${template}`, {
|
|
30
|
+
disableCache: true,
|
|
31
|
+
force: true,
|
|
32
|
+
verbose: false,
|
|
33
|
+
});
|
|
38
34
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
94
|
-
|
|
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
|
-
|
|
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
|
-
.
|
|
146
|
-
|
|
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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
}
|