@buzola/vite-plugin 0.0.11 → 0.0.12

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.
Files changed (76) hide show
  1. package/dist/__tests__/plugin.test.d.ts +2 -0
  2. package/dist/__tests__/plugin.test.d.ts.map +1 -0
  3. package/dist/__tests__/plugin.test.js +110 -0
  4. package/dist/__tests__/plugin.test.js.map +1 -0
  5. package/dist/index.d.ts +0 -14
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +0 -7
  8. package/dist/index.js.map +1 -1
  9. package/dist/plugin.d.ts +2 -20
  10. package/dist/plugin.d.ts.map +1 -1
  11. package/dist/plugin.js +12 -31
  12. package/dist/plugin.js.map +1 -1
  13. package/package.json +3 -5
  14. package/src/__tests__/plugin.test.ts +129 -0
  15. package/src/index.ts +0 -21
  16. package/src/plugin.ts +22 -56
  17. package/dist/__tests__/codegen.test.d.ts +0 -2
  18. package/dist/__tests__/codegen.test.d.ts.map +0 -1
  19. package/dist/__tests__/codegen.test.js +0 -208
  20. package/dist/__tests__/codegen.test.js.map +0 -1
  21. package/dist/__tests__/conventions.test.d.ts +0 -2
  22. package/dist/__tests__/conventions.test.d.ts.map +0 -1
  23. package/dist/__tests__/conventions.test.js +0 -80
  24. package/dist/__tests__/conventions.test.js.map +0 -1
  25. package/dist/__tests__/page-extractor.test.d.ts +0 -2
  26. package/dist/__tests__/page-extractor.test.d.ts.map +0 -1
  27. package/dist/__tests__/page-extractor.test.js +0 -82
  28. package/dist/__tests__/page-extractor.test.js.map +0 -1
  29. package/dist/__tests__/tree-builder.test.d.ts +0 -2
  30. package/dist/__tests__/tree-builder.test.d.ts.map +0 -1
  31. package/dist/__tests__/tree-builder.test.js +0 -474
  32. package/dist/__tests__/tree-builder.test.js.map +0 -1
  33. package/dist/cli.d.ts +0 -3
  34. package/dist/cli.d.ts.map +0 -1
  35. package/dist/cli.js +0 -39
  36. package/dist/cli.js.map +0 -1
  37. package/dist/config.d.ts +0 -20
  38. package/dist/config.d.ts.map +0 -1
  39. package/dist/config.js +0 -20
  40. package/dist/config.js.map +0 -1
  41. package/dist/conventions.d.ts +0 -53
  42. package/dist/conventions.d.ts.map +0 -1
  43. package/dist/conventions.js +0 -82
  44. package/dist/conventions.js.map +0 -1
  45. package/dist/generate.d.ts +0 -26
  46. package/dist/generate.d.ts.map +0 -1
  47. package/dist/generate.js +0 -44
  48. package/dist/generate.js.map +0 -1
  49. package/dist/generator/codegen.d.ts +0 -19
  50. package/dist/generator/codegen.d.ts.map +0 -1
  51. package/dist/generator/codegen.js +0 -170
  52. package/dist/generator/codegen.js.map +0 -1
  53. package/dist/generator/page-extractor.d.ts +0 -21
  54. package/dist/generator/page-extractor.d.ts.map +0 -1
  55. package/dist/generator/page-extractor.js +0 -23
  56. package/dist/generator/page-extractor.js.map +0 -1
  57. package/dist/generator/scanner.d.ts +0 -11
  58. package/dist/generator/scanner.d.ts.map +0 -1
  59. package/dist/generator/scanner.js +0 -34
  60. package/dist/generator/scanner.js.map +0 -1
  61. package/dist/generator/tree-builder.d.ts +0 -54
  62. package/dist/generator/tree-builder.d.ts.map +0 -1
  63. package/dist/generator/tree-builder.js +0 -364
  64. package/dist/generator/tree-builder.js.map +0 -1
  65. package/src/__tests__/codegen.test.ts +0 -229
  66. package/src/__tests__/conventions.test.ts +0 -93
  67. package/src/__tests__/page-extractor.test.ts +0 -95
  68. package/src/__tests__/tree-builder.test.ts +0 -554
  69. package/src/cli.ts +0 -43
  70. package/src/config.ts +0 -35
  71. package/src/conventions.ts +0 -116
  72. package/src/generate.ts +0 -64
  73. package/src/generator/codegen.ts +0 -221
  74. package/src/generator/page-extractor.ts +0 -48
  75. package/src/generator/scanner.ts +0 -45
  76. package/src/generator/tree-builder.ts +0 -454
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=plugin.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/plugin.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,110 @@
1
+ import { describe, expect, it } from 'bun:test';
2
+ import * as fs from 'node:fs';
3
+ import * as os from 'node:os';
4
+ import * as path from 'node:path';
5
+ import { build } from 'vite';
6
+ import { buzolaPlugin } from '../plugin.js';
7
+ function makeEmptyRoutesFixture() {
8
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'buzola-vite-test-'));
9
+ fs.mkdirSync(path.join(root, 'routes'));
10
+ return { root, cleanup: () => fs.rmSync(root, { recursive: true, force: true }) };
11
+ }
12
+ function writeEntry(root, body) {
13
+ const entryPath = path.join(root, 'entry.ts');
14
+ fs.writeFileSync(entryPath, body);
15
+ return entryPath;
16
+ }
17
+ describe('buzolaPlugin (Vite)', () => {
18
+ it('vite build resolves virtual:buzola/routes through the plugin', async () => {
19
+ const { root, cleanup } = makeEmptyRoutesFixture();
20
+ try {
21
+ const entryPath = writeEntry(root, `import { routes, pageRegistry } from 'virtual:buzola/routes'\nexport { routes, pageRegistry }\n`);
22
+ const result = await build({
23
+ root,
24
+ plugins: [buzolaPlugin({ routesDir: 'routes', output: 'buzola.gen.ts' })],
25
+ build: {
26
+ lib: { entry: entryPath, formats: ['es'], fileName: 'bundle' },
27
+ outDir: path.join(root, 'dist'),
28
+ write: false,
29
+ rollupOptions: { external: ['react', '@buzola/router'] },
30
+ },
31
+ logLevel: 'silent',
32
+ });
33
+ const chunk = result[0].output.find((o) => o.type === 'chunk');
34
+ expect(chunk).toBeDefined();
35
+ expect(chunk.code).toContain('pageRegistry');
36
+ expect(chunk.code).toContain('buildRouteTree');
37
+ }
38
+ finally {
39
+ cleanup();
40
+ }
41
+ });
42
+ it('vite build resolves named virtual module ID', async () => {
43
+ const { root, cleanup } = makeEmptyRoutesFixture();
44
+ try {
45
+ const entryPath = writeEntry(root, `import { routes, pageRegistry } from 'virtual:buzola/admin/routes'\nexport { routes, pageRegistry }\n`);
46
+ const result = await build({
47
+ root,
48
+ plugins: [buzolaPlugin({ name: 'admin', routesDir: 'routes', output: 'buzola.gen.ts' })],
49
+ build: {
50
+ lib: { entry: entryPath, formats: ['es'], fileName: 'bundle' },
51
+ outDir: path.join(root, 'dist'),
52
+ write: false,
53
+ rollupOptions: { external: ['react', '@buzola/router'] },
54
+ },
55
+ logLevel: 'silent',
56
+ });
57
+ const chunk = result[0].output.find((o) => o.type === 'chunk');
58
+ expect(chunk).toBeDefined();
59
+ expect(chunk.code).toContain('pageRegistry');
60
+ }
61
+ finally {
62
+ cleanup();
63
+ }
64
+ });
65
+ it('writes buzola.gen.ts during vite build', async () => {
66
+ const { root, cleanup } = makeEmptyRoutesFixture();
67
+ try {
68
+ const entryPath = writeEntry(root, `export const x = 1\n`);
69
+ const outputPath = path.join(root, 'buzola.gen.ts');
70
+ expect(fs.existsSync(outputPath)).toBe(false);
71
+ await build({
72
+ root,
73
+ plugins: [buzolaPlugin({ routesDir: 'routes', output: 'buzola.gen.ts' })],
74
+ build: {
75
+ lib: { entry: entryPath, formats: ['es'], fileName: 'bundle' },
76
+ outDir: path.join(root, 'dist'),
77
+ write: false,
78
+ },
79
+ logLevel: 'silent',
80
+ });
81
+ expect(fs.existsSync(outputPath)).toBe(true);
82
+ expect(fs.readFileSync(outputPath, 'utf-8')).toContain('pageRegistry');
83
+ }
84
+ finally {
85
+ cleanup();
86
+ }
87
+ });
88
+ it('vite build succeeds when routes dir does not exist', async () => {
89
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'buzola-vite-test-'));
90
+ try {
91
+ const entryPath = writeEntry(root, `export const x = 1\n`);
92
+ const result = await build({
93
+ root,
94
+ plugins: [buzolaPlugin({ routesDir: 'nonexistent', output: 'buzola.gen.ts' })],
95
+ build: {
96
+ lib: { entry: entryPath, formats: ['es'], fileName: 'bundle' },
97
+ outDir: path.join(root, 'dist'),
98
+ write: false,
99
+ },
100
+ logLevel: 'silent',
101
+ });
102
+ expect(result[0].output.length).toBeGreaterThan(0);
103
+ expect(fs.existsSync(path.join(root, 'buzola.gen.ts'))).toBe(false);
104
+ }
105
+ finally {
106
+ fs.rmSync(root, { recursive: true, force: true });
107
+ }
108
+ });
109
+ });
110
+ //# sourceMappingURL=plugin.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.test.js","sourceRoot":"","sources":["../../src/__tests__/plugin.test.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,17 +1,3 @@
1
1
  export { buzolaPlugin } from './plugin.js';
