@ramonyx/bundler 2.0.1 → 2.1.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/dist/build.d.ts +9 -0
- package/dist/build.js +21 -1
- package/dist/build.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/server-only.js +5 -1
- package/dist/server-only.js.map +1 -1
- package/package.json +4 -4
package/dist/build.d.ts
CHANGED
|
@@ -31,6 +31,15 @@ export interface BuildClientResult {
|
|
|
31
31
|
/** Nama berkas (relatif terhadap outDir) yang dihasilkan build. */
|
|
32
32
|
readonly files: readonly string[];
|
|
33
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Mirror the hashed client entry + chunks into `<outDir>/assets/**`.
|
|
36
|
+
*
|
|
37
|
+
* Node's `serveStatic({ prefix: "/assets" })` strips the prefix, while static hosts
|
|
38
|
+
* (notably Cloudflare Workers Assets) serve the output directory at its root. Copying
|
|
39
|
+
* here makes the same `/assets/client-*.js` URL work on both without an app-level build
|
|
40
|
+
* script. Idempotent and safe when the public directory already contains `assets/`.
|
|
41
|
+
*/
|
|
42
|
+
export declare function mirrorClientAssets(outDir: string, clientFile: string): Promise<void>;
|
|
34
43
|
export declare function buildClient(options: BuildClientOptions): Promise<BuildClientResult>;
|
|
35
44
|
/**
|
|
36
45
|
* URL bundle klien dari manifest hasil build — dipakai server (`ramonyx start`, aplikasi)
|
package/dist/build.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
-
import { mkdir, readdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { cp, mkdir, readdir, readFile, writeFile } from "node:fs/promises";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { generateClientEntry, lintClientBoundaries } from "@ramonyx/compiler";
|
|
5
5
|
import { errorHint } from "@ramonyx/core";
|
|
@@ -67,6 +67,23 @@ async function assertBundleBrowserSafe(outDir) {
|
|
|
67
67
|
`\nPisahkan modul server (\`*.server.ts\`) dan impor hanya dari loader/action/route API. ${errorHint("RMX-BUILD-2")}`);
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Mirror the hashed client entry + chunks into `<outDir>/assets/**`.
|
|
72
|
+
*
|
|
73
|
+
* Node's `serveStatic({ prefix: "/assets" })` strips the prefix, while static hosts
|
|
74
|
+
* (notably Cloudflare Workers Assets) serve the output directory at its root. Copying
|
|
75
|
+
* here makes the same `/assets/client-*.js` URL work on both without an app-level build
|
|
76
|
+
* script. Idempotent and safe when the public directory already contains `assets/`.
|
|
77
|
+
*/
|
|
78
|
+
export async function mirrorClientAssets(outDir, clientFile) {
|
|
79
|
+
const assetsDir = join(outDir, "assets");
|
|
80
|
+
await mkdir(assetsDir, { recursive: true });
|
|
81
|
+
await cp(join(outDir, clientFile), join(assetsDir, clientFile));
|
|
82
|
+
const chunksDir = join(outDir, "chunks");
|
|
83
|
+
if (existsSync(chunksDir)) {
|
|
84
|
+
await cp(chunksDir, join(assetsDir, "chunks"), { recursive: true });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
70
87
|
export async function buildClient(options) {
|
|
71
88
|
const outDir = join(options.appDir, options.outDir ?? "dist/client");
|
|
72
89
|
const entryDir = join(options.appDir, ".ramonyx");
|
|
@@ -114,6 +131,9 @@ export async function buildClient(options) {
|
|
|
114
131
|
if (clientFile === undefined) {
|
|
115
132
|
throw new Error(`build klien tidak menghasilkan client-<hash>.js di ${outDir}`);
|
|
116
133
|
}
|
|
134
|
+
// Edge static hosts serve the client directory at root; Node strips `/assets`.
|
|
135
|
+
// Mirror the hashed entry + chunks so both deployment models share one URL contract.
|
|
136
|
+
await mirrorClientAssets(outDir, clientFile);
|
|
117
137
|
// Pipeline aset (ADR-0069): pindai `src/assets/**` → salin ber-hash + catat di manifest.
|
|
118
138
|
const assetsDir = options.assetsDir === false
|
|
119
139
|
? null
|
package/dist/build.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../../packages/bundler/src/build.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { mkdir, readdir, readFile, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { generateClientEntry, lintClientBoundaries } from \"@ramonyx/compiler\";\nimport { errorHint, type LoadedPage } from \"@ramonyx/core\";\nimport { build, type PluginOption } from \"vite\";\nimport { type AssetProcessor, collectAssets, DEFAULT_ASSETS_DIR } from \"./assets.ts\";\nimport {\n type AssetManifest,\n CLIENT_MANIFEST_FILE,\n readAssetManifest,\n writeAssetManifest,\n} from \"./manifest.ts\";\nimport { serverOnlyPlugin } from \"./server-only.ts\";\n\nexport type { AssetEntry, AssetManifest, AssetMap } from \"./manifest.ts\";\nexport { CLIENT_MANIFEST_FILE, readAssetManifest } from \"./manifest.ts\";\n\nconst SERVER_ONLY_IMPORT = /(?:from|import\\s*\\(|require\\s*\\()\\s*[\"'](node:[^\"']+)[\"']/g;\nconst BROWSER_EXTERNAL_MARKER = \"__vite-browser-external\";\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 /** Prefix URL publik aset (untuk `scriptPath` hasil); default \"/assets\". */\n readonly assetsUrlPrefix?: string;\n readonly minify?: boolean;\n /** Plugin Vite tambahan (dari plugin Ramonyx — ADR-0067). */\n readonly plugins?: readonly PluginOption[];\n /** Prosesor aset (hook `assets` plugin — ADR-0079). */\n readonly assetProcessors?: readonly AssetProcessor[];\n /**\n * Direktori aset (relatif appDir) yang dipindai & disalin ber-hash ke `assets/**` +\n * dicatat di manifest (ADR-0069). Default `src/assets` bila ada; `false` mematikan.\n */\n readonly assetsDir?: string | false;\n}\n\nexport interface BuildClientResult {\n readonly outDir: string;\n /** URL bundle klien ber-fingerprint, mis. `/assets/client-D3fK2p.js`. */\n readonly scriptPath: string;\n readonly entryFile: string;\n /** Nama berkas (relatif terhadap outDir) yang dihasilkan build. */\n readonly files: readonly string[];\n}\n\n/**\n * Membundel client (React + registry halaman) memakai Vite (ADR-0005).\n *\n * Nama berkas memuat **hash konten** (`client-<hash>.js`, ADR-0055) sehingga dapat disajikan\n * dengan `cache-control: immutable`; peta nama ditulis ke `ramonyx.assets.json` dan dibaca\n * server lewat `readClientScript`.\n */\n/** Pre-check (ADR-0063): modul yang masuk bundle klien (page/layout) dilarang mengimpor `node:*`. */\nasync function assertClientFilesBrowserSafe(pages: readonly LoadedPage[]): Promise<void> {\n const files = new Set<string>();\n for (const page of pages) {\n if (page.pageFile !== undefined) {\n files.add(page.pageFile);\n }\n for (const layout of page.layoutFiles ?? []) {\n files.add(layout);\n }\n }\n\n const violations: string[] = [];\n for (const file of files) {\n let source: string;\n try {\n source = await readFile(file, \"utf8\");\n } catch {\n continue;\n }\n for (const match of source.matchAll(SERVER_ONLY_IMPORT)) {\n violations.push(`${file} → ${match[1] ?? \"?\"}`);\n }\n }\n\n if (violations.length > 0) {\n throw new Error(\n \"Batas server/client dilanggar (ADR-0063): modul yang masuk bundle klien mengimpor API server:\\n\" +\n violations.map((entry) => ` - ${entry}`).join(\"\\n\") +\n \"\\nPindahkan kode server ke modul `*.server.ts` yang hanya diimpor dari loader/action/route API, \" +\n `atau akses lewat API route. ${errorHint(\"RMX-BUILD-1\")}`,\n );\n }\n}\n\n/** Post-build (ADR-0063): output tidak boleh memuat shim browser-external Vite atau `node:*` (impor transitif). */\nasync function assertBundleBrowserSafe(outDir: string): Promise<void> {\n const files = (await readdir(outDir, { recursive: true })).filter((file) => file.endsWith(\".js\"));\n const violations = new Set<string>();\n for (const file of files) {\n const source = await readFile(join(outDir, file), \"utf8\");\n if (source.includes(BROWSER_EXTERNAL_MARKER)) {\n violations.add(file);\n }\n for (const match of source.matchAll(SERVER_ONLY_IMPORT)) {\n violations.add(`${file} → ${match[1] ?? \"?\"}`);\n }\n }\n\n if (violations.size > 0) {\n throw new Error(\n \"Bundel klien memuat API server (ADR-0063) — kemungkinan impor transitif dari modul klien:\\n\" +\n [...violations].map((entry) => ` - ${entry}`).join(\"\\n\") +\n `\\nPisahkan modul server (\\`*.server.ts\\`) dan impor hanya dari loader/action/route API. ${errorHint(\"RMX-BUILD-2\")}`,\n );\n }\n}\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 const boundaryViolations = await lintClientBoundaries(options.pages);\n if (boundaryViolations.length > 0) {\n throw new Error(\n \"Batas server/client dilanggar (ADR-0063): modul halaman/layout/error mengimpor API server:\\n\" +\n boundaryViolations\n .map((violation) => ` - ${violation.file} → ${violation.specifier}`)\n .join(\"\\n\") +\n \"\\nPindahkan impor tersebut ke modul `*.server.ts` yang hanya dipakai loader/action/route API. \" +\n errorHint(\"RMX-BUILD-1\"),\n );\n }\n\n await assertClientFilesBrowserSafe(options.pages);\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 plugins: [...(options.plugins ?? []), serverOnlyPlugin()],\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-[hash].js\",\n chunkFileNames: \"chunks/[name]-[hash].js\",\n assetFileNames: \"[name]-[hash][extname]\",\n },\n },\n },\n });\n\n await assertBundleBrowserSafe(outDir);\n\n const files = (await readdir(outDir, { recursive: true })).filter(\n (file) => !file.endsWith(CLIENT_MANIFEST_FILE),\n );\n const clientFile = files.find((file) => /^client-.*\\.js$/.test(file));\n if (clientFile === undefined) {\n throw new Error(`build klien tidak menghasilkan client-<hash>.js di ${outDir}`);\n }\n\n // Pipeline aset (ADR-0069): pindai `src/assets/**` → salin ber-hash + catat di manifest.\n const assetsDir =\n options.assetsDir === false\n ? null\n : join(options.appDir, options.assetsDir ?? DEFAULT_ASSETS_DIR);\n let assets: Awaited<ReturnType<typeof collectAssets>>[\"assets\"] = {};\n if (assetsDir !== null && existsSync(assetsDir)) {\n const collected = await collectAssets(assetsDir, outDir, {\n processors: options.assetProcessors,\n });\n assets = collected.assets;\n }\n\n const manifest: AssetManifest = {\n client: clientFile,\n files: [...files].sort(),\n ...(Object.keys(assets).length > 0 ? { assets } : {}),\n };\n await writeAssetManifest(outDir, manifest);\n\n const prefix = (options.assetsUrlPrefix ?? \"/assets\").replace(/\\/$/, \"\");\n return { outDir, scriptPath: `${prefix}/${clientFile}`, entryFile, files: manifest.files };\n}\n\n/**\n * URL bundle klien dari manifest hasil build — dipakai server (`ramonyx start`, aplikasi)\n * agar tetap benar saat nama berkas ber-hash. Fallback `/assets/client.js` bila manifest\n * belum ada (mis. server dijalankan tanpa build — CLI sudah memperingatkan).\n */\nexport async function readClientScript(\n clientDir: string,\n options: { urlPrefix?: string } = {},\n): Promise<string> {\n const prefix = (options.urlPrefix ?? \"/assets\").replace(/\\/$/, \"\");\n const manifest = await readAssetManifest(clientDir);\n return manifest === null ? `${prefix}/client.js` : `${prefix}/${manifest.client}`;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../../packages/bundler/src/build.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { cp, mkdir, readdir, readFile, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { generateClientEntry, lintClientBoundaries } from \"@ramonyx/compiler\";\nimport { errorHint, type LoadedPage } from \"@ramonyx/core\";\nimport { build, type PluginOption } from \"vite\";\nimport { type AssetProcessor, collectAssets, DEFAULT_ASSETS_DIR } from \"./assets.ts\";\nimport {\n type AssetManifest,\n CLIENT_MANIFEST_FILE,\n readAssetManifest,\n writeAssetManifest,\n} from \"./manifest.ts\";\nimport { serverOnlyPlugin } from \"./server-only.ts\";\n\nexport type { AssetEntry, AssetManifest, AssetMap } from \"./manifest.ts\";\nexport { CLIENT_MANIFEST_FILE, readAssetManifest } from \"./manifest.ts\";\n\nconst SERVER_ONLY_IMPORT = /(?:from|import\\s*\\(|require\\s*\\()\\s*[\"'](node:[^\"']+)[\"']/g;\nconst BROWSER_EXTERNAL_MARKER = \"__vite-browser-external\";\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 /** Prefix URL publik aset (untuk `scriptPath` hasil); default \"/assets\". */\n readonly assetsUrlPrefix?: string;\n readonly minify?: boolean;\n /** Plugin Vite tambahan (dari plugin Ramonyx — ADR-0067). */\n readonly plugins?: readonly PluginOption[];\n /** Prosesor aset (hook `assets` plugin — ADR-0079). */\n readonly assetProcessors?: readonly AssetProcessor[];\n /**\n * Direktori aset (relatif appDir) yang dipindai & disalin ber-hash ke `assets/**` +\n * dicatat di manifest (ADR-0069). Default `src/assets` bila ada; `false` mematikan.\n */\n readonly assetsDir?: string | false;\n}\n\nexport interface BuildClientResult {\n readonly outDir: string;\n /** URL bundle klien ber-fingerprint, mis. `/assets/client-D3fK2p.js`. */\n readonly scriptPath: string;\n readonly entryFile: string;\n /** Nama berkas (relatif terhadap outDir) yang dihasilkan build. */\n readonly files: readonly string[];\n}\n\n/**\n * Membundel client (React + registry halaman) memakai Vite (ADR-0005).\n *\n * Nama berkas memuat **hash konten** (`client-<hash>.js`, ADR-0055) sehingga dapat disajikan\n * dengan `cache-control: immutable`; peta nama ditulis ke `ramonyx.assets.json` dan dibaca\n * server lewat `readClientScript`.\n */\n/** Pre-check (ADR-0063): modul yang masuk bundle klien (page/layout) dilarang mengimpor `node:*`. */\nasync function assertClientFilesBrowserSafe(pages: readonly LoadedPage[]): Promise<void> {\n const files = new Set<string>();\n for (const page of pages) {\n if (page.pageFile !== undefined) {\n files.add(page.pageFile);\n }\n for (const layout of page.layoutFiles ?? []) {\n files.add(layout);\n }\n }\n\n const violations: string[] = [];\n for (const file of files) {\n let source: string;\n try {\n source = await readFile(file, \"utf8\");\n } catch {\n continue;\n }\n for (const match of source.matchAll(SERVER_ONLY_IMPORT)) {\n violations.push(`${file} → ${match[1] ?? \"?\"}`);\n }\n }\n\n if (violations.length > 0) {\n throw new Error(\n \"Batas server/client dilanggar (ADR-0063): modul yang masuk bundle klien mengimpor API server:\\n\" +\n violations.map((entry) => ` - ${entry}`).join(\"\\n\") +\n \"\\nPindahkan kode server ke modul `*.server.ts` yang hanya diimpor dari loader/action/route API, \" +\n `atau akses lewat API route. ${errorHint(\"RMX-BUILD-1\")}`,\n );\n }\n}\n\n/** Post-build (ADR-0063): output tidak boleh memuat shim browser-external Vite atau `node:*` (impor transitif). */\nasync function assertBundleBrowserSafe(outDir: string): Promise<void> {\n const files = (await readdir(outDir, { recursive: true })).filter((file) => file.endsWith(\".js\"));\n const violations = new Set<string>();\n for (const file of files) {\n const source = await readFile(join(outDir, file), \"utf8\");\n if (source.includes(BROWSER_EXTERNAL_MARKER)) {\n violations.add(file);\n }\n for (const match of source.matchAll(SERVER_ONLY_IMPORT)) {\n violations.add(`${file} → ${match[1] ?? \"?\"}`);\n }\n }\n\n if (violations.size > 0) {\n throw new Error(\n \"Bundel klien memuat API server (ADR-0063) — kemungkinan impor transitif dari modul klien:\\n\" +\n [...violations].map((entry) => ` - ${entry}`).join(\"\\n\") +\n `\\nPisahkan modul server (\\`*.server.ts\\`) dan impor hanya dari loader/action/route API. ${errorHint(\"RMX-BUILD-2\")}`,\n );\n }\n}\n\n/**\n * Mirror the hashed client entry + chunks into `<outDir>/assets/**`.\n *\n * Node's `serveStatic({ prefix: \"/assets\" })` strips the prefix, while static hosts\n * (notably Cloudflare Workers Assets) serve the output directory at its root. Copying\n * here makes the same `/assets/client-*.js` URL work on both without an app-level build\n * script. Idempotent and safe when the public directory already contains `assets/`.\n */\nexport async function mirrorClientAssets(outDir: string, clientFile: string): Promise<void> {\n const assetsDir = join(outDir, \"assets\");\n await mkdir(assetsDir, { recursive: true });\n await cp(join(outDir, clientFile), join(assetsDir, clientFile));\n const chunksDir = join(outDir, \"chunks\");\n if (existsSync(chunksDir)) {\n await cp(chunksDir, join(assetsDir, \"chunks\"), { recursive: true });\n }\n}\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 const boundaryViolations = await lintClientBoundaries(options.pages);\n if (boundaryViolations.length > 0) {\n throw new Error(\n \"Batas server/client dilanggar (ADR-0063): modul halaman/layout/error mengimpor API server:\\n\" +\n boundaryViolations\n .map((violation) => ` - ${violation.file} → ${violation.specifier}`)\n .join(\"\\n\") +\n \"\\nPindahkan impor tersebut ke modul `*.server.ts` yang hanya dipakai loader/action/route API. \" +\n errorHint(\"RMX-BUILD-1\"),\n );\n }\n\n await assertClientFilesBrowserSafe(options.pages);\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 plugins: [...(options.plugins ?? []), serverOnlyPlugin()],\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-[hash].js\",\n chunkFileNames: \"chunks/[name]-[hash].js\",\n assetFileNames: \"[name]-[hash][extname]\",\n },\n },\n },\n });\n\n await assertBundleBrowserSafe(outDir);\n\n const files = (await readdir(outDir, { recursive: true })).filter(\n (file) => !file.endsWith(CLIENT_MANIFEST_FILE),\n );\n const clientFile = files.find((file) => /^client-.*\\.js$/.test(file));\n if (clientFile === undefined) {\n throw new Error(`build klien tidak menghasilkan client-<hash>.js di ${outDir}`);\n }\n\n // Edge static hosts serve the client directory at root; Node strips `/assets`.\n // Mirror the hashed entry + chunks so both deployment models share one URL contract.\n await mirrorClientAssets(outDir, clientFile);\n\n // Pipeline aset (ADR-0069): pindai `src/assets/**` → salin ber-hash + catat di manifest.\n const assetsDir =\n options.assetsDir === false\n ? null\n : join(options.appDir, options.assetsDir ?? DEFAULT_ASSETS_DIR);\n let assets: Awaited<ReturnType<typeof collectAssets>>[\"assets\"] = {};\n if (assetsDir !== null && existsSync(assetsDir)) {\n const collected = await collectAssets(assetsDir, outDir, {\n processors: options.assetProcessors,\n });\n assets = collected.assets;\n }\n\n const manifest: AssetManifest = {\n client: clientFile,\n files: [...files].sort(),\n ...(Object.keys(assets).length > 0 ? { assets } : {}),\n };\n await writeAssetManifest(outDir, manifest);\n\n const prefix = (options.assetsUrlPrefix ?? \"/assets\").replace(/\\/$/, \"\");\n return { outDir, scriptPath: `${prefix}/${clientFile}`, entryFile, files: manifest.files };\n}\n\n/**\n * URL bundle klien dari manifest hasil build — dipakai server (`ramonyx start`, aplikasi)\n * agar tetap benar saat nama berkas ber-hash. Fallback `/assets/client.js` bila manifest\n * belum ada (mis. server dijalankan tanpa build — CLI sudah memperingatkan).\n */\nexport async function readClientScript(\n clientDir: string,\n options: { urlPrefix?: string } = {},\n): Promise<string> {\n const prefix = (options.urlPrefix ?? \"/assets\").replace(/\\/$/, \"\");\n const manifest = await readAssetManifest(clientDir);\n return manifest === null ? `${prefix}/client.js` : `${prefix}/${manifest.client}`;\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export type { AssetProcessor, AssetProcessorInput, AssetProcessorOutput, AssetProcessorResult, AssetUrlOptions, CollectAssetsOptions, CollectAssetsResult, CreateAssetResolverOptions, } from "./assets.js";
|
|
2
2
|
export { assetInfoMap, assetsDirExists, assetUrl, collectAssets, createAssetResolver, DEFAULT_ASSETS_DIR, fontPreloadTag, } from "./assets.js";
|
|
3
3
|
export type { BuildClientOptions, BuildClientResult } from "./build.js";
|
|
4
|
-
export { buildClient, readClientScript } from "./build.js";
|
|
4
|
+
export { buildClient, mirrorClientAssets, readClientScript } from "./build.js";
|
|
5
5
|
export type { DevServer, DevServerOptions } from "./dev.js";
|
|
6
6
|
export { createDevServer } from "./dev.js";
|
|
7
7
|
export type { BuildEdgeOptions, BuildEdgeResult } from "./edge.js";
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { assetInfoMap, assetsDirExists, assetUrl, collectAssets, createAssetResolver, DEFAULT_ASSETS_DIR, fontPreloadTag, } from "./assets.js";
|
|
2
|
-
export { buildClient, readClientScript } from "./build.js";
|
|
2
|
+
export { buildClient, mirrorClientAssets, readClientScript } from "./build.js";
|
|
3
3
|
export { createDevServer } from "./dev.js";
|
|
4
4
|
export { buildEdge } from "./edge.js";
|
|
5
5
|
export { CLIENT_MANIFEST_FILE, readAssetManifest, writeAssetManifest } from "./manifest.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../packages/bundler/src/index.ts"],"names":[],"mappings":"AAUA,OAAO,EACL,YAAY,EACZ,eAAe,EACf,QAAQ,EACR,aAAa,EACb,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,GACf,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../packages/bundler/src/index.ts"],"names":[],"mappings":"AAUA,OAAO,EACL,YAAY,EACZ,eAAe,EACf,QAAQ,EACR,aAAa,EACb,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,GACf,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE/E,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAE3C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAE5F,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAMxD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC","sourcesContent":["export type {\n AssetProcessor,\n AssetProcessorInput,\n AssetProcessorOutput,\n AssetProcessorResult,\n AssetUrlOptions,\n CollectAssetsOptions,\n CollectAssetsResult,\n CreateAssetResolverOptions,\n} from \"./assets.ts\";\nexport {\n assetInfoMap,\n assetsDirExists,\n assetUrl,\n collectAssets,\n createAssetResolver,\n DEFAULT_ASSETS_DIR,\n fontPreloadTag,\n} from \"./assets.ts\";\nexport type { BuildClientOptions, BuildClientResult } from \"./build.ts\";\nexport { buildClient, mirrorClientAssets, readClientScript } from \"./build.ts\";\nexport type { DevServer, DevServerOptions } from \"./dev.ts\";\nexport { createDevServer } from \"./dev.ts\";\nexport type { BuildEdgeOptions, BuildEdgeResult } from \"./edge.ts\";\nexport { buildEdge } from \"./edge.ts\";\nexport type { AssetEntry, AssetManifest, AssetMap } from \"./manifest.ts\";\nexport { CLIENT_MANIFEST_FILE, readAssetManifest, writeAssetManifest } from \"./manifest.ts\";\nexport type { LoadedPlugins, PluginContext, RamonyxPlugin } from \"./plugin.ts\";\nexport { definePlugin, loadPlugins } from \"./plugin.ts\";\nexport type {\n PrerenderOptions,\n PrerenderResult,\n PrerenderRouteInfo,\n} from \"./prerender.ts\";\nexport { prerenderRoutes } from \"./prerender.ts\";\n"]}
|
package/dist/server-only.js
CHANGED
|
@@ -46,7 +46,11 @@ export function serverOnlyPlugin() {
|
|
|
46
46
|
return {
|
|
47
47
|
name: "ramonyx-server-only",
|
|
48
48
|
enforce: "pre",
|
|
49
|
-
async resolveId(source, importer) {
|
|
49
|
+
async resolveId(source, importer, resolveOptions) {
|
|
50
|
+
// SSR/dev must load the real server module: only the browser graph gets the poison stub.
|
|
51
|
+
if (resolveOptions?.ssr === true) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
50
54
|
if (!SERVER_MODULE.test(source) || importer === undefined) {
|
|
51
55
|
return null;
|
|
52
56
|
}
|
package/dist/server-only.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-only.js","sourceRoot":"","sources":["../../../packages/bundler/src/server-only.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,EAAE;AACF,2FAA2F;AAC3F,2FAA2F;AAC3F,wDAAwD;AAExD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5C,MAAM,aAAa,GAAG,4BAA4B,CAAC;AACnD,MAAM,cAAc,GAAG,wBAAwB,CAAC;AAEhD,gFAAgF;AAChF,SAAS,aAAa,CAAC,MAAc;IACnC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,QAAQ,CACjC,8EAA8E,CAC/E,EAAE,CAAC;QACF,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;YAC3B,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EAAE,CAAC;QAC7D,KAAK,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;YACpD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACzB,SAAS;YACX,CAAC;YACD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YACxC,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;YACjD,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;gBAC1C,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;AAC3B,CAAC;AAED,SAAS,UAAU,CAAC,IAAY,EAAE,KAAwB;IACxD,MAAM,MAAM,GAAG,CAAC,IAAY,EAAU,EAAE,CACtC,4BAA4B,IAAI,CAAC,SAAS,CACxC,IAAI,IAAI,UAAU,IAAI,wGAAwG,CAC/H,OAAO,CAAC;IACX,MAAM,KAAK,GAAG;QACZ,+DAA+D;QAC/D,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,gBAAgB,IAAI,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;QACjE,kBAAkB,MAAM,CAAC,SAAS,CAAC,GAAG;KACvC,CAAC;IACF,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AACjC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO;QACL,IAAI,EAAE,qBAAqB;QAC3B,OAAO,EAAE,KAAK;QACd,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,QAAQ;
|
|
1
|
+
{"version":3,"file":"server-only.js","sourceRoot":"","sources":["../../../packages/bundler/src/server-only.ts"],"names":[],"mappings":"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","sourcesContent":["// Plugin Vite: modul `*.server.ts` diganti **stub** di bundle klien (ADR-0063).\n//\n// Pola \"server-only\": halaman boleh mengimpor modul server (dipakai `loader`/`action` yang\n// berjalan di server), tetapi bundle klien menerima stub yang melempar bila dipanggil dari\n// kode klien — bukan kebocoran implementasi/API server.\n\nimport { readFile } from \"node:fs/promises\";\nimport type { Plugin } from \"vite\";\n\nconst SERVER_MODULE = /\\.server\\.(ts|tsx|js|mjs)$/;\nconst VIRTUAL_PREFIX = \"\\0ramonyx-server-stub:\";\n\n/** Nama ekspor dari sumber server (regex ringan — tipe/interface diabaikan). */\nfunction exportedNames(source: string): string[] {\n const names = new Set<string>();\n for (const match of source.matchAll(\n /export\\s+(?:async\\s+)?(?:function|const|let|var|class)\\s+([A-Za-z_$][\\w$]*)/g,\n )) {\n if (match[1] !== undefined) {\n names.add(match[1]);\n }\n }\n for (const match of source.matchAll(/export\\s*\\{([^}]*)\\}/g)) {\n for (const part of (match[1] ?? \"\").split(\",\")) {\n const cleaned = part.trim().replace(/^type\\s+/, \"\");\n if (cleaned.length === 0) {\n continue;\n }\n const alias = cleaned.split(/\\s+as\\s+/);\n const name = (alias[1] ?? alias[0] ?? \"\").trim();\n if (name.length > 0 && name !== \"default\") {\n names.add(name);\n }\n }\n }\n return [...names].sort();\n}\n\nfunction stubSource(file: string, names: readonly string[]): string {\n const poison = (name: string): string =>\n `(() => { throw new Error(${JSON.stringify(\n `\"${name}\" dari ${file} hanya tersedia di server — impor modul ini dari loader/action/route API, bukan kode klien (ADR-0063).`,\n )}); })`;\n const lines = [\n \"// Stub server-only (digenerate @ramonyx/bundler — ADR-0063).\",\n ...names.map((name) => `export const ${name} = ${poison(name)};`),\n `export default ${poison(\"default\")};`,\n ];\n return `${lines.join(\"\\n\")}\\n`;\n}\n\n/**\n * Plugin untuk `buildClient`: setiap impor `*.server.ts` diresolusi ke stub yang melempar\n * bila dipanggil di browser.\n */\nexport function serverOnlyPlugin(): Plugin {\n return {\n name: \"ramonyx-server-only\",\n enforce: \"pre\",\n async resolveId(source, importer, resolveOptions) {\n // SSR/dev must load the real server module: only the browser graph gets the poison stub.\n if (resolveOptions?.ssr === true) {\n return null;\n }\n if (!SERVER_MODULE.test(source) || importer === undefined) {\n return null;\n }\n const resolved = await this.resolve(source, importer, { skipSelf: true });\n if (resolved === null) {\n return null;\n }\n return `${VIRTUAL_PREFIX}${resolved.id}`;\n },\n async load(id) {\n if (!id.startsWith(VIRTUAL_PREFIX)) {\n return null;\n }\n const file = id.slice(VIRTUAL_PREFIX.length);\n const source = await readFile(file, \"utf8\");\n return stubSource(file, exportedNames(source));\n },\n };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ramonyx/bundler",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Build pipeline for Ramonyx: Vite client bundles, edge builds, static prerender, and plugin hooks.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
"node": ">=24"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@ramonyx/adapter-runtime": "^2.0
|
|
23
|
-
"@ramonyx/compiler": "^2.0
|
|
24
|
-
"@ramonyx/core": "^2.0
|
|
22
|
+
"@ramonyx/adapter-runtime": "^2.1.0",
|
|
23
|
+
"@ramonyx/compiler": "^2.1.0",
|
|
24
|
+
"@ramonyx/core": "^2.1.0",
|
|
25
25
|
"vite": "8.3.4"
|
|
26
26
|
},
|
|
27
27
|
"publishConfig": {
|