@docsector/docsector-reader 1.7.0 → 2.0.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.
@@ -61,33 +61,344 @@ function getPackageRoot (projectRoot) {
61
61
  }
62
62
 
63
63
  /**
64
- * Create a Vite plugin that watches consumer content files (pages/index.js,
65
- * i18n languages, etc.) and forces the Vite dep optimizer to re-run when
66
- * they change.
64
+ * Normalize paths for cross-platform file matching.
65
+ */
66
+ function normalizePathForMatch (path) {
67
+ return String(path || '').replace(/\\/g, '/')
68
+ }
69
+
70
+ /**
71
+ * List top-level page registry definition files.
72
+ *
73
+ * Includes:
74
+ * - src/pages/index.js (legacy)
75
+ * - src/pages/*.book.js
76
+ * - src/pages/*.index.js
77
+ */
78
+ function getPagesRegistryFiles (projectRoot) {
79
+ const pagesDir = resolve(projectRoot, 'src', 'pages')
80
+ if (!existsSync(pagesDir)) return []
81
+
82
+ const names = readdirSync(pagesDir, { withFileTypes: true })
83
+ .filter(entry => entry.isFile())
84
+ .map(entry => entry.name)
85
+
86
+ return names
87
+ .filter(name => {
88
+ if (name === 'index.js') return true
89
+ return /^[^/]+\.book\.js$/.test(name) || /^[^/]+\.index\.js$/.test(name)
90
+ })
91
+ .sort()
92
+ .map(name => resolve(pagesDir, name))
93
+ }
94
+
95
+ /**
96
+ * Discover configured books from src/pages/*.book.js paired with *.index.js.
97
+ */
98
+ function getBookRegistryEntries (projectRoot) {
99
+ const pagesDir = resolve(projectRoot, 'src', 'pages')
100
+ if (!existsSync(pagesDir)) return []
101
+
102
+ const names = readdirSync(pagesDir, { withFileTypes: true })
103
+ .filter(entry => entry.isFile())
104
+ .map(entry => entry.name)
105
+
106
+ const books = names
107
+ .filter(name => /^[^/]+\.book\.js$/.test(name))
108
+ .sort()
109
+
110
+ const entries = []
111
+ for (const bookFile of books) {
112
+ const baseName = bookFile.slice(0, -'.book.js'.length)
113
+ const indexFile = `${baseName}.index.js`
114
+ if (!names.includes(indexFile)) continue
115
+
116
+ entries.push({
117
+ id: baseName,
118
+ bookFile,
119
+ indexFile,
120
+ bookPath: resolve(pagesDir, bookFile),
121
+ indexPath: resolve(pagesDir, indexFile)
122
+ })
123
+ }
124
+
125
+ return entries
126
+ }
127
+
128
+ /**
129
+ * Resolve book identifier from page config with legacy fallback support.
130
+ */
131
+ function resolvePageBook (config, fallbackBook = 'manual') {
132
+ if (!config || typeof config !== 'object') return fallbackBook
133
+ return config.book ?? config.type ?? fallbackBook
134
+ }
135
+
136
+ const DEFAULT_BOOK_COLORS = Object.freeze({
137
+ active: 'white',
138
+ inactive: 'rgba(255, 255, 255, 0.72)'
139
+ })
140
+
141
+ function normalizeBookColorConfig (rawColor) {
142
+ if (typeof rawColor === 'object' && rawColor !== null && !Array.isArray(rawColor)) {
143
+ const active = typeof rawColor.active === 'string' && rawColor.active.trim().length > 0
144
+ ? rawColor.active.trim()
145
+ : DEFAULT_BOOK_COLORS.active
146
+
147
+ const inactive = typeof rawColor.inactive === 'string' && rawColor.inactive.trim().length > 0
148
+ ? rawColor.inactive.trim()
149
+ : active
150
+
151
+ return { active, inactive }
152
+ }
153
+
154
+ if (typeof rawColor === 'string' && rawColor.trim().length > 0) {
155
+ const normalized = rawColor.trim()
156
+ return {
157
+ active: normalized,
158
+ inactive: normalized
159
+ }
160
+ }
161
+
162
+ return { ...DEFAULT_BOOK_COLORS }
163
+ }
164
+
165
+ /**
166
+ * Build source code for the virtual module `virtual:docsector-books`.
167
+ */
168
+ function buildVirtualBooksModule (projectRoot) {
169
+ const bookEntries = getBookRegistryEntries(projectRoot)
170
+
171
+ // Legacy fallback: support projects that still define src/pages/index.js only.
172
+ if (bookEntries.length === 0) {
173
+ return `import legacyPages from 'pages'
174
+
175
+ const defaultBook = {
176
+ id: 'manual',
177
+ label: 'Manual',
178
+ icon: 'menu_book',
179
+ order: 1,
180
+ color: {
181
+ active: 'white',
182
+ inactive: 'rgba(255, 255, 255, 0.72)'
183
+ }
184
+ }
185
+
186
+ const normalizedPages = legacyPages || {}
187
+
188
+ export const books = {
189
+ manual: {
190
+ config: defaultBook,
191
+ routes: normalizedPages
192
+ }
193
+ }
194
+
195
+ export const allBooks = [defaultBook]
196
+ export const allPages = normalizedPages
197
+
198
+ export default books
199
+ `
200
+ }
201
+
202
+ const imports = []
203
+ const rows = []
204
+
205
+ for (const [index, entry] of bookEntries.entries()) {
206
+ imports.push(`import __book_${index} from 'pages/${entry.bookFile}'`)
207
+ imports.push(`import __routes_${index} from 'pages/${entry.indexFile}'`)
208
+ rows.push(` { fallbackId: ${JSON.stringify(entry.id)}, config: __book_${index}, routes: __routes_${index} }`)
209
+ }
210
+
211
+ return `${imports.join('\n')}
212
+
213
+ const entries = [
214
+ ${rows.join(',\n')}
215
+ ]
216
+
217
+ const DEFAULT_BOOK_COLORS = Object.freeze({
218
+ active: 'white',
219
+ inactive: 'rgba(255, 255, 255, 0.72)'
220
+ })
221
+
222
+ const normalizeBookColor = (rawColor) => {
223
+ if (typeof rawColor === 'object' && rawColor !== null && !Array.isArray(rawColor)) {
224
+ const active = typeof rawColor.active === 'string' && rawColor.active.trim().length > 0
225
+ ? rawColor.active.trim()
226
+ : DEFAULT_BOOK_COLORS.active
227
+
228
+ const inactive = typeof rawColor.inactive === 'string' && rawColor.inactive.trim().length > 0
229
+ ? rawColor.inactive.trim()
230
+ : active
231
+
232
+ return { active, inactive }
233
+ }
234
+
235
+ if (typeof rawColor === 'string' && rawColor.trim().length > 0) {
236
+ const normalized = rawColor.trim()
237
+ return {
238
+ active: normalized,
239
+ inactive: normalized
240
+ }
241
+ }
242
+
243
+ return { ...DEFAULT_BOOK_COLORS }
244
+ }
245
+
246
+ export const books = entries.reduce((accumulator, entry, index) => {
247
+ const config = entry.config || {}
248
+ const resolvedId = config.id || entry.fallbackId || ('book-' + (index + 1))
249
+ const label = config.label || (resolvedId.charAt(0).toUpperCase() + resolvedId.slice(1))
250
+ const normalizedConfig = {
251
+ ...config,
252
+ id: resolvedId,
253
+ label,
254
+ icon: config.icon || 'menu_book',
255
+ order: config.order ?? (index + 1),
256
+ color: normalizeBookColor(config.color)
257
+ }
258
+
259
+ accumulator[resolvedId] = {
260
+ config: normalizedConfig,
261
+ routes: entry.routes || {}
262
+ }
263
+ return accumulator
264
+ }, {})
265
+
266
+ export const allBooks = Object.values(books).map(book => book.config)
267
+ export const allPages = Object.values(books).reduce((accumulator, book) => {
268
+ return {
269
+ ...accumulator,
270
+ ...(book.routes || {})
271
+ }
272
+ }, {})
273
+
274
+ export default books
275
+ `
276
+ }
277
+
278
+ /**
279
+ * Load books and merged pages for build-time plugins (Node context).
280
+ */
281
+ async function loadBooksRegistry (projectRoot) {
282
+ const entries = getBookRegistryEntries(projectRoot)
283
+
284
+ // Legacy fallback
285
+ if (entries.length === 0) {
286
+ const legacyPath = resolve(projectRoot, 'src', 'pages', 'index.js')
287
+ const pages = existsSync(legacyPath)
288
+ ? ((await import(pathToFileURL(legacyPath).href)).default || {})
289
+ : {}
290
+
291
+ const defaultBook = {
292
+ id: 'manual',
293
+ label: 'Manual',
294
+ icon: 'menu_book',
295
+ order: 1,
296
+ color: {
297
+ active: 'white',
298
+ inactive: 'rgba(255, 255, 255, 0.72)'
299
+ }
300
+ }
301
+
302
+ return {
303
+ books: {
304
+ manual: {
305
+ config: defaultBook,
306
+ routes: pages
307
+ }
308
+ },
309
+ allBooks: [defaultBook],
310
+ allPages: pages
311
+ }
312
+ }
313
+
314
+ const books = {}
315
+ const allPages = {}
316
+
317
+ for (const [index, entry] of entries.entries()) {
318
+ const { default: rawConfig = {} } = await import(pathToFileURL(entry.bookPath).href)
319
+ const { default: routes = {} } = await import(pathToFileURL(entry.indexPath).href)
320
+
321
+ const resolvedId = rawConfig.id || entry.id || `book-${index + 1}`
322
+ const label = rawConfig.label || (resolvedId.charAt(0).toUpperCase() + resolvedId.slice(1))
323
+
324
+ const config = {
325
+ ...rawConfig,
326
+ id: resolvedId,
327
+ label,
328
+ icon: rawConfig.icon || 'menu_book',
329
+ order: rawConfig.order ?? (index + 1),
330
+ color: normalizeBookColorConfig(rawConfig.color)
331
+ }
332
+
333
+ books[resolvedId] = {
334
+ config,
335
+ routes
336
+ }
337
+
338
+ Object.assign(allPages, routes || {})
339
+ }
340
+
341
+ const allBooks = Object.values(books).map(book => book.config)
342
+
343
+ return {
344
+ books,
345
+ allBooks,
346
+ allPages
347
+ }
348
+ }
349
+
350
+ /**
351
+ * Check if a file path is a book registry definition file.
352
+ */
353
+ function isPagesRegistryFile (projectRoot, changedPath) {
354
+ const pagesDir = normalizePathForMatch(resolve(projectRoot, 'src', 'pages'))
355
+ const normalizedPath = normalizePathForMatch(changedPath)
356
+ const prefix = `${pagesDir}/`
357
+
358
+ if (!normalizedPath.startsWith(prefix)) return false
359
+ const relativePath = normalizedPath.slice(prefix.length)
360
+
361
+ if (relativePath === 'index.js') return true
362
+ return /^[^/]+\.book\.js$/.test(relativePath) || /^[^/]+\.index\.js$/.test(relativePath)
363
+ }
364
+
365
+ /**
366
+ * Create a Vite plugin that exposes discovered books through
367
+ * `virtual:docsector-books` and restarts dev server when definitions change.
67
368
  *
68
369
  * Why: The router module (`routes.js`) imports consumer content via the
69
370
  * `pages` alias. Vite's dep optimizer pre-bundles the router with the
70
371
  * consumer content inlined, but the optimizer cache hash is based on config
71
- * and lockfile only — NOT on consumer source files. So when pages/index.js
72
- * changes during development, the optimizer serves stale pre-bundled code
73
- * until the cache is manually cleared.
74
- *
75
- * Fix: When pages/index.js changes, the watcher plugin clears the dep cache,
76
- * sets an env flag, and restarts the server. On restart, the config reads the
77
- * flag and sets `optimizeDeps.force = true`, which makes Vite generate a new
78
- * browserHash — effectively busting the browser module cache.
372
+ * and lockfile only — NOT on consumer source files. So when page registries
373
+ * change during development, the optimizer can serve stale pre-bundled code.
79
374
  */
