@bakery-framework/plugin-vue 2.0.0-alpha.1 → 2.0.0-alpha.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bakery-framework/plugin-vue",
3
- "version": "2.0.0-alpha.1",
3
+ "version": "2.0.0-alpha.12",
4
4
  "description": "Bakery vue plugin.",
5
5
  "keywords": [
6
6
  "bakery",
@@ -43,9 +43,9 @@
43
43
  "vue": "^3.5.38"
44
44
  },
45
45
  "dependencies": {
46
- "@bakery-framework/core": "^1.2.3"
46
+ "@bakery-framework/core": "^2.0.0-alpha.12"
47
47
  },
48
48
  "engines": {
49
- "bun": ">=1.3.14"
49
+ "bun": ">=1.4.0"
50
50
  }
51
51
  }
package/src/chunks.ts CHANGED
@@ -66,7 +66,12 @@ export async function serveVueChunk(
66
66
  entrypoints: [sourcePath],
67
67
  target: 'browser',
68
68
  format: 'esm',
69
- minify: import.meta.env.PROD,
69
+ // `Boolean(...)`, not the flag directly: the mode flags are `'1'`/`''`
70
+ // strings (`core/init.ts`), and `Bun.build` **rejects** a non-boolean
71
+ // `minify` rather than coercing it. Core's `compiler.ts` already wrapped
72
+ // its three; this one did not, and the build would have thrown on every
73
+ // production SFC chunk.
74
+ minify: Boolean(import.meta.env.PROD),
70
75
  define: BUNDLE_DEFINES,
71
76
  })
72
77
 
