@pracht/vite-plugin 0.0.0 → 0.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/README.md ADDED
@@ -0,0 +1,34 @@
1
+ # @pracht/vite-plugin
2
+
3
+ Vite integration for pracht. Handles virtual module generation, multi-environment builds, and SSG prerendering.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @pracht/vite-plugin
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```ts
14
+ // vite.config.ts
15
+ import { defineConfig } from "vite";
16
+ import pracht from "@pracht/vite-plugin";
17
+
18
+ export default defineConfig({
19
+ plugins: [pracht()],
20
+ });
21
+ ```
22
+
23
+ ## What It Does
24
+
25
+ - Generates virtual modules (`virtual:pracht/client`, `virtual:pracht/server`) from your route manifest
26
+ - Builds client and SSR bundles via Vite's multi-environment mode
27
+ - Pre-renders SSG and ISG routes at build time
28
+ - Provides HMR during development
29
+
30
+ ## Peer Dependencies
31
+
32
+ - `vite@^8.0.0`
33
+ - `@cloudflare/vite-plugin@^1.0.0` (optional, for Cloudflare targets)
34
+ - `wrangler@^4.81.0` (optional, for Cloudflare targets)
package/dist/index.d.mts CHANGED
@@ -44,6 +44,7 @@ declare function createPrachtClientModuleSource(options?: PrachtPluginOptions, b
44
44
  }): string;
45
45
  declare function createPrachtServerModuleSource(options?: PrachtPluginOptions, buildOptions?: {
46
46
  root?: string;
47
+ isBuild?: boolean;
47
48
  }): string;
48
49
  declare function createPrachtRegistryModuleSource(options?: PrachtPluginOptions): string;
49
50
  //#endregion