80
- function createPagesWatchPlugin (projectRoot) {
81
- const pagesIndex = resolve(projectRoot, 'src', 'pages', 'index.js')
375
+ function createBooksPlugin (projectRoot) {
376
+ const virtualId = 'virtual:docsector-books'
377
+ const resolvedId = '\0' + virtualId
378
+
82
379
  return {
83
- name: 'docsector-pages-watch',
380
+ name: 'docsector-books',
381
+ resolveId (id) {
382
+ if (id === virtualId) return resolvedId
383
+ },
384
+ load (id) {
385
+ if (id !== resolvedId) return null
386
+ return buildVirtualBooksModule(projectRoot)
387
+ },
84
388
  configureServer (server) {
85
- server.watcher.on('change', (changedPath) => {
86
- if (changedPath === pagesIndex) {
389
+ const onPagesRegistryChange = (changedPath) => {
390
+ if (isPagesRegistryFile(projectRoot, changedPath)) {
87
391
  server.config.logger.info(
88
- '\\x1b[36m[docsector]\\x1b[0m pages/index.js changed — clearing dep cache and restarting...',
392
+ `\\x1b[36m[docsector]\\x1b[0m pages registry changed (${changedPath}) — clearing dep cache and restarting...`,
89
393
  { timestamp: true }
90
394
  )
395
+
396
+ // Invalidate virtual module before restart
397
+ const module = server.moduleGraph.getModuleById(resolvedId)
398
+ if (module) {
399
+ server.moduleGraph.invalidateModule(module)
400
+ }
401
+
91
402
  // Signal the restarted config to force a new optimizer hash
92
403
  process.env.__DOCSECTOR_FORCE_OPTIMIZE = '1'
93
404
  // Delete the stale optimizer cache
@@ -95,7 +406,11 @@ function createPagesWatchPlugin (projectRoot) {
95
406
  rmSync(cacheDir, { recursive: true, force: true })
96
407
  server.restart()
97
408
  }
98
- })
409
+ }
410
+
411
+ server.watcher.on('add', onPagesRegistryChange)
412
+ server.watcher.on('change', onPagesRegistryChange)
413
+ server.watcher.on('unlink', onPagesRegistryChange)
99
414
  }
100
415
  }
101
416
  }
@@ -145,11 +460,10 @@ function createPrerenderMetaPlugin (projectRoot) {
145
460
 
146
461
  const baseHtml = readFileSync(baseHtmlPath, 'utf-8')
147
462
 
148
- // Dynamic import pages registry and docsector config
149
- const pagesUrl = pathToFileURL(resolve(projectRoot, 'src', 'pages', 'index.js')).href
463
+ // Dynamic import books registry and docsector config
150
464
  const configUrl = pathToFileURL(resolve(projectRoot, 'docsector.config.js')).href
151
465
 
152
- const { default: pages } = await import(pagesUrl)
466
+ const { allPages: pages } = await loadBooksRegistry(projectRoot)
153
467
  const { default: config } = await import(configUrl)
154
468
 
155
469
  const brandingName = config.branding?.name || ''
@@ -170,7 +484,7 @@ function createPrerenderMetaPlugin (projectRoot) {
170
484
  for (const [pagePath, page] of Object.entries(pages)) {
171
485
  if (page.config === null) continue
172
486
 
173
- const type = page.config.type ?? 'manual'
487
+ const book = resolvePageBook(page.config, 'manual')
174
488
  const titleData = page.data?.[defaultLang] || page.data?.['*'] || page.data?.['en-US'] || Object.values(page.data || {})[0]
175
489
  const title = titleData?.title || ''
176
490
  const fullTitle = title
@@ -186,7 +500,7 @@ function createPrerenderMetaPlugin (projectRoot) {
186
500
  if (page.config.subpages?.vs) subpages.push('vs')
187
501
 
188
502
  for (const subpage of subpages) {
189
- const routePath = `${type}${pagePath}/${subpage}`
503
+ const routePath = `${book}${pagePath}/${subpage}`
190
504
 
191
505
  const html = baseHtml
192
506
  .replace(/<title>[^<]*<\/title>/, () => `<title>${fullTitle}</title>`)
@@ -759,10 +1073,9 @@ function createMarkdownBuildPlugin (projectRoot) {
759
1073
 
760
1074
  const pagesDir = resolve(projectRoot, 'src', 'pages')
761
1075
  const configUrl = pathToFileURL(resolve(projectRoot, 'docsector.config.js')).href
762
- const pagesUrl = pathToFileURL(resolve(projectRoot, 'src', 'pages', 'index.js')).href
763
1076
 
764
1077
  const { default: config } = await import(configUrl)
765
- const { default: pages } = await import(pagesUrl)
1078
+ const { allPages: pages } = await loadBooksRegistry(projectRoot)
766
1079
 
767
1080
  const defaultLang = config.defaultLanguage || config.languages?.[0]?.value || 'en-US'
768
1081
  let count = 0
@@ -771,17 +1084,17 @@ function createMarkdownBuildPlugin (projectRoot) {
771
1084
  if (page.config === null) continue
772
1085
  if (page.config.status === 'empty') continue
773
1086
 
774
- const type = page.config.type ?? 'manual'
1087
+ const book = resolvePageBook(page.config, 'manual')
775
1088
 
776
1089
  const subpages = ['overview']
777
1090
  if (page.config.subpages?.showcase) subpages.push('showcase')
778
1091
  if (page.config.subpages?.vs) subpages.push('vs')
779
1092
 
780
1093
  for (const subpage of subpages) {
781
- const srcFile = resolve(pagesDir, `${type}${pagePath}.${subpage}.${defaultLang}.md`)
1094
+ const srcFile = resolve(pagesDir, `${book}${pagePath}.${subpage}.${defaultLang}.md`)
782
1095
  if (!existsSync(srcFile)) continue
783
1096
 
784
- const routePath = `${type}${pagePath}/${subpage}`
1097
+ const routePath = `${book}${pagePath}/${subpage}`
785
1098
  const destFile = resolve(distDir, `${routePath}.md`)
786
1099
  const destDir = resolve(destFile, '..')
787
1100
 
@@ -820,17 +1133,17 @@ function createMarkdownBuildPlugin (projectRoot) {
820
1133
  if (page.config === null) continue
821
1134
  if (page.config.status === 'empty') continue
822
1135
 
823
- const type = page.config.type ?? 'manual'
1136
+ const book = resolvePageBook(page.config, 'manual')
824
1137
 
825
1138
  const subpages = ['overview']
826
1139
  if (page.config.subpages?.showcase) subpages.push('showcase')
827
1140
  if (page.config.subpages?.vs) subpages.push('vs')
828
1141
 
829
1142
  for (const subpage of subpages) {
830
- const srcFile = resolve(pagesDir, `${type}${pagePath}.${subpage}.${defaultLang}.md`)
1143
+ const srcFile = resolve(pagesDir, `${book}${pagePath}.${subpage}.${defaultLang}.md`)
831
1144
  if (!existsSync(srcFile)) continue
832
1145
 
833
- const routePath = `/${type}${pagePath}/${subpage}`
1146
+ const routePath = `/${book}${pagePath}/${subpage}`
834
1147
  urls += ` <url>\n <loc>${siteUrl}${routePath}</loc>\n <lastmod>${today}</lastmod>\n </url>\n`
835
1148
  }
836
1149
  }
@@ -853,7 +1166,7 @@ function createMarkdownBuildPlugin (projectRoot) {
853
1166
  if (page.config === null) continue
854
1167
  if (page.config.status === 'empty') continue
855
1168
 
856
- const type = page.config.type ?? 'manual'
1169
+ const book = resolvePageBook(page.config, 'manual')
857
1170
  const title = page.data?.['*']?.title
858
1171
  || page.data?.[defaultLang]?.title
859
1172
  || page.data?.['en-US']?.title
@@ -865,18 +1178,18 @@ function createMarkdownBuildPlugin (projectRoot) {
865
1178
  if (page.config.subpages?.vs) subpages.push('vs')
866
1179
 
867
1180
  for (const subpage of subpages) {
868
- const srcFile = resolve(pagesDir, `${type}${pagePath}.${subpage}.${defaultLang}.md`)
1181
+ const srcFile = resolve(pagesDir, `${book}${pagePath}.${subpage}.${defaultLang}.md`)
869
1182
  if (!existsSync(srcFile)) continue
870
1183
 
871
- const routePath = `${type}${pagePath}/${subpage}`
1184
+ const routePath = `${book}${pagePath}/${subpage}`
872
1185
  const mdUrl = `${siteUrl}/${routePath}.md`
873
1186
  const pageUrl = `${siteUrl}/${routePath}`
874
1187
 
875
1188
  const desc = page.config.meta?.description
876
1189
  const descText = typeof desc === 'object' ? (desc[defaultLang] || desc['en-US'] || '') : (desc || '')
877
1190
 
878
- if (!llmsSections[type]) llmsSections[type] = []
879
- llmsSections[type].push(
1191
+ if (!llmsSections[book]) llmsSections[book] = []
1192
+ llmsSections[book].push(
880
1193
  descText
881
1194
  ? `- [${title}](${mdUrl}): ${descText}`
882
1195
  : `- [${title}](${mdUrl})`
@@ -1474,7 +1787,7 @@ export async function onRequest (context) {
1474
1787
  if (page.config === null) continue
1475
1788
  if (page.config.status === 'empty') continue
1476
1789
 
1477
- const type = page.config.type ?? 'manual'
1790
+ const book = resolvePageBook(page.config, 'manual')
1478
1791
  const defaultTitle = page.data?.['*']?.title
1479
1792
  || page.data?.[defaultLang]?.title
1480
1793
  || page.data?.['en-US']?.title
@@ -1486,13 +1799,14 @@ export async function onRequest (context) {
1486
1799
  if (page.config.subpages?.vs) subpageList.push('vs')
1487
1800
 
1488
1801
  for (const subpage of subpageList) {
1489
- const srcFile = resolve(pagesDir, `${type}${pagePath}.${subpage}.${defaultLang}.md`)
1802
+ const srcFile = resolve(pagesDir, `${book}${pagePath}.${subpage}.${defaultLang}.md`)
1490
1803
  if (!existsSync(srcFile)) continue
1491
1804
 
1492
1805
  mcpPages.push({
1493
- path: `${type}${pagePath}/${subpage}`,
1806
+ path: `${book}${pagePath}/${subpage}`,
1494
1807
  title: defaultTitle,
1495
- type,
1808
+ book,
1809
+ type: book,
1496
1810
  subpage
1497
1811
  })
1498
1812
  }
@@ -1874,12 +2188,12 @@ export function createQuasarConfig (options = {}) {
1874
2188
  vueRouterMode: 'history',
1875
2189
 
1876
2190
  vitePlugins: [
2191
+ createBooksPlugin(projectRoot),
1877
2192
  createHjsonPlugin(),
1878
2193
  createHomePageOverridePlugin(projectRoot),
1879
2194
  createGitDatesPlugin(projectRoot),
1880
2195
  createMarkdownEndpointPlugin(projectRoot),
1881
2196
  createMarkdownBuildPlugin(projectRoot),
1882
- createPagesWatchPlugin(projectRoot),
1883
2197
  createPrerenderMetaPlugin(projectRoot),
1884
2198
  ...vitePlugins
1885
2199
  ],
@@ -1897,16 +2211,23 @@ export function createQuasarConfig (options = {}) {
1897
2211
  viteConf.optimizeDeps.force = true
1898
2212
  }
1899
2213
 
1900
- // Include a hash of pages/index.js in the optimizer config so that
1901
- // Vite's configHash (and thus browserHash) changes whenever page
1902
- // definitions change. This prevents the browser from serving stale
1903
- // pre-bundled router modules from its module cache.
1904
- const pagesFile = resolve(projectRoot, 'src', 'pages', 'index.js')
1905
- if (existsSync(pagesFile)) {
2214
+ // Include a hash of page registry definition files (legacy index.js,
2215
+ // plus *.book.js and *.index.js) in optimizer config so Vite's
2216
+ // configHash/browserHash changes whenever routes/books are edited.
2217
+ const pagesRegistryFiles = getPagesRegistryFiles(projectRoot)
2218
+ if (pagesRegistryFiles.length > 0) {
2219
+ const pagesHashBuilder = createHash('sha256')
2220
+ for (const file of pagesRegistryFiles) {
2221
+ pagesHashBuilder
2222
+ .update(file)
2223
+ .update(readFileSync(file))
2224
+ }
2225
+
1906
2226
  const pagesHash = createHash('sha256')
1907
- .update(readFileSync(pagesFile))
2227
+ .update(pagesHashBuilder.digest('hex'))
1908
2228
  .digest('hex')
1909
2229
  .slice(0, 8)
2230
+
1910
2231
  viteConf.optimizeDeps.esbuildOptions = viteConf.optimizeDeps.esbuildOptions || {}
1911
2232
  viteConf.optimizeDeps.esbuildOptions.define = {
1912
2233
  ...(viteConf.optimizeDeps.esbuildOptions.define || {}),
@@ -1950,7 +2271,7 @@ export function createQuasarConfig (options = {}) {
1950
2271
  // The router is excluded because routes.js imports consumer content via
1951
2272
  // the `pages` alias. If pre-bundled, consumer content gets embedded in
1952
2273
  // the optimizer cache whose hash doesn't track source file changes,
1953
- // causing stale routes after editing pages/index.js.
2274
+ // causing stale routes after editing page registry files.
1954
2275
  viteConf.optimizeDeps.exclude = [
1955
2276
  ...(viteConf.optimizeDeps.exclude || []),
1956
2277
  'boot/i18n', 'boot/store', 'boot/QZoom', 'boot/axios'