2
2
  export type { BuzolaPluginOptions } from './plugin.js';
3
- export { generate } from './generate.js';
4
- export type { GenerateOptions } from './generate.js';
5
- export { loadConfig } from './config.js';
6
- export type { BuzolaConfig } from './config.js';
7
- export { scanRouteFiles } from './generator/scanner.js';
8
- export type { ScannedFile } from './generator/scanner.js';
9
- export { buildFileRouteTree } from './generator/tree-builder.js';
10
- export type { FileRouteNode, PageExportInfo } from './generator/tree-builder.js';
11
- export { generateRouteModule } from './generator/codegen.js';
12
- export type { CodegenOptions } from './generator/codegen.js';
13
- export { extractPages } from './generator/page-extractor.js';
14
- export type { ExtractedPage, ExtractedParam, ModuleLoader } from './generator/page-extractor.js';
15
- export { isRouteFile, parseDirName, parseFileName, parseRouteFile } from './conventions.js';
16
- export type { ParsedRouteFile } from './conventions.js';
17
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,YAAY,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AAEtD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAEpD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE/C,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AACvD,YAAY,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAEzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAA;AAChE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAEhF,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAC5D,YAAY,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAE5D,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAA;AAC5D,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAA;AAEhG,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAC3F,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,YAAY,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA"}
package/dist/index.js CHANGED
@@ -1,9 +1,2 @@
1
1
  export { buzolaPlugin } from './plugin.js';