package/dist/index.mjs CHANGED
@@ -71,6 +71,7 @@ async function pracht(options = {}) {
71
71
  const isPagesMode = !!resolved.pagesDir;
72
72
  let root = process.cwd();
73
73
  if (isPagesMode && options.appFile) console.warn("[pracht] Both `pagesDir` and `appFile` are set. `pagesDir` takes precedence — `appFile` will be ignored.");
74
+ let isBuild = false;
74
75
  const prachtPlugin = {
75
76
  name: "pracht",
76
77
  enforce: "pre",
@@ -84,6 +85,7 @@ async function pracht(options = {}) {
84
85
  },
85
86
  configResolved(config) {
86
87
  root = config.root;
88
+ isBuild = config.command === "build";
87
89
  },
88
90
  resolveId(id) {
89
91
  if (isClientModule(id)) return PRACHT_CLIENT_MODULE_ID;
@@ -92,9 +94,21 @@ async function pracht(options = {}) {
92
94
  },
93
95
  load(id) {
94
96
  if (isClientModule(id)) return createPrachtClientModuleSource(resolved, { root });
95
- if (isServerModule(id)) return createPrachtServerModuleSource(resolved, { root });
97
+ if (isServerModule(id)) return createPrachtServerModuleSource(resolved, {
98
+ root,
99
+ isBuild
100
+ });
96
101
  return null;
97
102
  },
103
+ transform(code, id) {
104
+ if (id !== resolve(root, resolved.appFile.slice(1))) return null;
105
+ const transformed = code.replace(/\(\)\s*=>\s*import\(\s*(['"])([^'"]+)\1\s*\)/g, "$1$2$1");
106
+ if (transformed === code) return null;
107
+ return {
108
+ code: transformed,
109
+ map: null
110
+ };
111
+ },
98
112
  configureServer(server) {
99
113
  if (isPagesMode) {
100
114
  const abs = resolve(root, resolved.pagesDir.slice(1));
@@ -186,10 +200,14 @@ function createPrachtServerModuleSource(options = {}, buildOptions = {}) {
186
200
  const resolved = resolveOptions(options);
187
201
  const isPagesMode = !!resolved.pagesDir;
188
202
  const registrySource = createPrachtRegistryModuleSource(resolved);
189
- const clientBuild = readClientBuildAssets(buildOptions.root);
203
+ const clientBuild = buildOptions.isBuild ? readClientBuildAssets(buildOptions.root) : {
204
+ clientEntryUrl: null,
205
+ cssManifest: {},
206
+ jsManifest: {}
207
+ };
190
208
  const adapter = resolved.adapter;
191
209
  const source = [
192
- adapter?.serverImports ? adapter.serverImports : "import { resolveApp, resolveApiRoutes } from \"@pracht/core\";",
210
+ adapter?.serverImports ? adapter.serverImports + "\nimport { prerenderApp } from \"@pracht/core\";" : "import { resolveApp, resolveApiRoutes, prerenderApp } from \"@pracht/core\";",
193
211
  isPagesMode ? generatePagesAppInlineSource(resolved, buildOptions.root) : `import { app } from ${JSON.stringify(resolved.appFile)};`,
194
212
  "",
195
213
  registrySource,
@@ -200,6 +218,7 @@ function createPrachtServerModuleSource(options = {}, buildOptions = {}) {
200
218
  `export const clientEntryUrl = ${JSON.stringify(clientBuild.clientEntryUrl ?? CLIENT_BROWSER_PATH)};`,
201
219
  `export const cssManifest = ${JSON.stringify(clientBuild.cssManifest)};`,
202
220
  `export const jsManifest = ${JSON.stringify(clientBuild.jsManifest)};`,
221
+ "export { prerenderApp };",
203
222
  ""
204
223
  ];
205
224
  if (adapter) source.push(adapter.createServerEntryModule());
@@ -255,6 +274,7 @@ function createDevSSRMiddleware(server, _pluginOptions) {
255
274
  app: serverMod.resolvedApp,
256
275
  registry: serverMod.registry,
257
276
  request: webRequest,
277
+ debugErrors: true,
258
278
  clientEntryUrl: CLIENT_BROWSER_PATH,
259
279
  apiRoutes: serverMod.apiRoutes
260
280
  });
@@ -297,7 +317,7 @@ function createDevSSRMiddleware(server, _pluginOptions) {
297
317
  }
298
318
  const BODYLESS_METHODS = new Set(["GET", "HEAD"]);
299
319
  async function nodeToWebRequest(req) {
300
- const protocol = (Array.isArray(req.headers["x-forwarded-proto"]) ? req.headers["x-forwarded-proto"][0] : req.headers["x-forwarded-proto"]) ?? "http";
320
+ const protocol = "http";
301
321
  const host = req.headers.host ?? "localhost";
302
322
  const url = new URL(req.url ?? "/", `${protocol}://${host}`);
303
323
  const method = req.method ?? "GET";
@@ -17,6 +17,7 @@ declare function filePathToRoutePath(relativePath: string): string;
17
17
  declare function sortRoutes(pages: ScannedPage[]): ScannedPage[];
18
18
  declare function generatePagesManifestSource(pages: ScannedPage[], options: PagesRouterOptions & {
19
19
  pagesDirPrefix?: string;
20
+ useImportSyntax?: boolean;
20
21
  }): string;
21
22
  declare function generateRoutesFile(pagesDir: string, outputPath: string, options: PagesRouterOptions): void;
22
23
  //#endregion
@@ -71,19 +71,22 @@ function generatePagesManifestSource(pages, options) {
71
71
  const pagesDir = options.pagesDir;
72
72
  const defaultRender = options.pagesDefaultRender ?? "ssr";
73
73
  const prefix = options.pagesDirPrefix;
74
+ const useImport = options.useImportSyntax ?? false;
74
75
  const appFile = scanAllFiles(pagesDir).find((f) => basename(f, extname(f)) === "_app" && PAGE_EXTENSIONS.has(extname(f)));
75
76
  const lines = ["import { defineApp, group, route } from \"@pracht/core\";", ""];
76
77
  const routeEntries = [];
77
78
  for (const page of pages) {
78
79
  const render = page.renderMode ?? defaultRender;
79
80
  const filePath = prefix ? `${prefix}/${page.relativePath.replace(/\\/g, "/")}` : `./${page.relativePath.replace(/\\/g, "/")}`;
80
- routeEntries.push(` route(${JSON.stringify(page.routePath)}, ${JSON.stringify(filePath)}, { render: ${JSON.stringify(render)} })`);
81
+ const fileRef = useImport ? `() => import(${JSON.stringify(filePath)})` : JSON.stringify(filePath);
82
+ routeEntries.push(` route(${JSON.stringify(page.routePath)}, ${fileRef}, { render: ${JSON.stringify(render)} })`);
81
83
  }
82
84
  if (appFile) {
83
85
  const appPath = prefix ? `${prefix}/_app.${extname(appFile).slice(1)}` : `./${relative(join(pagesDir, ".."), appFile).replace(/\\/g, "/")}`;
86
+ const shellRef = useImport ? `() => import(${JSON.stringify(appPath)})` : JSON.stringify(appPath);
84
87
  lines.push("const app = defineApp({");
85
88
  lines.push(" shells: {");
86
- lines.push(` pages: ${JSON.stringify(appPath)},`);
89
+ lines.push(` pages: ${shellRef},`);
87
90
  lines.push(" },");
88
91
  lines.push(" routes: [");
89
92
  lines.push(` group({ shell: "pages" }, [`);
@@ -121,7 +124,10 @@ function generateRoutesFile(pagesDir, outputPath, options) {
121
124
  "// Auto-generated from pages/ directory by @pracht/vite-plugin.",
122
125
  "// Customize this file and remove `pagesDir` from pracht config to use it directly.",
123
126
  "",
124
- generatePagesManifestSource(scanPagesDirectory(pagesDir), options).replace("const app = defineApp(", "export const app = defineApp(")
127
+ generatePagesManifestSource(scanPagesDirectory(pagesDir), {
128
+ ...options,
129
+ useImportSyntax: true
130
+ }).replace("const app = defineApp(", "export const app = defineApp(")
125
131
  ].join("\n"), "utf-8");
126
132
  }
127
133
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,15 @@
1
1
  {
2
2
  "name": "@pracht/vite-plugin",
3
- "version": "0.0.0",
3
+ "version": "0.1.0",
4
+ "homepage": "https://github.com/JoviDeCroock/pracht/tree/main/packages/vite-plugin",
5
+ "bugs": {
6
+ "url": "https://github.com/JoviDeCroock/pracht/issues"
7
+ },
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/JoviDeCroock/pracht",
11
+ "directory": "packages/vite-plugin"
12
+ },
4
13
  "files": [
5
14
  "dist"
6
15
  ],
@@ -15,11 +24,14 @@
15
24
  "default": "./dist/pages-router.mjs"
16
25
  }
17
26
  },
27
+ "publishConfig": {
28
+ "provenance": true
29
+ },
18
30
  "dependencies": {
19
31
  "@preact/preset-vite": "^2.10.5",
20
- "@pracht/adapter-cloudflare": "0.0.0",
21
- "@pracht/core": "0.0.0",
22
- "@pracht/adapter-vercel": "0.0.0"
32
+ "@pracht/adapter-cloudflare": "0.0.2",
33
+ "@pracht/adapter-vercel": "0.0.2",
34
+ "@pracht/core": "0.1.0"
23
35
  },
24
36
  "peerDependencies": {
25
37
  "@cloudflare/vite-plugin": "^1.0.0",