package/src/client.ts CHANGED
@@ -31,9 +31,11 @@ type StampedRoute = {
31
31
  /** The catch-all's param name (`slug` in `[...slug!]`). */
32
32
  param: string | null
33
33
  /**
34
- * First path segments the catch-all's *siblings* claim — `faculty` when
35
- * `faculty/[id].vue` sits beside the catch-all. Those URLs belong to more
36
- * specific routes, so they get real navigations, not soft ones.
34
+ * First path segments the catch-all's sibling *routes* claim — `faculty`
35
+ * when `faculty/[id].vue` sits beside the catch-all. Those URLs belong to
36
+ * more specific routes, so they get real navigations, not soft ones. Route
37
+ * names only, and only on catch-all pages: the stamp is readable by every
38
+ * visitor, so it must never be a directory listing.
37
39
  */
38
40
  claimed?: string[]
39
41
  /** True when a `[param]` sibling claims every single-segment path. */
package/src/handler.ts CHANGED
@@ -113,7 +113,36 @@ function findLayoutRoute(filePath: string, meta: VueMeta): string | null {
113
113
  }
114
114
 
115
115
  /**
116
- * What the catch-all's siblings claim, for the `defineLayout()` stamp.
116
+ * Does `dir` hold a file this handler routes, at any depth? A sibling
117
+ * directory claims its first segment only when it does — the claim exists for
118
+ * `faculty/[id].vue`-shaped subtrees, and a directory of assets or helpers
119
+ * routes nowhere more specific than the catch-all, so stamping its name would
120
+ * disclose it for no navigational gain. Files at each level are checked
121
+ * before any subdirectory is entered, so the common shallow layout answers
122
+ * without recursing. `Dirent.isDirectory()` is false for symlinks, which is
123
+ * what keeps the walk from cycling.
124
+ */
125
+ function containsRouteFile(dir: string, exts: string[]): boolean {
126
+ let entries: import('node:fs').Dirent[]
127
+ try {
128
+ entries = readdirSync(dir, { withFileTypes: true })
129
+ } catch {
130
+ // Unreadable: treated as holding no routes — same reasoning as the catch
131
+ // in claimedBeside below.
132
+ return false
133
+ }
134
+
135
+ const dirs: string[] = []
136
+ for (const entry of entries) {
137
+ if (entry.name.startsWith('.')) continue
138
+ if (entry.isDirectory()) dirs.push(`${dir}/${entry.name}`)
139
+ else if (exts.some(ext => entry.name.endsWith(ext))) return true
140
+ }
141
+ return dirs.some(sub => containsRouteFile(sub, exts))
142
+ }
143
+
144
+ /**
145
+ * What the catch-all's sibling *routes* claim, for the `defineLayout()` stamp.
117
146
  *
118
147
  * A catch-all owns only *what nothing else claims*: with
119
148
  * `admin/[...slug].vue` beside `admin/faculty/[id].vue`, the URL
@@ -128,6 +157,22 @@ function findLayoutRoute(filePath: string, meta: VueMeta): string | null {
128
157
  * path, which is what `claimedSingle` carries. `layout.vue` claims nothing (it
129
158
  * is not routable), and the catch-all file itself is the page being served.
130
159
  *
160
+ * Only entries the handler's own extension table routes are claims. The stamp
161
+ * is serialized into the HTML of every served page, so each name in it is
162
+ * published to any visitor — and this function used to list *every* sibling
163
+ * stem, which put non-route file names (`sample.bin`, `script.ts`,
164
+ * `index.tsx`) from the source directory into production responses: a
165
+ * directory listing of `src/`, observed in a smoke test of the published
166
+ * alpha. A file sibling therefore counts only with a routed extension, and a
167
+ * directory sibling only when a route file exists somewhere under it.
168
+ *
169
+ * The boundary that filter accepts: a *non-route* file under the base is
170
+ * served by core's real-file-beats-catch-all rule (`findDynamicRoute`), and
171
+ * the stamp no longer names it, so a plain anchor to one soft-navigates into
172
+ * the catch-all's view. An anchor carrying `target` or `download` is never
173
+ * intercepted — that is the spelling for linking a raw file out of a
174
+ * catch-all's subtree, and what `docs/plugins/vue.md` prescribes.
175
+ *
131
176
  * Computed per page request, so files added or removed in dev are seen on the
132
177
  * next load without cache ceremony.
133
178
  */
@@ -140,6 +185,9 @@ export function claimedBeside(catchAllFile: string): {
140
185
 
141
186
  const dir = fs.resolve(catchAllFile).replace(/\/[^/]*$/, '')
142
187
  const self = fs.resolve(catchAllFile).slice(dir.length + 1)
188
+ // The handler's own table (`['vue']`), read at call time so the two cannot
189
+ // drift apart.
190
+ const exts = VueHandler.config.ext.map(ext => `.${ext}`)
143
191
 
144
192
  let entries: import('node:fs').Dirent[]
145
193
  try {
@@ -157,6 +205,12 @@ export function claimedBeside(catchAllFile: string): {
157
205
  if (name.startsWith('.')) continue
158
206
 
159
207
  if (RX_CATCHALL.test(name) || RX_OPT_CATCHALL.test(name)) continue
208
+
209
+ const isRoute = entry.isDirectory()
210
+ ? containsRouteFile(`${dir}/${name}`, exts)
211
+ : exts.some(ext => name.endsWith(ext))
212
+ if (!isRoute) continue
213
+
160
214
  if (RX_DYNAMIC.test(name)) {
161
215
  claimedSingle = true
162
216
  continue
@@ -460,7 +514,13 @@ export class VueHandler extends DynamicHandler {
460
514
  routePath: string,
461
515
  serverParams: any,
462
516
  parsed: ParsedCacheEntry,
463
- route?: { catchAll: boolean; base: string; param: string | null },
517
+ route?: {
518
+ catchAll: boolean
519
+ base: string
520
+ param: string | null
521
+ claimed?: string[]
522
+ claimedSingle?: boolean
523
+ },
464
524
  ) {
465
525
  const { hasCss, serverScript } = parsed
466
526
  const hasServerData =
@@ -724,6 +784,7 @@ async function sharedHandler(
724
784
  // `base` is the URL prefix the page owns: the file's directory. For
725
785
  // `wiki/[...page!].vue` that is `/wiki`; for a root-level catch-all it is
726
786
  // the empty string, which `defineLayout` treats as "everything".
787
+ const catchAll = Boolean(info.catchAll)
727
788
  return VueHandler.handleHtml(
728
789
  id,
729
790
  finalParams,
@@ -731,10 +792,13 @@ async function sharedHandler(
731
792
  serverParams,
732
793
  parsed,
733
794
  {
734
- catchAll: Boolean(info.catchAll),
795
+ catchAll,
735
796
  base: routePath.slice(0, routePath.lastIndexOf('/')),
736
797
  param: info.params.length ? info.params[info.params.length - 1] : null,
737
- ...claimedBeside(diskFile.name ?? ''),
798
+ // Catch-all pages only: `defineLayout()` refuses every other page, so
799
+ // on those the claims would be sibling names published in the HTML with
800
+ // no reader. Skipping the stamp also skips the directory scan.
801
+ ...(catchAll ? claimedBeside(diskFile.name ?? '') : null),
738
802
  },
739
803
  )
740
804
  }