2
- export { generate } from './generate.js';
3
- export { loadConfig } from './config.js';
4
- export { scanRouteFiles } from './generator/scanner.js';
5
- export { buildFileRouteTree } from './generator/tree-builder.js';
6
- export { generateRouteModule } from './generator/codegen.js';
7
- export { extractPages } from './generator/page-extractor.js';
8
- export { isRouteFile, parseDirName, parseFileName, parseRouteFile } from './conventions.js';
9
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAG1C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAGxC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAGxC,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAGvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAA;AAGhE,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAG5D,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAA;AAG5D,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA"}
package/dist/plugin.d.ts CHANGED
@@ -1,24 +1,6 @@
1
+ import { type BasePluginOptions } from '@buzola/codegen';
1
2
  import type { Plugin } from 'vite';
2
- export interface BuzolaPluginOptions {
3
- /**
4
- * Unique name for this plugin instance. Required when registering multiple
5
- * entrypoints in the same Vite config. Affects the plugin name
6
- * (`buzola:${name}`) and the virtual module ID (`virtual:buzola/${name}/routes`).
7
- *
8
- * When omitted, the plugin uses `buzola` as its name and
9
- * `virtual:buzola/routes` as the virtual module ID.
10
- */
11
- name?: string;
12
- /** Path to routes directory, relative to project root. Defaults to "src/routes". */
13
- routesDir?: string;
14
- /** Path to output generated file, relative to project root. Defaults to "src/buzola.gen.ts". */
15
- output?: string;
16
- /**
17
- * Parameter names that should be persistent across navigations.
18
- * When set, generates a BuzolaPersistentParams type augmentation
19
- * so these params become optional in Link and navigate() calls.
20
- */
21
- persistentParams?: string[];
3
+ export interface BuzolaPluginOptions extends BasePluginOptions {
22
4
  }
23
5
  /**
24
6
  * Vite plugin for Buzola page-centric routing.
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAiB,MAAM,MAAM,CAAA;AAIjD,MAAM,WAAW,mBAAmB;IACnC;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,oFAAoF;IACpF,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gGAAgG;IAChG,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;CAC3B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,MAAM,CAqFtE"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,iBAAiB,EAOtB,MAAM,iBAAiB,CAAA;AAExB,OAAO,KAAK,EAAE,MAAM,EAAiB,MAAM,MAAM,CAAA;AAEjD,MAAM,WAAW,mBAAoB,SAAQ,iBAAiB;CAAG;AAEjE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,MAAM,CAiEtE"}
package/dist/plugin.js CHANGED
@@ -1,7 +1,5 @@
1
- import * as fs from 'node:fs';
1
+ import { buildVirtualSource, generate, isRouteFile, resolveOptions, resolveVirtualModuleId, } from '@buzola/codegen';
2
2
  import * as path from 'node:path';
3
- import { loadConfig } from './config.js';
4
- import { generate } from './generate.js';
5
3
  /**
6
4
  * Vite plugin for Buzola page-centric routing.
7
5
  *
@@ -17,48 +15,35 @@ import { generate } from './generate.js';
17
15
  * Plugin options take precedence over the config file.
18
16
  */
19
17
  export function buzolaPlugin(options = {}) {
20
- const { name: nameOption } = options;
21
- const pluginName = nameOption ? `buzola:${nameOption}` : 'buzola';
22
- const virtualModuleId = nameOption ? `virtual:buzola/${nameOption}/routes` : 'virtual:buzola/routes';
23
- const resolvedVirtualId = '\0' + virtualModuleId;
24
- let root;
18
+ const { pluginName, id: virtualId } = resolveVirtualModuleId(options.name);
19
+ const resolvedVirtualId = '\0' + virtualId;
25
20
  let baseOptions;
21
+ let virtualSource;
26
22
  let server;
27
23
  return {
28
24
  name: pluginName,
29
25
  enforce: 'pre',
30
26
  async configResolved(config) {
31
- root = config.root;
32
- const fileConfig = await loadConfig(root);
33
- const routesDir = options.routesDir ?? fileConfig.routesDir ?? 'src/routes';
34
- const output = options.output ?? fileConfig.output ?? 'src/buzola.gen.ts';
35
- const persistentParams = options.persistentParams ?? fileConfig.persistentParams;
36
- baseOptions = {
37
- routesDir: path.resolve(root, routesDir),
38
- outputPath: path.resolve(root, output),
39
- persistentParams,
40
- };
27
+ baseOptions = await resolveOptions({ ...options, root: config.root });
28
+ virtualSource = buildVirtualSource(baseOptions.outputPath);
41
29
  },
42
30
  configureServer(srv) {
43
31
  server = srv;
44
32
  },
45
33
  async buildStart() {
46
- if (!fs.existsSync(baseOptions.routesDir))
47
- return;
48
34
  if (server) {
49
- await generate({ ...baseOptions, moduleLoader: (p) => server.ssrLoadModule(p) });
35
+ await generate({ ...baseOptions, optional: true, moduleLoader: (p) => server.ssrLoadModule(p) });
50
36
  }
51
37
  else {
52
- // Production build — create a temporary Vite server for module loading
53
38
  const { createServer } = await import('vite');
54
39
  const tempServer = await createServer({
55
- root,
40
+ root: baseOptions.root,
56
41
  server: { middlewareMode: true },
57
42
  logLevel: 'silent',
58
43
  optimizeDeps: { noDiscovery: true },
59
44
  });
60
45
  try {
61
- await generate({ ...baseOptions, moduleLoader: (p) => tempServer.ssrLoadModule(p) });
46
+ await generate({ ...baseOptions, optional: true, moduleLoader: (p) => tempServer.ssrLoadModule(p) });
62
47
  }
63
48
  finally {
64
49
  await tempServer.close();
@@ -66,25 +51,21 @@ export function buzolaPlugin(options = {}) {
66
51
  }
67
52
  },
68
53
  resolveId(id) {
69
- if (id === virtualModuleId) {
54
+ if (id === virtualId) {
70
55
  return resolvedVirtualId;
71
56
  }
72
57
  },
73
58
  load(id) {
74
59
  if (id === resolvedVirtualId) {
75
- return `export { routes, pageRegistry } from '${baseOptions.outputPath.replace(/\.ts$/, '')}';\n`;
60
+ return virtualSource;
76
61
  }
77
62
  },
78
63
  async handleHotUpdate({ file }) {
79
- if (!file.startsWith(baseOptions.routesDir) || !server)
64
+ if (!server || !file.startsWith(baseOptions.routesDir) || !isRouteFile(path.basename(file)))
80
65
  return;
81
66
  const changed = await generate({ ...baseOptions, moduleLoader: (p) => server.ssrLoadModule(p) });
82
67
  if (!changed)
83
68
  return;
84
- // Invalidate the virtual module so Vite re-evaluates it.
85
- // Vite propagates the update through the import chain — if the app
86
- // supports HMR for the route tree, no full-page reload is needed.
87
- // If not, Vite falls back to full-reload automatically.
88
69
  const mod = server.moduleGraph.getModuleById(resolvedVirtualId);
89
70
  if (mod) {
90
71
  server.moduleGraph.invalidateModule(mod);
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,12 +1,9 @@
1
1
  {
2
2
  "name": "@buzola/vite-plugin",
3
- "version": "0.0.11",
3
+ "version": "0.0.12",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
7
- "bin": {
8
- "buzola": "./dist/cli.js"
9
- },
10
7
  "exports": {
11
8
  ".": {
12
9
  "bun": "./src/index.ts",
@@ -24,7 +21,8 @@
24
21
  "directory": "packages/vite-plugin"
25
22
  },
26
23
  "dependencies": {
27
- "@buzola/router": "^0.0.11"
24
+ "@buzola/codegen": "^0.0.12",
25
+ "@buzola/router": "^0.0.12"
28
26
  },
29
27
  "devDependencies": {
30
28
  "@types/node": "^25.3.3",
@@ -0,0 +1,129 @@
1
+ import { describe, expect, it } from 'bun:test'
2
+ import * as fs from 'node:fs'
3
+ import * as os from 'node:os'
4
+ import * as path from 'node:path'
5
+ import { build } from 'vite'
6
+ import { buzolaPlugin } from '../plugin.js'
7
+
8
+ // vite's build() returns RollupOutput[] (one per format) for non-watch builds.
9
+ // RollupOutput isn't re-exported from 'vite', so we declare a minimal shape here.
10
+ type BuildResult = { output: { type: string; code?: string }[] }[]
11
+
12
+ function makeEmptyRoutesFixture(): { root: string; cleanup: () => void } {
13
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'buzola-vite-test-'))
14
+ fs.mkdirSync(path.join(root, 'routes'))
15
+ return { root, cleanup: () => fs.rmSync(root, { recursive: true, force: true }) }
16
+ }
17
+
18
+ function writeEntry(root: string, body: string): string {
19
+ const entryPath = path.join(root, 'entry.ts')
20
+ fs.writeFileSync(entryPath, body)
21
+ return entryPath
22
+ }
23
+
24
+ describe('buzolaPlugin (Vite)', () => {
25
+ it('vite build resolves virtual:buzola/routes through the plugin', async () => {
26
+ const { root, cleanup } = makeEmptyRoutesFixture()
27
+ try {
28
+ const entryPath = writeEntry(
29
+ root,
30
+ `import { routes, pageRegistry } from 'virtual:buzola/routes'\nexport { routes, pageRegistry }\n`,
31
+ )
32
+
33
+ const result = await build({
34
+ root,
35
+ plugins: [buzolaPlugin({ routesDir: 'routes', output: 'buzola.gen.ts' })],
36
+ build: {
37
+ lib: { entry: entryPath, formats: ['es'], fileName: 'bundle' },
38
+ outDir: path.join(root, 'dist'),
39
+ write: false,
40
+ rollupOptions: { external: ['react', '@buzola/router'] },
41
+ },
42
+ logLevel: 'silent',
43
+ }) as BuildResult
44
+
45
+ const chunk = result[0]!.output.find((o) => o.type === 'chunk')
46
+ expect(chunk).toBeDefined()
47
+ expect(chunk!.code).toContain('pageRegistry')
48
+ expect(chunk!.code).toContain('buildRouteTree')
49
+ } finally {
50
+ cleanup()
51
+ }
52
+ })
53
+
54
+ it('vite build resolves named virtual module ID', async () => {
55
+ const { root, cleanup } = makeEmptyRoutesFixture()
56
+ try {
57
+ const entryPath = writeEntry(
58
+ root,
59
+ `import { routes, pageRegistry } from 'virtual:buzola/admin/routes'\nexport { routes, pageRegistry }\n`,
60
+ )
61
+
62
+ const result = await build({
63
+ root,
64
+ plugins: [buzolaPlugin({ name: 'admin', routesDir: 'routes', output: 'buzola.gen.ts' })],
65
+ build: {
66
+ lib: { entry: entryPath, formats: ['es'], fileName: 'bundle' },
67
+ outDir: path.join(root, 'dist'),
68
+ write: false,
69
+ rollupOptions: { external: ['react', '@buzola/router'] },
70
+ },
71
+ logLevel: 'silent',
72
+ }) as BuildResult
73
+
74
+ const chunk = result[0]!.output.find((o) => o.type === 'chunk')
75
+ expect(chunk).toBeDefined()
76
+ expect(chunk!.code).toContain('pageRegistry')
77
+ } finally {
78
+ cleanup()
79
+ }
80
+ })
81
+
82
+ it('writes buzola.gen.ts during vite build', async () => {
83
+ const { root, cleanup } = makeEmptyRoutesFixture()
84
+ try {
85
+ const entryPath = writeEntry(root, `export const x = 1\n`)
86
+ const outputPath = path.join(root, 'buzola.gen.ts')
87
+ expect(fs.existsSync(outputPath)).toBe(false)
88
+
89
+ await build({
90
+ root,
91
+ plugins: [buzolaPlugin({ routesDir: 'routes', output: 'buzola.gen.ts' })],
92
+ build: {
93
+ lib: { entry: entryPath, formats: ['es'], fileName: 'bundle' },
94
+ outDir: path.join(root, 'dist'),
95
+ write: false,
96
+ },
97
+ logLevel: 'silent',
98
+ })
99
+
100
+ expect(fs.existsSync(outputPath)).toBe(true)
101
+ expect(fs.readFileSync(outputPath, 'utf-8')).toContain('pageRegistry')
102
+ } finally {
103
+ cleanup()
104
+ }
105
+ })
106
+
107
+ it('vite build succeeds when routes dir does not exist', async () => {
108
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'buzola-vite-test-'))
109
+ try {
110
+ const entryPath = writeEntry(root, `export const x = 1\n`)
111
+
112
+ const result = await build({
113
+ root,
114
+ plugins: [buzolaPlugin({ routesDir: 'nonexistent', output: 'buzola.gen.ts' })],
115
+ build: {
116
+ lib: { entry: entryPath, formats: ['es'], fileName: 'bundle' },
117
+ outDir: path.join(root, 'dist'),
118
+ write: false,
119
+ },
120
+ logLevel: 'silent',
121
+ }) as BuildResult
122
+
123
+ expect(result[0]!.output.length).toBeGreaterThan(0)
124
+ expect(fs.existsSync(path.join(root, 'buzola.gen.ts'))).toBe(false)
125
+ } finally {
126
+ fs.rmSync(root, { recursive: true, force: true })
127
+ }
128
+ })
129
+ })
package/src/index.ts CHANGED
@@ -1,23 +1,2 @@
1
1
  export { buzolaPlugin } from './plugin.js'
2
2
  export type { BuzolaPluginOptions } from './plugin.js'
3
-
4
- export { generate } from './generate.js'
5
- export type { GenerateOptions } from './generate.js'
6
-
7
- export { loadConfig } from './config.js'
8
- export type { BuzolaConfig } from './config.js'
9
-
10
- export { scanRouteFiles } from './generator/scanner.js'
11
- export type { ScannedFile } from './generator/scanner.js'
12
-
13
- export { buildFileRouteTree } from './generator/tree-builder.js'
14
- export type { FileRouteNode, PageExportInfo } from './generator/tree-builder.js'
15
-
16
- export { generateRouteModule } from './generator/codegen.js'
17
- export type { CodegenOptions } from './generator/codegen.js'
18
-
19
- export { extractPages } from './generator/page-extractor.js'
20
- export type { ExtractedPage, ExtractedParam, ModuleLoader } from './generator/page-extractor.js'
21
-
22
- export { isRouteFile, parseDirName, parseFileName, parseRouteFile } from './conventions.js'
23
- export type { ParsedRouteFile } from './conventions.js'
package/src/plugin.ts CHANGED
@@ -1,30 +1,16 @@
1
- import * as fs from 'node:fs'
1
+ import {
2
+ type BasePluginOptions,
3
+ buildVirtualSource,
4
+ generate,
5
+ isRouteFile,
6
+ type ResolvedOptions,
7
+ resolveOptions,
8
+ resolveVirtualModuleId,
9
+ } from '@buzola/codegen'
2
10
  import * as path from 'node:path'
3
11
  import type { Plugin, ViteDevServer } from 'vite'
4
- import { loadConfig } from './config.js'
5
- import { generate, type GenerateOptions } from './generate.js'
6
12
 
7
- export interface BuzolaPluginOptions {
8
- /**
9
- * Unique name for this plugin instance. Required when registering multiple
10
- * entrypoints in the same Vite config. Affects the plugin name
11
- * (`buzola:${name}`) and the virtual module ID (`virtual:buzola/${name}/routes`).
12
- *
13
- * When omitted, the plugin uses `buzola` as its name and
14
- * `virtual:buzola/routes` as the virtual module ID.
15
- */
16
- name?: string
17
- /** Path to routes directory, relative to project root. Defaults to "src/routes". */
18
- routesDir?: string
19
- /** Path to output generated file, relative to project root. Defaults to "src/buzola.gen.ts". */
20
- output?: string
21
- /**
22
- * Parameter names that should be persistent across navigations.
23
- * When set, generates a BuzolaPersistentParams type augmentation
24
- * so these params become optional in Link and navigate() calls.
25
- */
26
- persistentParams?: string[]
27
- }
13
+ export interface BuzolaPluginOptions extends BasePluginOptions {}
28
14
 
29
15
  /**
30
16
  * Vite plugin for Buzola page-centric routing.
@@ -41,14 +27,11 @@ export interface BuzolaPluginOptions {
41
27
  * Plugin options take precedence over the config file.
42
28
  */
43
29
  export function buzolaPlugin(options: BuzolaPluginOptions = {}): Plugin {
44
- const { name: nameOption } = options
45
-
46
- const pluginName = nameOption ? `buzola:${nameOption}` : 'buzola'
47
- const virtualModuleId = nameOption ? `virtual:buzola/${nameOption}/routes` : 'virtual:buzola/routes'
48
- const resolvedVirtualId = '\0' + virtualModuleId
30
+ const { pluginName, id: virtualId } = resolveVirtualModuleId(options.name)
31
+ const resolvedVirtualId = '\0' + virtualId
49
32
 
50
- let root: string
51
- let baseOptions: Omit<GenerateOptions, 'moduleLoader'>
33
+ let baseOptions: ResolvedOptions
34
+ let virtualSource: string
52
35
  let server: ViteDevServer | undefined
53
36
 
54
37
  return {
@@ -56,18 +39,8 @@ export function buzolaPlugin(options: BuzolaPluginOptions = {}): Plugin {
56
39
  enforce: 'pre',
57
40
 
58
41
  async configResolved(config) {
59
- root = config.root
60
- const fileConfig = await loadConfig(root)
61
-
62
- const routesDir = options.routesDir ?? fileConfig.routesDir ?? 'src/routes'
63
- const output = options.output ?? fileConfig.output ?? 'src/buzola.gen.ts'
64
- const persistentParams = options.persistentParams ?? fileConfig.persistentParams
65
-
66
- baseOptions = {
67
- routesDir: path.resolve(root, routesDir),
68
- outputPath: path.resolve(root, output),
69
- persistentParams,
70
- }
42
+ baseOptions = await resolveOptions({ ...options, root: config.root })
43
+ virtualSource = buildVirtualSource(baseOptions.outputPath)
71
44
  },
72
45
 
73
46
  configureServer(srv) {
@@ -75,21 +48,18 @@ export function buzolaPlugin(options: BuzolaPluginOptions = {}): Plugin {
75
48
  },
76
49
 
77
50
  async buildStart() {
78
- if (!fs.existsSync(baseOptions.routesDir)) return
79
-
80
51
  if (server) {
81
- await generate({ ...baseOptions, moduleLoader: (p) => server!.ssrLoadModule(p) })
52
+ await generate({ ...baseOptions, optional: true, moduleLoader: (p) => server!.ssrLoadModule(p) })
82
53
  } else {
83
- // Production build — create a temporary Vite server for module loading
84
54
  const { createServer } = await import('vite')
85
55
  const tempServer = await createServer({
86
- root,
56
+ root: baseOptions.root,
87
57
  server: { middlewareMode: true },
88
58
  logLevel: 'silent',
89
59
  optimizeDeps: { noDiscovery: true },
90
60
  })
91
61
  try {
92
- await generate({ ...baseOptions, moduleLoader: (p) => tempServer.ssrLoadModule(p) })
62
+ await generate({ ...baseOptions, optional: true, moduleLoader: (p) => tempServer.ssrLoadModule(p) })
93
63
  } finally {
94
64
  await tempServer.close()
95
65
  }
@@ -97,27 +67,23 @@ export function buzolaPlugin(options: BuzolaPluginOptions = {}): Plugin {
97
67
  },
98
68
 
99
69
  resolveId(id) {
100
- if (id === virtualModuleId) {
70
+ if (id === virtualId) {
101
71
  return resolvedVirtualId
102
72
  }
103
73
  },
104
74
 
105
75
  load(id) {
106
76
  if (id === resolvedVirtualId) {
107
- return `export { routes, pageRegistry } from '${baseOptions.outputPath.replace(/\.ts$/, '')}';\n`
77
+ return virtualSource
108
78
  }
109
79
  },
110
80
 
111
81
  async handleHotUpdate({ file }) {
112
- if (!file.startsWith(baseOptions.routesDir) || !server) return
82
+ if (!server || !file.startsWith(baseOptions.routesDir) || !isRouteFile(path.basename(file))) return
113
83
 
114
84
  const changed = await generate({ ...baseOptions, moduleLoader: (p) => server!.ssrLoadModule(p) })
115
85
  if (!changed) return
116
86
 
117
- // Invalidate the virtual module so Vite re-evaluates it.
118
- // Vite propagates the update through the import chain — if the app
119
- // supports HMR for the route tree, no full-page reload is needed.
120
- // If not, Vite falls back to full-reload automatically.
121
87
  const mod = server.moduleGraph.getModuleById(resolvedVirtualId)
122
88
  if (mod) {
123
89
  server.moduleGraph.invalidateModule(mod)
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=codegen.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"codegen.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/codegen.test.ts"],"names":[],"mappings":""}