vaderjs 2.2.6 → 2.3.0
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 +61 -39
- package/cli.ts +186 -0
- package/index.ts +839 -688
- package/jsconfig.json +2 -2
- package/main.js +414 -600
- package/package.json +1 -1
- package/plugins/index.ts +63 -0
- package/plugins/tailwind.ts +2 -0
- package/README.md +0 -89
- package/bun.lockb +0 -0
- package/bundler/index.js +0 -295
- package/document/index.ts +0 -77
- package/examples/counter/index.jsx +0 -10
package/main.js
CHANGED
|
@@ -1,642 +1,456 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
2
|
+
/**
|
|
3
|
+
* VaderJS Build & Development Script
|
|
4
|
+
*
|
|
5
|
+
* This script handles building the VaderJS framework, your application code,
|
|
6
|
+
* and serving it in a local development environment with live reloading.
|
|
7
|
+
*
|
|
8
|
+
* Commands:
|
|
9
|
+
* bun run vaderjs build - Builds the project for production.
|
|
10
|
+
* bun run vaderjs dev - Starts the dev server with HMR and file watching.
|
|
11
|
+
* bun run vaderjs serve - Builds and serves the production output.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { build, serve } from "bun";
|
|
15
|
+
import fs from "fs/promises";
|
|
16
|
+
import fsSync from "fs";
|
|
17
|
+
import path from "path";
|
|
18
|
+
import { init } from "./cli";
|
|
19
|
+
|
|
20
|
+
// --- UTILITIES for a Sleek CLI ---
|
|
21
|
+
|
|
22
|
+
const colors = {
|
|
23
|
+
reset: "\x1b[0m",
|
|
24
|
+
red: "\x1b[31m",
|
|
25
|
+
green: "\x1b[32m",
|
|
26
|
+
yellow: "\x1b[33m",
|
|
27
|
+
blue: "\x1b[34m",
|
|
28
|
+
magenta: "\x1b[35m",
|
|
29
|
+
cyan: "\x1b[36m",
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const logger = {
|
|
33
|
+
_log: (color, ...args) => console.log(color, ...args, colors.reset),
|
|
34
|
+
info: (...args) => logger._log(colors.cyan, "ℹ", ...args),
|
|
35
|
+
success: (...args) => logger._log(colors.green, "✅", ...args),
|
|
36
|
+
warn: (...args) => logger._log(colors.yellow, "⚠️", ...args),
|
|
37
|
+
error: (...args) => logger._log(colors.red, "❌", ...args),
|
|
38
|
+
step: (...args) => logger._log(colors.magenta, "\n🚀", ...args),
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
async function timedStep(name, fn) {
|
|
42
|
+
logger.step(`${name}...`);
|
|
43
|
+
const start = performance.now();
|
|
44
|
+
try {
|
|
45
|
+
await fn();
|
|
46
|
+
const duration = (performance.now() - start).toFixed(2);
|
|
47
|
+
logger.success(`Finished '${name}' in ${duration}ms`);
|
|
48
|
+
} catch (e) {
|
|
49
|
+
logger.error(`Error during '${name}':`, e.message);
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
16
52
|
}
|
|
17
53
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
54
|
+
// --- CONSTANTS ---
|
|
55
|
+
|
|
56
|
+
const PROJECT_ROOT = process.cwd();
|
|
57
|
+
const APP_DIR = path.join(PROJECT_ROOT, "app");
|
|
58
|
+
const PUBLIC_DIR = path.join(PROJECT_ROOT, "public");
|
|
59
|
+
const DIST_DIR = path.join(PROJECT_ROOT, "dist");
|
|
60
|
+
const SRC_DIR = path.join(PROJECT_ROOT, "src");
|
|
61
|
+
const VADER_SRC_PATH = path.join(PROJECT_ROOT, "node_modules", "vaderjs", "index.ts");
|
|
62
|
+
const TEMP_SRC_DIR = path.join(PROJECT_ROOT, ".vader_temp_src");
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
// --- CONFIG & PLUGIN SYSTEM ---
|
|
66
|
+
|
|
67
|
+
let config = {};
|
|
68
|
+
let htmlInjections = [];
|
|
69
|
+
|
|
70
|
+
const vaderAPI = {
|
|
71
|
+
runCommand: async (cmd) => {
|
|
72
|
+
if (typeof cmd === "string") cmd = cmd.split(" ");
|
|
73
|
+
const p = Bun.spawn(cmd);
|
|
74
|
+
await p.exited;
|
|
75
|
+
},
|
|
76
|
+
injectHTML: (content) => htmlInjections.push(content),
|
|
77
|
+
log: (msg) => logger.info(`[Plugin] ${msg}`),
|
|
78
|
+
getProjectRoot: () => PROJECT_ROOT,
|
|
79
|
+
getDistDir: () => DIST_DIR,
|
|
80
|
+
getPublicDir: () => PUBLIC_DIR,
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
async function loadConfig() {
|
|
84
|
+
try {
|
|
85
|
+
const configModule = await import(path.join(PROJECT_ROOT, "vader.config.js"));
|
|
86
|
+
return configModule.default || configModule;
|
|
87
|
+
} catch {
|
|
88
|
+
logger.warn("No 'vader.config.js' found, using defaults.");
|
|
89
|
+
return {};
|
|
90
|
+
}
|
|
30
91
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
export default defineConfig({
|
|
35
|
-
port: 8080,
|
|
36
|
-
host_provider: 'apache'
|
|
37
|
-
})`)
|
|
38
|
-
}
|
|
39
|
-
var config = require(process.cwd() + '/vader.config.ts').default
|
|
40
|
-
const mode = args.includes('dev') ? 'development' : args.includes('prod') || args.includes('build') ? 'production' : args.includes('init') ? 'init' : args.includes('serve') ? 'serve' : null;
|
|
41
|
-
if (!mode) {
|
|
42
|
-
console.log(`
|
|
43
|
-
Usage:
|
|
44
|
-
bun vaderjs serve - Start the server
|
|
45
|
-
bun vaderjs dev - Start development server output in dist/
|
|
46
|
-
bun vaderjs prod - Build for production output in dist/
|
|
47
|
-
bun vaderjs init - Initialize a new vaderjs project
|
|
48
|
-
`)
|
|
49
|
-
process.exit(1)
|
|
92
|
+
|
|
93
|
+
export function defineConfig(config) {
|
|
94
|
+
return config;
|
|
50
95
|
}
|
|
51
96
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
97
|
+
async function runPluginHook(hookName) {
|
|
98
|
+
if (!config.plugins) return;
|
|
99
|
+
for (const plugin of config.plugins) {
|
|
100
|
+
if (typeof plugin[hookName] === "function") {
|
|
101
|
+
try {
|
|
102
|
+
await plugin[hookName](vaderAPI);
|
|
103
|
+
} catch (e) {
|
|
104
|
+
logger.error(`Plugin hook error (${hookName} in ${plugin.name || 'anonymous plugin'}):`, e);
|
|
105
|
+
}
|
|
56
106
|
}
|
|
57
|
-
|
|
58
|
-
await Bun.write(path.join(process.cwd(), "/app/index.jsx"), counterText)
|
|
59
|
-
console.log('Initialized new vaderjs project: run `bun vaderjs dev` to start the development server')
|
|
60
|
-
process.exit(0)
|
|
107
|
+
}
|
|
61
108
|
}
|
|
62
109
|
|
|
63
|
-
console.log(
|
|
64
|
-
`VaderJS - v${require(process.cwd() + '/node_modules/vaderjs/package.json').version} 🚀
|
|
65
|
-
Mode: ${mode}
|
|
66
|
-
SSR: ${require(process.cwd() + '/vader.config.ts').default.ssr ? 'Enabled' : 'Disabled'}
|
|
67
|
-
PORT: ${require(process.cwd() + '/vader.config.ts').default.port || 8080}
|
|
68
|
-
${mode == 'serve' ? `SSL: ${require(process.cwd() + '/vader.config.ts').default?.ssl?.enabled ? 'Enabled' : 'Disabled'} ` : ``}
|
|
69
|
-
`
|
|
70
|
-
)
|
|
71
110
|
|
|
111
|
+
// --- BUILD LOGIC ---
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Step 1: Transpile and bundle the core vaderjs library.
|
|
115
|
+
*/
|
|
116
|
+
async function buildVaderCore() {
|
|
117
|
+
if (!fsSync.existsSync(VADER_SRC_PATH)) {
|
|
118
|
+
logger.error("VaderJS source not found:", VADER_SRC_PATH);
|
|
119
|
+
throw new Error("Missing vaderjs dependency.");
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
await build({
|
|
123
|
+
entrypoints: [VADER_SRC_PATH],
|
|
124
|
+
outdir: path.join(DIST_DIR, "src", "vader"),
|
|
125
|
+
target: "browser",
|
|
126
|
+
minify: false,
|
|
127
|
+
sourcemap: "external",
|
|
128
|
+
jsxFactory: "e",
|
|
129
|
+
jsxFragment: "Fragment",
|
|
130
|
+
jsxImportSource: "vaderjs",
|
|
131
|
+
});
|
|
132
|
+
}
|
|
72
133
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
134
|
+
/**
|
|
135
|
+
* Step 2: Patches source code to remove server-side hook imports.
|
|
136
|
+
*/
|
|
137
|
+
function patchHooksUsage(code) {
|
|
138
|
+
return code.replace(/import\s+{[^}]*use(State|Effect|Memo|Navigation)[^}]*}\s+from\s+['"]vaderjs['"];?\n?/g, "");
|
|
76
139
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Step 3: Pre-processes all files in `/src` into a temporary directory.
|
|
143
|
+
*/
|
|
144
|
+
async function preprocessSources(srcDir, tempDir) {
|
|
145
|
+
await fs.mkdir(tempDir, { recursive: true });
|
|
146
|
+
for (const entry of await fs.readdir(srcDir, { withFileTypes: true })) {
|
|
147
|
+
const srcPath = path.join(srcDir, entry.name);
|
|
148
|
+
const destPath = path.join(tempDir, entry.name);
|
|
149
|
+
|
|
150
|
+
if (entry.isDirectory()) {
|
|
151
|
+
await preprocessSources(srcPath, destPath);
|
|
152
|
+
} else if (/\.(tsx|jsx|ts|js)$/.test(entry.name)) {
|
|
153
|
+
let content = await fs.readFile(srcPath, "utf8");
|
|
154
|
+
content = patchHooksUsage(content);
|
|
155
|
+
await fs.writeFile(destPath, content);
|
|
156
|
+
} else {
|
|
157
|
+
await fs.copyFile(srcPath, destPath);
|
|
84
158
|
}
|
|
85
|
-
|
|
159
|
+
}
|
|
86
160
|
}
|
|
87
161
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
bindes.push(html)
|
|
121
|
-
globalThis.bindes = bindes
|
|
122
|
-
},
|
|
162
|
+
/**
|
|
163
|
+
* Step 4: Build the application's source code from the preprocessed temp directory.
|
|
164
|
+
*/
|
|
165
|
+
async function buildSrc() {
|
|
166
|
+
if (!fsSync.existsSync(SRC_DIR)) return;
|
|
167
|
+
|
|
168
|
+
if (fsSync.existsSync(TEMP_SRC_DIR)) {
|
|
169
|
+
await fs.rm(TEMP_SRC_DIR, { recursive: true, force: true });
|
|
170
|
+
}
|
|
171
|
+
await preprocessSources(SRC_DIR, TEMP_SRC_DIR);
|
|
172
|
+
|
|
173
|
+
const entrypoints = fsSync.readdirSync(TEMP_SRC_DIR, { recursive: true })
|
|
174
|
+
.map(file => path.join(TEMP_SRC_DIR, file))
|
|
175
|
+
.filter(file => /\.(ts|tsx|js|jsx)$/.test(file));
|
|
176
|
+
|
|
177
|
+
if (entrypoints.length === 0) {
|
|
178
|
+
logger.info("No source files found in /src to build.");
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
await build({
|
|
183
|
+
entrypoints,
|
|
184
|
+
outdir: path.join(DIST_DIR, "src"),
|
|
185
|
+
root: TEMP_SRC_DIR,
|
|
186
|
+
naming: { entry: "[dir]/[name].js" },
|
|
187
|
+
jsxFactory: "e",
|
|
188
|
+
jsxFragment: "Fragment",
|
|
189
|
+
jsxImportSource: "vaderjs",
|
|
190
|
+
target: "browser",
|
|
191
|
+
minify: false,
|
|
192
|
+
external: ["vaderjs"],
|
|
193
|
+
});
|
|
123
194
|
}
|
|
124
|
-
const handleReplacements = (code) => {
|
|
125
|
-
let lines = code.split('\n')
|
|
126
|
-
let newLines = []
|
|
127
|
-
for (let line of lines) {
|
|
128
|
-
let hasImport = line.includes('import')
|
|
129
|
-
|
|
130
|
-
if (hasImport && line.includes('public')) {
|
|
131
|
-
// remove ../ from path
|
|
132
195
|
|
|
133
|
-
|
|
196
|
+
/**
|
|
197
|
+
* Step 5: Copy all assets from the `/public` directory to `/dist`.
|
|
198
|
+
*/
|
|
199
|
+
async function copyPublicAssets() {
|
|
200
|
+
if (!fsSync.existsSync(PUBLIC_DIR)) return;
|
|
201
|
+
// Copy contents of public into dist, not the public folder itself
|
|
202
|
+
for (const item of await fs.readdir(PUBLIC_DIR)) {
|
|
203
|
+
await fs.cp(path.join(PUBLIC_DIR, item), path.join(DIST_DIR, item), { recursive: true });
|
|
204
|
+
}
|
|
205
|
+
}
|
|
134
206
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
207
|
+
|
|
208
|
+
async function buildAppEntrypoints(isDev = false) {
|
|
209
|
+
if (!fsSync.existsSync(APP_DIR)) {
|
|
210
|
+
logger.warn("No '/app' directory found, skipping app entrypoint build.");
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Ensure the dist directory exists
|
|
215
|
+
if (!fsSync.existsSync(DIST_DIR)) {
|
|
216
|
+
await fs.mkdir(DIST_DIR, { recursive: true });
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const devClientScript = isDev ? `
|
|
220
|
+
<script>
|
|
221
|
+
new WebSocket("ws://" + location.host + "/__hmr").onmessage = (msg) => {
|
|
222
|
+
if (msg.data === "reload") location.reload();
|
|
223
|
+
};
|
|
224
|
+
</script>` : "";
|
|
225
|
+
|
|
226
|
+
const entries = fsSync.readdirSync(APP_DIR, { recursive: true })
|
|
227
|
+
.filter(file => /index\.(jsx|tsx)$/.test(file))
|
|
228
|
+
.map(file => ({
|
|
229
|
+
name: path.dirname(file) === '.' ? 'index' : path.dirname(file).replace(/\\/g, '/'),
|
|
230
|
+
path: path.join(APP_DIR, file)
|
|
231
|
+
}));
|
|
232
|
+
|
|
233
|
+
for (const { name, path: entryPath } of entries) {
|
|
234
|
+
// Ensure correct path handling for subdirectories
|
|
235
|
+
const outDir = path.join(DIST_DIR, name === 'index' ? '' : name);
|
|
236
|
+
const outJsPath = path.join(outDir, `index.js`); // Output JavaScript file path
|
|
237
|
+
|
|
238
|
+
// Ensure the output directory exists
|
|
239
|
+
await fs.mkdir(outDir, { recursive: true });
|
|
240
|
+
|
|
241
|
+
// **FIXED CSS HANDLING**: Find, copy, and correctly link CSS files
|
|
242
|
+
const cssLinks = [];
|
|
243
|
+
const cssContent = await fs.readFile(entryPath, "utf8");
|
|
244
|
+
const cssImports = [...cssContent.matchAll(/import\s+['"](.*\.css)['"]/g)];
|
|
245
|
+
|
|
246
|
+
for (const match of cssImports) {
|
|
247
|
+
const cssImportPath = match[1]; // e.g., './styles.css'
|
|
248
|
+
const sourceCssPath = path.resolve(path.dirname(entryPath), cssImportPath);
|
|
249
|
+
if (fsSync.existsSync(sourceCssPath)) {
|
|
250
|
+
const relativeCssPath = path.relative(APP_DIR, sourceCssPath);
|
|
251
|
+
const destCssPath = path.join(DIST_DIR, relativeCssPath);
|
|
252
|
+
|
|
253
|
+
await fs.mkdir(path.dirname(destCssPath), { recursive: true });
|
|
254
|
+
await fs.copyFile(sourceCssPath, destCssPath);
|
|
255
|
+
|
|
256
|
+
const htmlRelativePath = path.relative(outDir, destCssPath).replace(/\\/g, '/');
|
|
257
|
+
cssLinks.push(`<link rel="stylesheet" href="${htmlRelativePath}">`);
|
|
258
|
+
} else {
|
|
259
|
+
logger.warn(`CSS file not found: ${sourceCssPath}`);
|
|
172
260
|
}
|
|
173
|
-
if (!hasImport && line.includes('useAsyncState')) {
|
|
174
|
-
let key = line.split(',')[0].split('[')[1].replace(' ', '')
|
|
175
|
-
let b4 = line
|
|
176
|
-
b4 = line.replace('useAsyncState(', `this.useAsyncState('${key}',`)
|
|
177
|
-
line = b4
|
|
178
|
-
}
|
|
179
|
-
if (!hasImport && line.includes('useEffect')) {
|
|
180
|
-
let b4 = line
|
|
181
|
-
b4 = line.replace('useEffect(', `this.useEffect(`)
|
|
182
|
-
line = b4
|
|
183
|
-
}
|
|
184
|
-
if (!hasImport && line.includes('useRef')) {
|
|
185
|
-
line = line.replace(' ', '')
|
|
186
|
-
let b4 = line
|
|
187
|
-
let key = line.split('=')[0].split(' ').filter(Boolean)[1]
|
|
188
|
-
b4 = line.replace('useRef(', `this.useRef('${key}',`)
|
|
189
|
-
line = b4
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
newLines.push(line)
|
|
193
261
|
}
|
|
194
|
-
let c = newLines.join('\n')
|
|
195
|
-
return c
|
|
196
|
-
}
|
|
197
262
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
263
|
+
// Update the script tag to use relative paths for index.js
|
|
264
|
+
const htmlContent = `<!DOCTYPE html>
|
|
265
|
+
<html lang="en">
|
|
266
|
+
<head>
|
|
267
|
+
<meta charset="UTF-8" />
|
|
268
|
+
<title>VaderJS App - ${name}</title>
|
|
269
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
270
|
+
${cssLinks.join("\n ")}
|
|
271
|
+
${htmlInjections.join("\n ")}
|
|
272
|
+
</head>
|
|
273
|
+
<body>
|
|
274
|
+
<div id="app"></div>
|
|
275
|
+
<script type="module">
|
|
276
|
+
import App from '/${name}/index.js';
|
|
277
|
+
import * as Vader from '/src/vader/index.js';
|
|
278
|
+
Vader.render(Vader.createElement(App, null), document.getElementById("app"));
|
|
279
|
+
</script>
|
|
280
|
+
${devClientScript}
|
|
281
|
+
</body>
|
|
282
|
+
</html>`;
|
|
283
|
+
|
|
284
|
+
await fs.writeFile(path.join(outDir, "index.html"), htmlContent);
|
|
285
|
+
|
|
286
|
+
// Log for debugging
|
|
287
|
+
|
|
288
|
+
// Build the JavaScript file and ensure it uses the correct paths
|
|
289
|
+
await build({
|
|
290
|
+
entrypoints: [entryPath],
|
|
291
|
+
outdir: outDir, // Pass the directory path to outdir
|
|
292
|
+
target: "browser",
|
|
293
|
+
minify: false,
|
|
294
|
+
sourcemap: "external",
|
|
295
|
+
external: ["vaderjs"],
|
|
296
|
+
jsxFactory: "e",
|
|
297
|
+
jsxFragment: "Fragment",
|
|
298
|
+
jsxImportSource: "vaderjs",
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
// After build, replace the 'vaderjs' import to the correct path
|
|
302
|
+
let jsContent = await fs.readFile(outJsPath, "utf8");
|
|
303
|
+
jsContent = jsContent.replace(/from\s+['"]vaderjs['"]/g, `from '/src/vader/index.js'`);
|
|
304
|
+
await fs.writeFile(outJsPath, jsContent);
|
|
305
|
+
}
|
|
201
306
|
}
|
|
202
|
-
let start = Date.now()
|
|
203
|
-
async function generateApp() {
|
|
204
|
-
globalThis.isBuilding = true;
|
|
205
|
-
console.log(ansiColors.green('Building...'))
|
|
206
|
-
if (mode === 'development') {
|
|
207
307
|
|
|
208
|
-
|
|
209
|
-
fs.mkdirSync(process.cwd() + '/dist', { recursive: true })
|
|
210
|
-
}
|
|
211
|
-
try {
|
|
212
|
-
let plugins = config.plugins || []
|
|
213
|
-
for (let plugin of plugins) {
|
|
214
|
-
if (plugin.onBuildStart) {
|
|
215
|
-
await plugin.onBuildStart(vader)
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
} catch (error) {
|
|
219
|
-
console.log(error)
|
|
220
|
-
}
|
|
308
|
+
|
|
221
309
|
|
|
310
|
+
async function buildAll(isDev = false) {
|
|
311
|
+
logger.info(`Starting VaderJS ${isDev ? 'development' : 'production'} build...`);
|
|
312
|
+
const totalTime = performance.now();
|
|
222
313
|
|
|
223
|
-
|
|
224
|
-
let routes = new Bun.FileSystemRouter({
|
|
225
|
-
dir: path.join(process.cwd(), '/app'),
|
|
226
|
-
style: 'nextjs'
|
|
227
|
-
})
|
|
228
|
-
routes.reload()
|
|
229
|
-
globalThis.routes = routes.routes
|
|
230
|
-
Object.keys(routes.routes).forEach(async (route) => {
|
|
231
|
-
|
|
232
|
-
let r = routes.routes[route]
|
|
233
|
-
let code = await Bun.file(r).text()
|
|
234
|
-
code = handleReplacements(code)
|
|
235
|
-
let size = code.length / 1024
|
|
236
|
-
r = r.replace(process.cwd().replace(/\\/g, '/') + '/app', '')
|
|
237
|
-
r = r.replace('.jsx', '.js').replace('.tsx', '.js')
|
|
238
|
-
fs.mkdirSync(path.join(process.cwd() + '/dist', path.dirname(r)), { recursive: true })
|
|
239
|
-
let params = routes.match(route).params || {}
|
|
240
|
-
let base = routes.match(route)
|
|
241
|
-
let paramIndexes = []
|
|
242
|
-
for (let param in params) {
|
|
243
|
-
let routes = base.pathname.split('/')
|
|
244
|
-
let index = routes.indexOf('[' + param + ']')
|
|
245
|
-
paramIndexes.push(index)
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
// dont return
|
|
249
|
-
code = await new Bun.Transpiler({
|
|
250
|
-
loader: 'tsx',
|
|
251
|
-
tsconfig: {
|
|
252
|
-
"compilerOptions": {
|
|
253
|
-
"jsx": "react",
|
|
254
|
-
"jsxFactory": "e",
|
|
255
|
-
"jsxFragmentFactory": "Fragment"
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
}).transformSync(code)
|
|
259
|
-
|
|
260
|
-
fs.writeFileSync(
|
|
261
|
-
process.cwd() + '/dist/' + path.dirname(r) + '/' + path.basename(r),
|
|
262
|
-
`
|
|
263
|
-
let route = window.location.pathname.split('/').filter(Boolean)
|
|
264
|
-
let params = {
|
|
265
|
-
// get index tehn do route[index]
|
|
266
|
-
${Object.keys(params).map((param, i) => {
|
|
267
|
-
if (paramIndexes[i] !== -1) {
|
|
268
|
-
var r_copy = r;
|
|
269
|
-
r_copy = r_copy.split('/').filter(Boolean)
|
|
270
|
-
var index = paramIndexes[i] - 1
|
|
271
|
-
return `${param}: route[${index}]`
|
|
272
|
-
}
|
|
273
|
-
}).join(',\n')}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
\n${code}
|
|
277
|
-
`
|
|
278
|
-
);
|
|
279
|
-
fs.mkdirSync(process.cwd() + '/dev', { recursive: true })
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
if (!fs.existsSync(process.cwd() + '/dev/readme.md')) {
|
|
283
|
-
fs.writeFileSync(process.cwd() + '/dev/readme.md', `# Please do not edit the bundler.js file in the dev directory. This file is automatically generated by the bundler. \n\n`)
|
|
284
|
-
}
|
|
285
|
-
async function runT() {
|
|
286
|
-
return await new Bun.Transpiler({
|
|
287
|
-
loader: 'tsx',
|
|
288
|
-
}).transformSync(await Bun.file(require.resolve('vaderjs')).text())
|
|
289
|
-
}
|
|
290
|
-
if (!fs.existsSync(path.join(process.cwd(), '/dist/src/vader'))
|
|
291
|
-
|| fs.readFileSync(path.join(process.cwd(), '/dist/src/vader/index.js')) != await runT()
|
|
292
|
-
) {
|
|
293
|
-
fs.mkdirSync(process.cwd() + '/dist/src/vader', { recursive: true })
|
|
294
|
-
fs.writeFileSync(path.join(process.cwd(), '/dist/src/vader/index.js'), (await runT()))
|
|
295
|
-
|
|
296
|
-
}
|
|
297
|
-
await Bun.spawn({
|
|
298
|
-
cmd: [bunPath, 'run', './dev/bundler.js'],
|
|
299
|
-
cwd: process.cwd(),
|
|
300
|
-
stdout: 'inherit',
|
|
301
|
-
env: {
|
|
302
|
-
ENTRYPOINT: path.join(process.cwd(), 'dist', path.dirname(r), path.basename(r)),
|
|
303
|
-
ROOT: path.join(process.cwd(), 'app/'),
|
|
304
|
-
OUT: path.dirname(r),
|
|
305
|
-
file: path.join(process.cwd(), 'dist', path.dirname(r), path.basename(r)),
|
|
306
|
-
DEV: mode === 'development',
|
|
307
|
-
size,
|
|
308
|
-
bindes: bindes.join('\n'),
|
|
309
|
-
filePath: r,
|
|
310
|
-
isAppFile: true,
|
|
311
|
-
isJsx: true,
|
|
312
|
-
INPUT: `../app/${r.replace('.js', '.jsx').replace('.tsx', '.js')}`,
|
|
313
|
-
},
|
|
314
|
-
onExit({ exitCode: code }) {
|
|
315
|
-
if (code === 0) {
|
|
316
|
-
bindes = [];
|
|
317
|
-
resolve();
|
|
318
|
-
} else {
|
|
319
|
-
reject();
|
|
320
|
-
}
|
|
321
|
-
},
|
|
322
|
-
});
|
|
323
|
-
})
|
|
324
|
-
|
|
325
|
-
switch (host_provider) {
|
|
326
|
-
case 'vercel':
|
|
327
|
-
|
|
328
|
-
let vercelData = {
|
|
329
|
-
rewrites: []
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
for (let route in routes.routes) {
|
|
333
|
-
let { filePath, kind, name, params, pathname, query } = routes.match(route)
|
|
334
|
-
let r = route
|
|
335
|
-
|
|
336
|
-
if (r.includes('[')) {
|
|
337
|
-
r = r.replaceAll('[', ':').replaceAll(']', '')
|
|
338
|
-
}
|
|
339
|
-
if (r === '/') {
|
|
340
|
-
continue
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
vercelData.rewrites.push({
|
|
344
|
-
source: r,
|
|
345
|
-
destination: `${path.dirname(routes.routes[route]).replace(process.cwd().replace(/\\/g, '/') + '/app', '')}/index.html`
|
|
346
|
-
})
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
fs.writeFileSync(process.cwd() + '/vercel.json', JSON.stringify(vercelData, null, 4))
|
|
350
|
-
break;
|
|
351
|
-
case 'apache':
|
|
352
|
-
let data = ''
|
|
314
|
+
htmlInjections = [];
|
|
353
315
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
for (let plugin of plugins) {
|
|
359
|
-
if (plugin.onBuildFinish) {
|
|
360
|
-
await plugin.onBuildFinish(vader)
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
} catch (error) {
|
|
364
|
-
console.error(ansiColors.red(error))
|
|
365
|
-
}
|
|
316
|
+
// Ensure dist directory exists before cleaning
|
|
317
|
+
if (fsSync.existsSync(DIST_DIR)) {
|
|
318
|
+
await fs.rm(DIST_DIR, { recursive: true, force: true });
|
|
319
|
+
}
|
|
366
320
|
|
|
367
|
-
|
|
321
|
+
// Create the dist directory if it doesn't exist
|
|
322
|
+
await fs.mkdir(DIST_DIR, { recursive: true });
|
|
368
323
|
|
|
324
|
+
await runPluginHook("onBuildStart");
|
|
369
325
|
|
|
370
|
-
|
|
326
|
+
// Build the components in steps and handle errors properly
|
|
327
|
+
await timedStep("Building VaderJS Core", buildVaderCore);
|
|
328
|
+
await timedStep("Building App Source (/src)", buildSrc);
|
|
329
|
+
await timedStep("Copying Public Assets", copyPublicAssets);
|
|
330
|
+
await timedStep("Building App Entrypoints (/app)", () => buildAppEntrypoints(isDev));
|
|
371
331
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
let file = i
|
|
378
|
-
fs.mkdirSync(path.join(process.cwd() + '/dist', path.dirname(file)), { recursive: true })
|
|
379
|
-
if (fs.existsSync(path.join(process.cwd() + '/dist', file))) {
|
|
380
|
-
fs.rmSync(path.join(process.cwd() + '/dist', file))
|
|
381
|
-
}
|
|
382
|
-
fs.copyFileSync(file, path.join(process.cwd() + '/dist', file))
|
|
383
|
-
}
|
|
384
|
-
let glob2 = new Glob('src/**/*')
|
|
385
|
-
for await (var i of glob2.scan()) {
|
|
386
|
-
var file = i
|
|
387
|
-
fs.mkdirSync(path.join(process.cwd() + '/dist', path.dirname(file)), { recursive: true })
|
|
388
|
-
// turn jsx to js
|
|
389
|
-
if (file.includes('.jsx') || file.includes('.tsx')) {
|
|
390
|
-
let code = await Bun.file(file).text()
|
|
391
|
-
|
|
392
|
-
code = handleReplacements(code)
|
|
393
|
-
code = await new Bun.Transpiler({
|
|
394
|
-
loader: 'tsx',
|
|
395
|
-
}).transformSync(code)
|
|
396
|
-
|
|
397
|
-
file = file.replace('.jsx', '.js').replace('.tsx', '.js')
|
|
398
|
-
fs.writeFileSync(path.join(process.cwd() + '/dist', file.replace('.jsx', '.js').replace('.tsx', '.js')), code)
|
|
399
|
-
await Bun.spawn({
|
|
400
|
-
cmd: [bunPath, 'run', './dev/bundler.js'],
|
|
401
|
-
cwd: process.cwd(),
|
|
402
|
-
stdout: 'inherit',
|
|
403
|
-
env: {
|
|
404
|
-
ENTRYPOINT: path.join(process.cwd() + '/dist/' + file.replace('.jsx', '.js').replace('.tsx', '.js')),
|
|
405
|
-
ROOT: process.cwd() + '/app/',
|
|
406
|
-
OUT: path.dirname(file),
|
|
407
|
-
shouldReplace: true,
|
|
408
|
-
file: process.cwd() + '/dist/' + file.replace('.jsx', '.js').replace('.tsx', '.js'),
|
|
409
|
-
DEV: mode === 'development',
|
|
410
|
-
size: code.length / 1024,
|
|
411
|
-
filePath: file.replace('.jsx', '.js'),
|
|
412
|
-
isTs: file.includes('.tsx'),
|
|
413
|
-
INPUT: path.join(process.cwd(), file.replace('.js', '.jsx').replace('.tsx', '.js')),
|
|
414
|
-
},
|
|
415
|
-
onExit({ exitCode: code }) {
|
|
416
|
-
if (code === 0) {
|
|
417
|
-
resolve()
|
|
418
|
-
} else {
|
|
419
|
-
reject()
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
})
|
|
423
|
-
} else if (file.includes('.ts')) {
|
|
424
|
-
let code = await Bun.file(file).text()
|
|
425
|
-
code = handleReplacements(code)
|
|
426
|
-
file = file.replace('.ts', '.js')
|
|
427
|
-
fs.writeFileSync(path.join(process.cwd() + '/dist', file.replace('.ts', '.js')), code)
|
|
428
|
-
await Bun.spawn({
|
|
429
|
-
cmd: [bunPath, 'run', './dev/bundler.js'],
|
|
430
|
-
cwd: process.cwd(),
|
|
431
|
-
stdout: 'inherit',
|
|
432
|
-
env: {
|
|
433
|
-
ENTRYPOINT: path.join(process.cwd() + '/dist/' + file.replace('.ts', '.js')),
|
|
434
|
-
ROOT: process.cwd() + '/app/',
|
|
435
|
-
OUT: path.dirname(file),
|
|
436
|
-
file: process.cwd() + '/dist/' + file.replace('.ts', '.js'),
|
|
437
|
-
DEV: mode === 'development',
|
|
438
|
-
isTS: true,
|
|
439
|
-
size: code.length / 1024,
|
|
440
|
-
filePath: file.replace('.ts', '.js'),
|
|
441
|
-
INPUT: path.join(process.cwd(), file.replace('.js', '.jsx')),
|
|
442
|
-
},
|
|
443
|
-
onExit({ exitCode: code }) {
|
|
444
|
-
if (code === 0) {
|
|
445
|
-
resolve()
|
|
446
|
-
} else {
|
|
447
|
-
reject()
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
})
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
resolve()
|
|
456
|
-
} catch (error) {
|
|
457
|
-
reject(error)
|
|
458
|
-
}
|
|
459
|
-
})
|
|
332
|
+
await runPluginHook("onBuildFinish");
|
|
333
|
+
|
|
334
|
+
// Calculate the total duration and log it
|
|
335
|
+
const duration = (performance.now() - totalTime).toFixed(2);
|
|
336
|
+
logger.success(`Total build finished in ${duration}ms. Output is in /dist.`);
|
|
460
337
|
}
|
|
461
|
-
globalThis.clients = []
|
|
462
338
|
|
|
463
|
-
|
|
339
|
+
async function runDevServer() {
|
|
340
|
+
await buildAll(true);
|
|
341
|
+
|
|
342
|
+
const clients = new Set();
|
|
343
|
+
const port = config.port || 3000;
|
|
344
|
+
|
|
345
|
+
logger.info(`Starting dev server at http://localhost:${port}`);
|
|
346
|
+
|
|
347
|
+
serve({
|
|
348
|
+
port,
|
|
349
|
+
fetch(req, server) {
|
|
350
|
+
const url = new URL(req.url);
|
|
351
|
+
if (url.pathname === "/__hmr" && server.upgrade(req)) {
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
let filePath = path.join(DIST_DIR, url.pathname);
|
|
355
|
+
if (!path.extname(filePath)) {
|
|
356
|
+
filePath = path.join(filePath, "index.html");
|
|
357
|
+
}
|
|
358
|
+
const file = Bun.file(filePath);
|
|
359
|
+
return file.exists().then(exists =>
|
|
360
|
+
exists ? new Response(file) : new Response("Not Found", { status: 404 })
|
|
361
|
+
);
|
|
362
|
+
},
|
|
363
|
+
websocket: {
|
|
364
|
+
open: (ws) => clients.add(ws),
|
|
365
|
+
close: (ws) => clients.delete(ws),
|
|
366
|
+
},
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
const debouncedBuild = debounce(async () => {
|
|
464
370
|
try {
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
const startWatcher = () => {
|
|
472
|
-
if (watcher) watcher.close(); // Close any existing watcher
|
|
473
|
-
|
|
474
|
-
watcher = fs.watch(path.join(process.cwd(), '/'), { recursive: true }, (eventType, file) => {
|
|
475
|
-
if (!file) return; // Ensure file name is valid
|
|
476
|
-
if (file.includes('node_modules')) return;
|
|
477
|
-
if (file.includes('dist')) return;
|
|
478
|
-
if (!fs.existsSync(path.join(process.cwd(), file))) {
|
|
479
|
-
fs.rmSync(path.join(process.cwd(), "dist", file))
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
if (
|
|
483
|
-
file.endsWith('.tsx') || file.endsWith('.jsx') || file.endsWith('.css') || file.endsWith('.ts')
|
|
484
|
-
) {
|
|
485
|
-
// Reset config if needed
|
|
486
|
-
if (file.endsWith('vader.config.ts')) {
|
|
487
|
-
delete require.cache[require.resolve(process.cwd() + '/vader.config.ts')];
|
|
488
|
-
globalThis.config = require(process.cwd() + '/vader.config.ts').default;
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
clearTimeout(debounceTimeout);
|
|
492
|
-
debounceTimeout = setTimeout(async () => {
|
|
493
|
-
if (!isBuilding) {
|
|
494
|
-
isBuilding = true;
|
|
495
|
-
try {
|
|
496
|
-
await generateApp();
|
|
497
|
-
await handleFiles();
|
|
498
|
-
setTimeout(() => {
|
|
499
|
-
clients.forEach(c => c.send('reload'));
|
|
500
|
-
}, 1000);
|
|
501
|
-
} catch (error) {
|
|
502
|
-
console.error(error);
|
|
503
|
-
} finally {
|
|
504
|
-
isBuilding = false;
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
}, 500);
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
// Restart watcher if a new directory is created
|
|
511
|
-
if (eventType === 'rename') {
|
|
512
|
-
setTimeout(startWatcher, 500); // Slight delay to allow the OS to recognize new files
|
|
513
|
-
}
|
|
514
|
-
});
|
|
515
|
-
};
|
|
516
|
-
|
|
517
|
-
// Start the watcher and restart it periodically
|
|
518
|
-
setInterval(startWatcher, 500);
|
|
519
|
-
startWatcher(); // Run initially
|
|
520
|
-
} catch (error) {
|
|
521
|
-
console.error(error)
|
|
371
|
+
await buildAll(true);
|
|
372
|
+
for (const client of clients) {
|
|
373
|
+
client.send("reload");
|
|
374
|
+
}
|
|
375
|
+
} catch (e) {
|
|
376
|
+
logger.error("Rebuild failed:", e);
|
|
522
377
|
}
|
|
378
|
+
}, 200);
|
|
523
379
|
|
|
380
|
+
const watchDirs = [APP_DIR, SRC_DIR, PUBLIC_DIR].filter(fsSync.existsSync);
|
|
381
|
+
for (const dir of watchDirs) {
|
|
382
|
+
fsSync.watch(dir, { recursive: true }, debouncedBuild);
|
|
383
|
+
}
|
|
524
384
|
}
|
|
525
|
-
else if (mode == 'production') {
|
|
526
|
-
await handleFiles()
|
|
527
|
-
await generateApp()
|
|
528
385
|
|
|
529
|
-
|
|
386
|
+
async function runProdServer() {
|
|
387
|
+
const port = config.port || 3000;
|
|
388
|
+
logger.info(`Serving production build from /dist on http://localhost:${port}`);
|
|
389
|
+
serve({
|
|
390
|
+
port,
|
|
391
|
+
fetch(req) {
|
|
392
|
+
const url = new URL(req.url);
|
|
393
|
+
let filePath = path.join(DIST_DIR, url.pathname);
|
|
394
|
+
if (!path.extname(filePath)) {
|
|
395
|
+
filePath = path.join(filePath, "index.html");
|
|
396
|
+
}
|
|
397
|
+
const file = Bun.file(filePath);
|
|
398
|
+
return file.exists().then(exists =>
|
|
399
|
+
exists ? new Response(file) : new Response("Not Found", { status: 404 })
|
|
400
|
+
);
|
|
401
|
+
},
|
|
402
|
+
});
|
|
530
403
|
}
|
|
531
|
-
else {
|
|
532
|
-
if (isBuilding) console.log(`Build complete in ${Date.now() - start}ms at ${new Date().toLocaleTimeString()}`);
|
|
533
404
|
|
|
405
|
+
function debounce(fn, delay) {
|
|
406
|
+
let timeoutId;
|
|
407
|
+
return (...args) => {
|
|
408
|
+
clearTimeout(timeoutId);
|
|
409
|
+
timeoutId = setTimeout(() => fn(...args), delay);
|
|
410
|
+
};
|
|
534
411
|
}
|
|
535
412
|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
router.reload()
|
|
576
|
-
let route = router.match(url.pathname)
|
|
577
|
-
if (!route) {
|
|
578
|
-
return new Response('Not found', { status: 404 })
|
|
579
|
-
}
|
|
580
|
-
let p = route.pathname;
|
|
581
|
-
let base = path.dirname(route.filePath)
|
|
582
|
-
base = base.replace(/\\/g, '/')
|
|
583
|
-
base = base.replace(path.join(process.cwd() + '/app').replace(/\\/g, '/'), '')
|
|
584
|
-
base = base.replace(/\\/g, '/').replace('/app', '/dist')
|
|
585
|
-
base = process.cwd() + "/dist/" + base
|
|
586
|
-
if (!fs.existsSync(path.join(base, 'index.html'))) {
|
|
587
|
-
return new Response(`
|
|
588
|
-
<html>
|
|
589
|
-
<head>
|
|
590
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
591
|
-
<meta http-equiv="refresh" content="5">
|
|
592
|
-
</head>
|
|
593
|
-
<body>
|
|
594
|
-
<p>Rerouting to display changes from server</p>
|
|
595
|
-
</body>
|
|
596
|
-
`, {
|
|
597
|
-
headers: {
|
|
598
|
-
'Content-Type': 'text/html',
|
|
599
|
-
'Cache-Control': 'no-cache'
|
|
600
|
-
}
|
|
601
|
-
})
|
|
602
|
-
}
|
|
603
|
-
let data = await Bun.file(path.join(base, 'index.html')).text()
|
|
604
|
-
if (mode == "development") {
|
|
605
|
-
return new Response(data + `
|
|
606
|
-
<script>
|
|
607
|
-
let ws = new WebSocket(\`\${location.protocol === 'https:' ? 'wss' : 'ws'}://\${location.host}\`)
|
|
608
|
-
ws.onmessage = (e) => {
|
|
609
|
-
if(e.data === 'reload'){
|
|
610
|
-
console.log('Reloading to display changes from server')
|
|
611
|
-
window.location.reload()
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
ws.onopen = () => {
|
|
615
|
-
console.log('Connected to hmr server')
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
ws.onclose = () => {
|
|
619
|
-
// try to reconnect
|
|
620
|
-
console.log('Reconnecting to hmr server')
|
|
621
|
-
ws = new WebSocket(\`\${location.protocol === 'https:' ? 'wss' : 'ws'}://\${location.host}\`)
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
</script>
|
|
625
|
-
`, {
|
|
626
|
-
headers: {
|
|
627
|
-
'Content-Type': 'text/html'
|
|
628
|
-
}
|
|
629
|
-
})
|
|
630
|
-
} else {
|
|
631
|
-
return new Response(data, {
|
|
632
|
-
headers: {
|
|
633
|
-
'Content-Type': 'text/html'
|
|
634
|
-
}
|
|
635
|
-
})
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
}
|
|
639
|
-
})
|
|
413
|
+
// --- SCRIPT ENTRYPOINT ---
|
|
414
|
+
|
|
415
|
+
async function main() {
|
|
416
|
+
const banner = `${colors.magenta}
|
|
417
|
+
__ __ ____ ____ _______ __
|
|
418
|
+
| | / |/ __ \ / __ \ / ____/ |/ /
|
|
419
|
+
| | / / / / // /_/ // /___ | /
|
|
420
|
+
| | / / /_/ / \____// /___ / |
|
|
421
|
+
|____/____/_____/ /_____/ |_| |_|
|
|
422
|
+
${colors.reset}`;
|
|
423
|
+
|
|
424
|
+
console.log(banner);
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
config = await loadConfig();
|
|
428
|
+
config.port = config.port || 3000;
|
|
429
|
+
|
|
430
|
+
const command = process.argv[2];
|
|
431
|
+
|
|
432
|
+
if (command === "dev") {
|
|
433
|
+
await runDevServer();
|
|
434
|
+
} else if (command === "build") {
|
|
435
|
+
await buildAll(false);
|
|
436
|
+
} else if (command === "serve") {
|
|
437
|
+
await buildAll(false);
|
|
438
|
+
await runProdServer();
|
|
439
|
+
}
|
|
440
|
+
else if(command === "init"){
|
|
441
|
+
init().catch((e) => {
|
|
442
|
+
console.error("Initialization failed:", e);
|
|
443
|
+
process.exit(1);
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
} else {
|
|
447
|
+
logger.error(`Unknown command: '${command}'.`);
|
|
448
|
+
logger.info("Available commands: 'dev', 'build', 'serve'");
|
|
449
|
+
process.exit(1);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
640
452
|
|
|
641
|
-
|
|
642
|
-
|
|
453
|
+
main().catch(err => {
|
|
454
|
+
logger.error("An unexpected error occurred:", err);
|
|
455
|
+
process.exit(1);
|
|
456
|
+
});
|