@ramonyx/bundler 0.0.0-stage → 0.1.1
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/LICENSE +21 -0
- package/README.md +13 -2
- package/dist/build.d.ts +22 -0
- package/dist/build.js +45 -0
- package/dist/build.js.map +1 -0
- package/dist/dev.d.ts +20 -0
- package/dist/dev.js +141 -0
- package/dist/dev.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/package.json +30 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ramonymous
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @ramonyx/bundler
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Paket framework Ramonyx.
|
|
4
|
+
|
|
5
|
+
> **Alpha (0.1.1)** — framework Node.js ini adalah baseline produksi;
|
|
6
|
+
> runtime Rust/V8 bersifat eksperimental. Butuh **Node.js ≥ 24**.
|
|
7
|
+
|
|
8
|
+
## Instalasi
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @ramonyx/bundler
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Repo: https://github.com/RamonyxJS/ramonyx · Lisensi: MIT
|
package/dist/build.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { LoadedPage } from "@ramonyx/core";
|
|
2
|
+
export interface BuildClientOptions {
|
|
3
|
+
readonly appDir: string;
|
|
4
|
+
readonly pages: readonly LoadedPage[];
|
|
5
|
+
/** Relatif terhadap appDir; default "dist/client". */
|
|
6
|
+
readonly outDir?: string;
|
|
7
|
+
/** Hasilkan source map (`.js.map` + `sourcesContent`); default true. */
|
|
8
|
+
readonly sourcemap?: boolean;
|
|
9
|
+
/** URL publik bundle untuk `<script type="module">`; default "/assets/client.js". */
|
|
10
|
+
readonly scriptPath?: string;
|
|
11
|
+
readonly minify?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface BuildClientResult {
|
|
14
|
+
readonly outDir: string;
|
|
15
|
+
readonly scriptPath: string;
|
|
16
|
+
readonly entryFile: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Membundel client (React + registry halaman) memakai Vite (ADR-0005).
|
|
20
|
+
* Output ditulis ke `<appDir>/dist/client` dan siap disajikan sebagai aset statis.
|
|
21
|
+
*/
|
|
22
|
+
export declare function buildClient(options: BuildClientOptions): Promise<BuildClientResult>;
|
package/dist/build.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { generateClientEntry } from "@ramonyx/compiler";
|
|
4
|
+
import { build } from "vite";
|
|
5
|
+
/**
|
|
6
|
+
* Membundel client (React + registry halaman) memakai Vite (ADR-0005).
|
|
7
|
+
* Output ditulis ke `<appDir>/dist/client` dan siap disajikan sebagai aset statis.
|
|
8
|
+
*/
|
|
9
|
+
export async function buildClient(options) {
|
|
10
|
+
const outDir = join(options.appDir, options.outDir ?? "dist/client");
|
|
11
|
+
const entryDir = join(options.appDir, ".ramonyx");
|
|
12
|
+
const entryFile = join(entryDir, "client-entry.ts");
|
|
13
|
+
await mkdir(entryDir, { recursive: true });
|
|
14
|
+
await writeFile(entryFile, generateClientEntry(options.pages, { from: entryDir }));
|
|
15
|
+
await build({
|
|
16
|
+
configFile: false,
|
|
17
|
+
root: options.appDir,
|
|
18
|
+
logLevel: "warn",
|
|
19
|
+
esbuild: { jsx: "automatic" },
|
|
20
|
+
build: {
|
|
21
|
+
outDir,
|
|
22
|
+
emptyOutDir: true,
|
|
23
|
+
target: "es2022",
|
|
24
|
+
minify: options.minify ?? false,
|
|
25
|
+
// Source map produksi (default aktif): `sourcesContent` di-embed agar map tetap
|
|
26
|
+
// berguna walau sumber TS tidak ikut disajikan (ADR-0046).
|
|
27
|
+
sourcemap: options.sourcemap ?? true,
|
|
28
|
+
modulePreload: false,
|
|
29
|
+
rollupOptions: {
|
|
30
|
+
input: entryFile,
|
|
31
|
+
output: {
|
|
32
|
+
entryFileNames: "client.js",
|
|
33
|
+
chunkFileNames: "chunks/[name]-[hash].js",
|
|
34
|
+
assetFileNames: "[name][extname]",
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
return {
|
|
40
|
+
outDir,
|
|
41
|
+
scriptPath: options.scriptPath ?? "/assets/client.js",
|
|
42
|
+
entryFile,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=build.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../../packages/bundler/src/build.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD,OAAO,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAoB7B;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAA2B;IAC3D,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,aAAa,CAAC,CAAC;IACrE,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClD,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,EAAE,iBAAiB,CAAC,CAAC;IAEpD,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,MAAM,SAAS,CAAC,SAAS,EAAE,mBAAmB,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;IAEnF,MAAM,KAAK,CAAC;QACV,UAAU,EAAE,KAAK;QACjB,IAAI,EAAE,OAAO,CAAC,MAAM;QACpB,QAAQ,EAAE,MAAM;QAChB,OAAO,EAAE,EAAE,GAAG,EAAE,WAAW,EAAE;QAC7B,KAAK,EAAE;YACL,MAAM;YACN,WAAW,EAAE,IAAI;YACjB,MAAM,EAAE,QAAQ;YAChB,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,KAAK;YAC/B,gFAAgF;YAChF,2DAA2D;YAC3D,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,IAAI;YACpC,aAAa,EAAE,KAAK;YACpB,aAAa,EAAE;gBACb,KAAK,EAAE,SAAS;gBAChB,MAAM,EAAE;oBACN,cAAc,EAAE,WAAW;oBAC3B,cAAc,EAAE,yBAAyB;oBACzC,cAAc,EAAE,iBAAiB;iBAClC;aACF;SACF;KACF,CAAC,CAAC;IAEH,OAAO;QACL,MAAM;QACN,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,mBAAmB;QACrD,SAAS;KACV,CAAC;AACJ,CAAC","sourcesContent":["import { mkdir, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { generateClientEntry } from \"@ramonyx/compiler\";\nimport type { LoadedPage } from \"@ramonyx/core\";\nimport { build } from \"vite\";\n\nexport interface BuildClientOptions {\n readonly appDir: string;\n readonly pages: readonly LoadedPage[];\n /** Relatif terhadap appDir; default \"dist/client\". */\n readonly outDir?: string;\n /** Hasilkan source map (`.js.map` + `sourcesContent`); default true. */\n readonly sourcemap?: boolean;\n /** URL publik bundle untuk `<script type=\"module\">`; default \"/assets/client.js\". */\n readonly scriptPath?: string;\n readonly minify?: boolean;\n}\n\nexport interface BuildClientResult {\n readonly outDir: string;\n readonly scriptPath: string;\n readonly entryFile: string;\n}\n\n/**\n * Membundel client (React + registry halaman) memakai Vite (ADR-0005).\n * Output ditulis ke `<appDir>/dist/client` dan siap disajikan sebagai aset statis.\n */\nexport async function buildClient(options: BuildClientOptions): Promise<BuildClientResult> {\n const outDir = join(options.appDir, options.outDir ?? \"dist/client\");\n const entryDir = join(options.appDir, \".ramonyx\");\n const entryFile = join(entryDir, \"client-entry.ts\");\n\n await mkdir(entryDir, { recursive: true });\n await writeFile(entryFile, generateClientEntry(options.pages, { from: entryDir }));\n\n await build({\n configFile: false,\n root: options.appDir,\n logLevel: \"warn\",\n esbuild: { jsx: \"automatic\" },\n build: {\n outDir,\n emptyOutDir: true,\n target: \"es2022\",\n minify: options.minify ?? false,\n // Source map produksi (default aktif): `sourcesContent` di-embed agar map tetap\n // berguna walau sumber TS tidak ikut disajikan (ADR-0046).\n sourcemap: options.sourcemap ?? true,\n modulePreload: false,\n rollupOptions: {\n input: entryFile,\n output: {\n entryFileNames: \"client.js\",\n chunkFileNames: \"chunks/[name]-[hash].js\",\n assetFileNames: \"[name][extname]\",\n },\n },\n },\n });\n\n return {\n outDir,\n scriptPath: options.scriptPath ?? \"/assets/client.js\",\n entryFile,\n };\n}\n"]}
|
package/dist/dev.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type ModuleImporter } from "@ramonyx/compiler";
|
|
2
|
+
export interface DevServerOptions {
|
|
3
|
+
readonly appDir: string;
|
|
4
|
+
/** URL server SSR yang diproksikan (mis. "http://localhost:3000"). */
|
|
5
|
+
readonly target: string;
|
|
6
|
+
readonly port?: number;
|
|
7
|
+
}
|
|
8
|
+
export interface DevServer {
|
|
9
|
+
readonly url: string;
|
|
10
|
+
/** Importer untuk compiler: modul mengikuti module graph Vite (invalidasi saat file berubah). */
|
|
11
|
+
readonly importer: ModuleImporter;
|
|
12
|
+
readonly target: string;
|
|
13
|
+
close(): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Dev server: Vite (transform + HMR) sebagai front, proxy ke server SSR.
|
|
17
|
+
* Modul halaman/manifest dimuat lewat `vite.ssrLoadModule` agar SSR ikut segar saat file berubah
|
|
18
|
+
* (tanpa restart); perubahan di `src/routes` meregenerasi entry client + full-reload browser.
|
|
19
|
+
*/
|
|
20
|
+
export declare function createDevServer(options: DevServerOptions): Promise<DevServer>;
|
package/dist/dev.js
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
|
+
import { join, relative } from "node:path";
|
|
3
|
+
import { Readable } from "node:stream";
|
|
4
|
+
import { pipeline } from "node:stream/promises";
|
|
5
|
+
import { generateClientEntry, loadPageRoutes, RouteManifestError, } from "@ramonyx/compiler";
|
|
6
|
+
import { createServer } from "vite";
|
|
7
|
+
const ENTRY_FILE = "client-entry.ts";
|
|
8
|
+
/** Path yang dimiliki Vite (jangan diproksikan ke SSR). */
|
|
9
|
+
function isViteRequest(url) {
|
|
10
|
+
const path = url.split("?")[0] ?? "";
|
|
11
|
+
return (path.startsWith("/@") ||
|
|
12
|
+
path.startsWith("/node_modules/") ||
|
|
13
|
+
path.startsWith("/.ramonyx/") ||
|
|
14
|
+
path.startsWith("/src/") ||
|
|
15
|
+
path === "/favicon.ico");
|
|
16
|
+
}
|
|
17
|
+
const HOP_BY_HOP = new Set([
|
|
18
|
+
"connection",
|
|
19
|
+
"keep-alive",
|
|
20
|
+
"transfer-encoding",
|
|
21
|
+
"content-length",
|
|
22
|
+
"content-encoding",
|
|
23
|
+
]);
|
|
24
|
+
/**
|
|
25
|
+
* Proxy manual ke SSR (bukan `server.proxy` Vite): request non-Vite diteruskan dengan `fetch`,
|
|
26
|
+
* respons dipipe kembali apa adanya. Body request non-GET/HEAD dialirkan via `Readable.toWeb`.
|
|
27
|
+
*/
|
|
28
|
+
async function proxyToSsr(target, req, res, next) {
|
|
29
|
+
try {
|
|
30
|
+
const url = new URL(req.url ?? "/", target);
|
|
31
|
+
const headers = new Headers();
|
|
32
|
+
for (const [name, value] of Object.entries(req.headers)) {
|
|
33
|
+
if (value === undefined)
|
|
34
|
+
continue;
|
|
35
|
+
if (Array.isArray(value)) {
|
|
36
|
+
for (const item of value) {
|
|
37
|
+
headers.append(name, item);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
headers.set(name, value);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const method = req.method ?? "GET";
|
|
45
|
+
const init = {
|
|
46
|
+
method,
|
|
47
|
+
headers,
|
|
48
|
+
redirect: "manual",
|
|
49
|
+
};
|
|
50
|
+
if (method !== "GET" && method !== "HEAD") {
|
|
51
|
+
init.body = Readable.toWeb(req);
|
|
52
|
+
init.duplex = "half";
|
|
53
|
+
}
|
|
54
|
+
const response = await fetch(url, init);
|
|
55
|
+
res.statusCode = response.status;
|
|
56
|
+
response.headers.forEach((value, name) => {
|
|
57
|
+
if (name !== "set-cookie" && !HOP_BY_HOP.has(name)) {
|
|
58
|
+
res.setHeader(name, value);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
const cookies = response.headers.getSetCookie();
|
|
62
|
+
if (cookies.length > 0) {
|
|
63
|
+
res.setHeader("set-cookie", cookies);
|
|
64
|
+
}
|
|
65
|
+
if (response.body === null) {
|
|
66
|
+
res.end();
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
await pipeline(Readable.fromWeb(response.body), res);
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
next(error);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Dev server: Vite (transform + HMR) sebagai front, proxy ke server SSR.
|
|
77
|
+
* Modul halaman/manifest dimuat lewat `vite.ssrLoadModule` agar SSR ikut segar saat file berubah
|
|
78
|
+
* (tanpa restart); perubahan di `src/routes` meregenerasi entry client + full-reload browser.
|
|
79
|
+
*/
|
|
80
|
+
export async function createDevServer(options) {
|
|
81
|
+
const appDir = options.appDir;
|
|
82
|
+
const entryDir = join(appDir, ".ramonyx");
|
|
83
|
+
const entryFile = join(entryDir, ENTRY_FILE);
|
|
84
|
+
const routesDir = join(appDir, "src", "routes");
|
|
85
|
+
const vite = await createServer({
|
|
86
|
+
configFile: false,
|
|
87
|
+
root: appDir,
|
|
88
|
+
appType: "custom",
|
|
89
|
+
logLevel: "info",
|
|
90
|
+
esbuild: { jsx: "automatic" },
|
|
91
|
+
server: { port: options.port ?? 5173 },
|
|
92
|
+
plugins: [
|
|
93
|
+
{
|
|
94
|
+
name: "ramonyx-ssr-proxy",
|
|
95
|
+
configureServer(server) {
|
|
96
|
+
server.middlewares.use((req, res, next) => {
|
|
97
|
+
if (req.url === undefined || isViteRequest(req.url)) {
|
|
98
|
+
next();
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
void proxyToSsr(options.target, req, res, next);
|
|
102
|
+
});
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
});
|
|
107
|
+
const importer = async (absolute, label) => {
|
|
108
|
+
try {
|
|
109
|
+
return (await vite.ssrLoadModule(absolute));
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
throw new RouteManifestError(`[dev] gagal memuat ${label} (${relative(appDir, absolute) || absolute}) via Vite: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
const regenerateEntry = async () => {
|
|
116
|
+
const pages = await loadPageRoutes({ dir: routesDir, importer });
|
|
117
|
+
await mkdir(entryDir, { recursive: true });
|
|
118
|
+
await writeFile(entryFile, generateClientEntry(pages, { from: entryDir }));
|
|
119
|
+
};
|
|
120
|
+
await regenerateEntry();
|
|
121
|
+
vite.watcher.on("all", (_event, file) => {
|
|
122
|
+
if (!file.startsWith(routesDir)) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
void regenerateEntry()
|
|
126
|
+
.catch(() => undefined)
|
|
127
|
+
.finally(() => {
|
|
128
|
+
vite.ws.send({ type: "full-reload" });
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
await vite.listen();
|
|
132
|
+
const address = vite.httpServer?.address();
|
|
133
|
+
const port = typeof address === "object" && address !== null ? address.port : (options.port ?? 5173);
|
|
134
|
+
return {
|
|
135
|
+
url: `http://localhost:${port}`,
|
|
136
|
+
importer,
|
|
137
|
+
target: options.target,
|
|
138
|
+
close: () => vite.close(),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=dev.js.map
|
package/dist/dev.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev.js","sourceRoot":"","sources":["../../../packages/bundler/src/dev.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdir, writeFile } from \"node:fs/promises\";\nimport type { ServerResponse } from \"node:http\";\nimport { join, relative } from \"node:path\";\nimport { Readable } from \"node:stream\";\nimport { pipeline } from \"node:stream/promises\";\nimport {\n generateClientEntry,\n loadPageRoutes,\n type ModuleImporter,\n RouteManifestError,\n} from \"@ramonyx/compiler\";\nimport { type Connect, createServer } from \"vite\";\n\nexport interface DevServerOptions {\n readonly appDir: string;\n /** URL server SSR yang diproksikan (mis. \"http://localhost:3000\"). */\n readonly target: string;\n readonly port?: number;\n}\n\nexport interface DevServer {\n readonly url: string;\n /** Importer untuk compiler: modul mengikuti module graph Vite (invalidasi saat file berubah). */\n readonly importer: ModuleImporter;\n readonly target: string;\n close(): Promise<void>;\n}\n\nconst ENTRY_FILE = \"client-entry.ts\";\n\n/** Path yang dimiliki Vite (jangan diproksikan ke SSR). */\nfunction isViteRequest(url: string): boolean {\n const path = url.split(\"?\")[0] ?? \"\";\n return (\n path.startsWith(\"/@\") ||\n path.startsWith(\"/node_modules/\") ||\n path.startsWith(\"/.ramonyx/\") ||\n path.startsWith(\"/src/\") ||\n path === \"/favicon.ico\"\n );\n}\n\nconst HOP_BY_HOP = new Set([\n \"connection\",\n \"keep-alive\",\n \"transfer-encoding\",\n \"content-length\",\n \"content-encoding\",\n]);\n\n/**\n * Proxy manual ke SSR (bukan `server.proxy` Vite): request non-Vite diteruskan dengan `fetch`,\n * respons dipipe kembali apa adanya. Body request non-GET/HEAD dialirkan via `Readable.toWeb`.\n */\nasync function proxyToSsr(\n target: string,\n req: Connect.IncomingMessage,\n res: ServerResponse,\n next: Connect.NextFunction,\n): Promise<void> {\n try {\n const url = new URL(req.url ?? \"/\", target);\n const headers = new Headers();\n for (const [name, value] of Object.entries(req.headers)) {\n if (value === undefined) continue;\n if (Array.isArray(value)) {\n for (const item of value) {\n headers.append(name, item);\n }\n } else {\n headers.set(name, value);\n }\n }\n\n const method = req.method ?? \"GET\";\n const init: RequestInit & { duplex?: \"half\" } = {\n method,\n headers,\n redirect: \"manual\",\n };\n if (method !== \"GET\" && method !== \"HEAD\") {\n init.body = Readable.toWeb(req) as unknown as BodyInit;\n init.duplex = \"half\";\n }\n\n const response = await fetch(url, init);\n res.statusCode = response.status;\n response.headers.forEach((value, name) => {\n if (name !== \"set-cookie\" && !HOP_BY_HOP.has(name)) {\n res.setHeader(name, value);\n }\n });\n const cookies = response.headers.getSetCookie();\n if (cookies.length > 0) {\n res.setHeader(\"set-cookie\", cookies);\n }\n\n if (response.body === null) {\n res.end();\n return;\n }\n await pipeline(Readable.fromWeb(response.body as never), res);\n } catch (error) {\n next(error);\n }\n}\n\n/**\n * Dev server: Vite (transform + HMR) sebagai front, proxy ke server SSR.\n * Modul halaman/manifest dimuat lewat `vite.ssrLoadModule` agar SSR ikut segar saat file berubah\n * (tanpa restart); perubahan di `src/routes` meregenerasi entry client + full-reload browser.\n */\nexport async function createDevServer(options: DevServerOptions): Promise<DevServer> {\n const appDir = options.appDir;\n const entryDir = join(appDir, \".ramonyx\");\n const entryFile = join(entryDir, ENTRY_FILE);\n const routesDir = join(appDir, \"src\", \"routes\");\n\n const vite = await createServer({\n configFile: false,\n root: appDir,\n appType: \"custom\",\n logLevel: \"info\",\n esbuild: { jsx: \"automatic\" },\n server: { port: options.port ?? 5173 },\n plugins: [\n {\n name: \"ramonyx-ssr-proxy\",\n configureServer(server) {\n server.middlewares.use((req, res, next) => {\n if (req.url === undefined || isViteRequest(req.url)) {\n next();\n return;\n }\n void proxyToSsr(options.target, req, res, next);\n });\n },\n },\n ],\n });\n\n const importer: ModuleImporter = async (absolute, label) => {\n try {\n return (await vite.ssrLoadModule(absolute)) as Record<string, unknown>;\n } catch (error) {\n throw new RouteManifestError(\n `[dev] gagal memuat ${label} (${relative(appDir, absolute) || absolute}) via Vite: ${\n error instanceof Error ? error.message : String(error)\n }`,\n { cause: error },\n );\n }\n };\n\n const regenerateEntry = async (): Promise<void> => {\n const pages = await loadPageRoutes({ dir: routesDir, importer });\n await mkdir(entryDir, { recursive: true });\n await writeFile(entryFile, generateClientEntry(pages, { from: entryDir }));\n };\n await regenerateEntry();\n\n vite.watcher.on(\"all\", (_event, file) => {\n if (!file.startsWith(routesDir)) {\n return;\n }\n void regenerateEntry()\n .catch(() => undefined)\n .finally(() => {\n vite.ws.send({ type: \"full-reload\" });\n });\n });\n\n await vite.listen();\n const address = vite.httpServer?.address();\n const port =\n typeof address === \"object\" && address !== null ? address.port : (options.port ?? 5173);\n\n return {\n url: `http://localhost:${port}`,\n importer,\n target: options.target,\n close: () => vite.close(),\n };\n}\n"]}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../packages/bundler/src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC","sourcesContent":["export type { BuildClientOptions, BuildClientResult } from \"./build.ts\";\nexport { buildClient } from \"./build.ts\";\nexport type { DevServer, DevServerOptions } from \"./dev.ts\";\nexport { createDevServer } from \"./dev.ts\";\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,33 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ramonyx/bundler",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Paket framework Ramonyx.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"README.md",
|
|
16
|
+
"LICENSE"
|
|
17
|
+
],
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=24"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@ramonyx/compiler": "^0.1.1",
|
|
23
|
+
"@ramonyx/core": "^0.1.1",
|
|
24
|
+
"vite": "8.3.4"
|
|
25
|
+
},
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
28
|
+
},
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "https://github.com/RamonyxJS/ramonyx"
|
|
32
|
+
}
|
|
6
33
|
}
|