|
|
@ -1,8 +1,7 @@
|
|
|
|
import fs from 'fs-extra'
|
|
|
|
import fs from 'fs-extra'
|
|
|
|
import path from 'node:path'
|
|
|
|
import path from 'node:path'
|
|
|
|
import c from 'picocolors'
|
|
|
|
import c from 'picocolors'
|
|
|
|
import { isMatch } from 'picomatch'
|
|
|
|
import pm from 'picomatch'
|
|
|
|
import { glob } from 'tinyglobby'
|
|
|
|
|
|
|
|
import {
|
|
|
|
import {
|
|
|
|
loadConfigFromFile,
|
|
|
|
loadConfigFromFile,
|
|
|
|
normalizePath,
|
|
|
|
normalizePath,
|
|
|
@ -12,6 +11,11 @@ import {
|
|
|
|
} from 'vite'
|
|
|
|
} from 'vite'
|
|
|
|
import type { Awaitable } from '../shared'
|
|
|
|
import type { Awaitable } from '../shared'
|
|
|
|
import { type SiteConfig, type UserConfig } from '../siteConfig'
|
|
|
|
import { type SiteConfig, type UserConfig } from '../siteConfig'
|
|
|
|
|
|
|
|
import {
|
|
|
|
|
|
|
|
getWatchedFiles,
|
|
|
|
|
|
|
|
normalizeWatchPatterns,
|
|
|
|
|
|
|
|
type GlobOptions
|
|
|
|
|
|
|
|
} from '../utils/glob'
|
|
|
|
import { ModuleGraph } from '../utils/moduleGraph'
|
|
|
|
import { ModuleGraph } from '../utils/moduleGraph'
|
|
|
|
import { resolveRewrites } from './rewritesPlugin'
|
|
|
|
import { resolveRewrites } from './rewritesPlugin'
|
|
|
|
|
|
|
|
|
|
|
@ -45,13 +49,15 @@ export interface RouteModule {
|
|
|
|
| UserRouteConfig[]
|
|
|
|
| UserRouteConfig[]
|
|
|
|
| ((watchedFiles: string[]) => Awaitable<UserRouteConfig[]>)
|
|
|
|
| ((watchedFiles: string[]) => Awaitable<UserRouteConfig[]>)
|
|
|
|
transformPageData?: UserConfig['transformPageData']
|
|
|
|
transformPageData?: UserConfig['transformPageData']
|
|
|
|
|
|
|
|
options?: { globOptions?: GlobOptions }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
interface ResolvedRouteModule {
|
|
|
|
interface ResolvedRouteModule {
|
|
|
|
watch: string[] | undefined
|
|
|
|
watch: string[]
|
|
|
|
routes: ResolvedRouteConfig[] | undefined
|
|
|
|
routes?: ResolvedRouteConfig[]
|
|
|
|
loader: RouteModule['paths']
|
|
|
|
loader: RouteModule['paths']
|
|
|
|
transformPageData?: RouteModule['transformPageData']
|
|
|
|
transformPageData?: RouteModule['transformPageData']
|
|
|
|
|
|
|
|
options: NonNullable<RouteModule['options']>
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const dynamicRouteRE = /\[(\w+?)\]/g
|
|
|
|
const dynamicRouteRE = /\[(\w+?)\]/g
|
|
|
@ -63,7 +69,7 @@ let moduleGraph = new ModuleGraph()
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Helper for defining routes with type inference
|
|
|
|
* Helper for defining routes with type inference
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
export function defineRoutes(loader: RouteModule) {
|
|
|
|
export function defineRoutes(loader: RouteModule): RouteModule {
|
|
|
|
return loader
|
|
|
|
return loader
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -78,23 +84,10 @@ export async function resolvePages(
|
|
|
|
routeModuleCache.clear()
|
|
|
|
routeModuleCache.clear()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Important: tinyglobby doesn't guarantee order of the returned files.
|
|
|
|
const allMarkdownFiles = await getWatchedFiles(['**/*.md'], {
|
|
|
|
// We must sort the pages so the input list to rollup is stable across
|
|
|
|
|
|
|
|
// builds - otherwise different input order could result in different exports
|
|
|
|
|
|
|
|
// order in shared chunks which in turns invalidates the hash of every chunk!
|
|
|
|
|
|
|
|
// JavaScript built-in sort() is mandated to be stable as of ES2019 and
|
|
|
|
|
|
|
|
// supported in Node 12+, which is required by Vite.
|
|
|
|
|
|
|
|
const allMarkdownFiles = (
|
|
|
|
|
|
|
|
await glob(['**/*.md'], {
|
|
|
|
|
|
|
|
cwd: srcDir,
|
|
|
|
cwd: srcDir,
|
|
|
|
ignore: [
|
|
|
|
ignore: userConfig.srcExclude
|
|
|
|
'**/node_modules/**',
|
|
|
|
|
|
|
|
'**/dist/**',
|
|
|
|
|
|
|
|
...(userConfig.srcExclude || [])
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
expandDirectories: false
|
|
|
|
|
|
|
|
})
|
|
|
|
})
|
|
|
|
).sort()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const pages: string[] = []
|
|
|
|
const pages: string[] = []
|
|
|
|
const dynamicRouteFiles: string[] = []
|
|
|
|
const dynamicRouteFiles: string[] = []
|
|
|
@ -137,9 +130,7 @@ export const dynamicRoutesPlugin = async (
|
|
|
|
const matched = config.dynamicRoutes.find(
|
|
|
|
const matched = config.dynamicRoutes.find(
|
|
|
|
(r) => r.fullPath === normalizedId
|
|
|
|
(r) => r.fullPath === normalizedId
|
|
|
|
)
|
|
|
|
)
|
|
|
|
if (matched) {
|
|
|
|
if (matched) return normalizedId
|
|
|
|
return normalizedId
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
load(id) {
|
|
|
|
load(id) {
|
|
|
@ -180,23 +171,22 @@ export const dynamicRoutesPlugin = async (
|
|
|
|
for (const id of moduleGraph.delete(normalizedFile)) {
|
|
|
|
for (const id of moduleGraph.delete(normalizedFile)) {
|
|
|
|
routeModuleCache.delete(id)
|
|
|
|
routeModuleCache.delete(id)
|
|
|
|
const mod = this.environment.moduleGraph.getModuleById(id)
|
|
|
|
const mod = this.environment.moduleGraph.getModuleById(id)
|
|
|
|
if (mod) {
|
|
|
|
if (mod) modules.push(mod)
|
|
|
|
modules.push(mod)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Also check if the file matches any custom watch patterns.
|
|
|
|
// Also check if the file matches any custom watch patterns.
|
|
|
|
let watchedFileChanged = false
|
|
|
|
let watchedFileChanged = false
|
|
|
|
for (const [file, route] of routeModuleCache) {
|
|
|
|
for (const [file, route] of routeModuleCache) {
|
|
|
|
if (route.watch && isMatch(normalizedFile, route.watch)) {
|
|
|
|
if (
|
|
|
|
|
|
|
|
route.watch?.length &&
|
|
|
|
|
|
|
|
pm(route.watch, route.options.globOptions)(normalizedFile)
|
|
|
|
|
|
|
|
) {
|
|
|
|
route.routes = undefined
|
|
|
|
route.routes = undefined
|
|
|
|
watchedFileChanged = true
|
|
|
|
watchedFileChanged = true
|
|
|
|
|
|
|
|
|
|
|
|
for (const id of moduleGraph.delete(file)) {
|
|
|
|
for (const id of moduleGraph.delete(file)) {
|
|
|
|
const mod = this.environment.moduleGraph.getModuleById(id)
|
|
|
|
const mod = this.environment.moduleGraph.getModuleById(id)
|
|
|
|
if (mod) {
|
|
|
|
if (mod) modules.push(mod)
|
|
|
|
modules.push(mod)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -255,7 +245,8 @@ async function resolveDynamicRoutes(
|
|
|
|
// load the paths loader module
|
|
|
|
// load the paths loader module
|
|
|
|
let watch: ResolvedRouteModule['watch']
|
|
|
|
let watch: ResolvedRouteModule['watch']
|
|
|
|
let loader: ResolvedRouteModule['loader']
|
|
|
|
let loader: ResolvedRouteModule['loader']
|
|
|
|
let extras: Partial<ResolvedRouteModule>
|
|
|
|
let transformPageData: ResolvedRouteModule['transformPageData']
|
|
|
|
|
|
|
|
let options: ResolvedRouteModule['options']
|
|
|
|
|
|
|
|
|
|
|
|
const loaderPath = normalizePath(pathsFile)
|
|
|
|
const loaderPath = normalizePath(pathsFile)
|
|
|
|
const existing = routeModuleCache.get(loaderPath)
|
|
|
|
const existing = routeModuleCache.get(loaderPath)
|
|
|
@ -267,7 +258,7 @@ async function resolveDynamicRoutes(
|
|
|
|
continue
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
;({ watch, loader, ...extras } = existing)
|
|
|
|
;({ watch, loader, transformPageData, options } = existing)
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
let mod
|
|
|
|
let mod
|
|
|
|
try {
|
|
|
|
try {
|
|
|
@ -294,8 +285,14 @@ async function resolveDynamicRoutes(
|
|
|
|
continue
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// @ts-ignore
|
|
|
|
const loaderModule = mod.config as RouteModule
|
|
|
|
;({ paths: loader, watch, ...extras } = mod.config)
|
|
|
|
watch = normalizeWatchPatterns(
|
|
|
|
|
|
|
|
loaderModule.watch,
|
|
|
|
|
|
|
|
path.dirname(pathsFile)
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
loader = loaderModule.paths
|
|
|
|
|
|
|
|
transformPageData = loaderModule.transformPageData
|
|
|
|
|
|
|
|
options = loaderModule.options || {}
|
|
|
|
|
|
|
|
|
|
|
|
if (!loader) {
|
|
|
|
if (!loader) {
|
|
|
|
logger.warn(
|
|
|
|
logger.warn(
|
|
|
@ -307,15 +304,6 @@ async function resolveDynamicRoutes(
|
|
|
|
continue
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
watch = typeof watch === 'string' ? [watch] : watch
|
|
|
|
|
|
|
|
if (watch) {
|
|
|
|
|
|
|
|
watch = watch.map((p) =>
|
|
|
|
|
|
|
|
p.startsWith('.')
|
|
|
|
|
|
|
|
? normalizePath(path.resolve(path.dirname(pathsFile), p))
|
|
|
|
|
|
|
|
: normalizePath(p)
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// record deps for hmr
|
|
|
|
// record deps for hmr
|
|
|
|
newModuleGraph.add(
|
|
|
|
newModuleGraph.add(
|
|
|
|
loaderPath,
|
|
|
|
loaderPath,
|
|
|
@ -327,15 +315,7 @@ async function resolveDynamicRoutes(
|
|
|
|
let pathsData: UserRouteConfig[]
|
|
|
|
let pathsData: UserRouteConfig[]
|
|
|
|
|
|
|
|
|
|
|
|
if (typeof loader === 'function') {
|
|
|
|
if (typeof loader === 'function') {
|
|
|
|
let watchedFiles: string[] = []
|
|
|
|
const watchedFiles = await getWatchedFiles(watch, options.globOptions)
|
|
|
|
if (watch) {
|
|
|
|
|
|
|
|
watchedFiles = (
|
|
|
|
|
|
|
|
await glob(watch, {
|
|
|
|
|
|
|
|
ignore: ['**/node_modules/**', '**/dist/**'],
|
|
|
|
|
|
|
|
expandDirectories: false
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
).sort()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
pathsData = await loader(watchedFiles)
|
|
|
|
pathsData = await loader(watchedFiles)
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
pathsData = loader
|
|
|
|
pathsData = loader
|
|
|
@ -355,7 +335,8 @@ async function resolveDynamicRoutes(
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
routeModuleCache.set(loaderPath, { ...extras, watch, routes, loader })
|
|
|
|
const mod = { watch, routes, loader, transformPageData, options }
|
|
|
|
|
|
|
|
routeModuleCache.set(loaderPath, mod)
|
|
|
|
|
|
|
|
|
|
|
|
return routes
|
|
|
|
return routes
|
|
|
|
}
|
|
|
|
}
|
|
|
|