@pyreon/zero 0.11.4 → 0.11.6
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 +22 -22
- package/lib/cache.js.map +1 -1
- package/lib/client.js.map +1 -1
- package/lib/config.js.map +1 -1
- package/lib/font.js.map +1 -1
- package/lib/fs-router-BkbIWqek.js.map +1 -1
- package/lib/fs-router-n4VA4lxu.js.map +1 -1
- package/lib/image-plugin.js.map +1 -1
- package/lib/image.js.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/link.js.map +1 -1
- package/lib/script.js.map +1 -1
- package/lib/seo.js.map +1 -1
- package/lib/theme.js.map +1 -1
- package/package.json +12 -12
- package/src/actions.ts +17 -17
- package/src/adapters/bun.ts +7 -7
- package/src/adapters/index.ts +11 -11
- package/src/adapters/node.ts +8 -8
- package/src/adapters/static.ts +3 -3
- package/src/api-routes.ts +21 -21
- package/src/app.ts +8 -8
- package/src/cache.ts +14 -14
- package/src/client.ts +8 -8
- package/src/compression.ts +19 -19
- package/src/config.ts +6 -6
- package/src/cors.ts +20 -20
- package/src/entry-server.ts +13 -13
- package/src/error-overlay.ts +9 -9
- package/src/font.ts +41 -41
- package/src/fs-router.ts +39 -39
- package/src/image-plugin.ts +45 -45
- package/src/image.tsx +39 -39
- package/src/index.ts +36 -56
- package/src/isr.ts +8 -8
- package/src/link.tsx +23 -23
- package/src/rate-limit.ts +15 -15
- package/src/script.tsx +20 -20
- package/src/seo.ts +46 -46
- package/src/sharp.d.ts +1 -1
- package/src/testing.ts +7 -7
- package/src/theme.tsx +18 -18
- package/src/types.ts +6 -6
- package/src/utils/use-intersection-observer.ts +2 -2
- package/src/vite-plugin.ts +21 -21
package/src/font.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Plugin } from
|
|
1
|
+
import type { Plugin } from 'vite'
|
|
2
2
|
|
|
3
3
|
// ─── Font optimization ──────────────────────────────────────────────────────
|
|
4
4
|
//
|
|
@@ -57,11 +57,11 @@ export interface LocalFont {
|
|
|
57
57
|
src: string
|
|
58
58
|
/** Single weight (400) or variable range ("100 900"). */
|
|
59
59
|
weight?: number | `${number} ${number}`
|
|
60
|
-
style?:
|
|
60
|
+
style?: 'normal' | 'italic'
|
|
61
61
|
display?: FontDisplay
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
export type FontDisplay =
|
|
64
|
+
export type FontDisplay = 'auto' | 'block' | 'swap' | 'fallback' | 'optional'
|
|
65
65
|
|
|
66
66
|
/** Metrics for generating size-adjusted fallback fonts to reduce CLS. */
|
|
67
67
|
export interface FallbackMetrics {
|
|
@@ -98,7 +98,7 @@ type ResolvedFont = StaticFont | VariableFont
|
|
|
98
98
|
* Normalize a GoogleFontInput (string or object) into a ResolvedFont.
|
|
99
99
|
*/
|
|
100
100
|
export function resolveGoogleFont(input: GoogleFontInput): ResolvedFont {
|
|
101
|
-
if (typeof input ===
|
|
101
|
+
if (typeof input === 'string') {
|
|
102
102
|
return parseGoogleFamily(input)
|
|
103
103
|
}
|
|
104
104
|
|
|
@@ -127,13 +127,13 @@ export function resolveGoogleFont(input: GoogleFontInput): ResolvedFont {
|
|
|
127
127
|
* Variable with italic: "Inter:ital,wght@100..900"
|
|
128
128
|
*/
|
|
129
129
|
export function parseGoogleFamily(input: string): ResolvedFont {
|
|
130
|
-
const parts = input.split(
|
|
131
|
-
const family = (parts[0] ??
|
|
130
|
+
const parts = input.split(':')
|
|
131
|
+
const family = (parts[0] ?? '').trim()
|
|
132
132
|
const spec = parts[1]
|
|
133
133
|
let italic = false
|
|
134
134
|
|
|
135
135
|
if (spec) {
|
|
136
|
-
italic = spec.includes(
|
|
136
|
+
italic = spec.includes('ital')
|
|
137
137
|
|
|
138
138
|
// Variable font range syntax: wght@100..900
|
|
139
139
|
const rangeMatch = spec.match(/wght@(\d+)\.\.(\d+)/)
|
|
@@ -153,7 +153,7 @@ export function parseGoogleFamily(input: string): ResolvedFont {
|
|
|
153
153
|
family,
|
|
154
154
|
italic,
|
|
155
155
|
variable: false,
|
|
156
|
-
weights: weightMatch[1].split(
|
|
156
|
+
weights: weightMatch[1].split(';').map(Number),
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
159
|
}
|
|
@@ -164,11 +164,11 @@ export function parseGoogleFamily(input: string): ResolvedFont {
|
|
|
164
164
|
/**
|
|
165
165
|
* Generate a Google Fonts CSS URL.
|
|
166
166
|
*/
|
|
167
|
-
export function googleFontsUrl(families: ResolvedFont[], display: FontDisplay =
|
|
167
|
+
export function googleFontsUrl(families: ResolvedFont[], display: FontDisplay = 'swap'): string {
|
|
168
168
|
const params = families
|
|
169
169
|
.map((f) => {
|
|
170
|
-
const axes = f.italic ?
|
|
171
|
-
const name = f.family.replace(/ /g,
|
|
170
|
+
const axes = f.italic ? 'ital,wght' : 'wght'
|
|
171
|
+
const name = f.family.replace(/ /g, '+')
|
|
172
172
|
|
|
173
173
|
if (f.variable) {
|
|
174
174
|
const range = `${f.weightRange[0]}..${f.weightRange[1]}`
|
|
@@ -176,10 +176,10 @@ export function googleFontsUrl(families: ResolvedFont[], display: FontDisplay =
|
|
|
176
176
|
return `family=${name}:${axes}@${value}`
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
-
const values = f.weights.map((w) => (f.italic ? `0,${w};1,${w}` : String(w))).join(
|
|
179
|
+
const values = f.weights.map((w) => (f.italic ? `0,${w};1,${w}` : String(w))).join(';')
|
|
180
180
|
return `family=${name}:${axes}@${values}`
|
|
181
181
|
})
|
|
182
|
-
.join(
|
|
182
|
+
.join('&')
|
|
183
183
|
|
|
184
184
|
return `https://fonts.googleapis.com/css2?${params}&display=${display}`
|
|
185
185
|
}
|
|
@@ -193,12 +193,12 @@ function localFontFaces(fonts: LocalFont[], display: FontDisplay): string {
|
|
|
193
193
|
(f) => `@font-face {
|
|
194
194
|
font-family: "${f.family}";
|
|
195
195
|
src: url("${f.src}");
|
|
196
|
-
font-weight: ${f.weight ??
|
|
197
|
-
font-style: ${f.style ??
|
|
196
|
+
font-weight: ${f.weight ?? '400'};
|
|
197
|
+
font-style: ${f.style ?? 'normal'};
|
|
198
198
|
font-display: ${f.display ?? display};
|
|
199
199
|
}`,
|
|
200
200
|
)
|
|
201
|
-
.join(
|
|
201
|
+
.join('\n\n')
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
/**
|
|
@@ -219,10 +219,10 @@ function fallbackFontFaces(fallbacks: Record<string, FallbackMetrics>): string {
|
|
|
219
219
|
return `@font-face {
|
|
220
220
|
font-family: "${family} Fallback";
|
|
221
221
|
src: local("${metrics.fallback}");
|
|
222
|
-
${overrides.join(
|
|
222
|
+
${overrides.join('\n')}
|
|
223
223
|
}`
|
|
224
224
|
})
|
|
225
|
-
.join(
|
|
225
|
+
.join('\n\n')
|
|
226
226
|
}
|
|
227
227
|
|
|
228
228
|
/**
|
|
@@ -231,18 +231,18 @@ ${overrides.join("\n")}
|
|
|
231
231
|
function preloadTags(fonts: LocalFont[]): string {
|
|
232
232
|
return fonts
|
|
233
233
|
.map((f) => {
|
|
234
|
-
const ext = f.src.split(
|
|
234
|
+
const ext = f.src.split('.').pop()
|
|
235
235
|
const type =
|
|
236
|
-
ext ===
|
|
237
|
-
?
|
|
238
|
-
: ext ===
|
|
239
|
-
?
|
|
240
|
-
: ext ===
|
|
241
|
-
?
|
|
242
|
-
:
|
|
236
|
+
ext === 'woff2'
|
|
237
|
+
? 'font/woff2'
|
|
238
|
+
: ext === 'woff'
|
|
239
|
+
? 'font/woff'
|
|
240
|
+
: ext === 'ttf'
|
|
241
|
+
? 'font/ttf'
|
|
242
|
+
: 'font/otf'
|
|
243
243
|
return `<link rel="preload" href="${f.src}" as="font" type="${type}" crossorigin>`
|
|
244
244
|
})
|
|
245
|
-
.join(
|
|
245
|
+
.join('\n')
|
|
246
246
|
}
|
|
247
247
|
|
|
248
248
|
/**
|
|
@@ -251,8 +251,8 @@ function preloadTags(fonts: LocalFont[]): string {
|
|
|
251
251
|
async function downloadGoogleFontsCSS(url: string): Promise<string> {
|
|
252
252
|
const response = await fetch(url, {
|
|
253
253
|
headers: {
|
|
254
|
-
|
|
255
|
-
|
|
254
|
+
'User-Agent':
|
|
255
|
+
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
|
256
256
|
},
|
|
257
257
|
})
|
|
258
258
|
if (!response.ok) {
|
|
@@ -300,8 +300,8 @@ async function selfHostFonts(
|
|
|
300
300
|
let rewrittenCss = css
|
|
301
301
|
|
|
302
302
|
for (const url of fontUrls) {
|
|
303
|
-
const urlParts = url.split(
|
|
304
|
-
const fileName = urlParts.at(-1)?.split(
|
|
303
|
+
const urlParts = url.split('/')
|
|
304
|
+
const fileName = urlParts.at(-1)?.split('?')[0] ?? 'font'
|
|
305
305
|
const content = await downloadFontFile(url)
|
|
306
306
|
|
|
307
307
|
fontFiles.push({ name: fileName, content })
|
|
@@ -334,27 +334,27 @@ async function selfHostFonts(
|
|
|
334
334
|
* }
|
|
335
335
|
*/
|
|
336
336
|
export function fontPlugin(config: FontConfig = {}): Plugin {
|
|
337
|
-
const display = config.display ??
|
|
337
|
+
const display = config.display ?? 'swap'
|
|
338
338
|
const shouldPreload = config.preload !== false
|
|
339
339
|
const shouldSelfHost = config.selfHost !== false
|
|
340
340
|
const googleFamilies = (config.google ?? []).map(resolveGoogleFont)
|
|
341
341
|
|
|
342
342
|
let isBuild = false
|
|
343
|
-
let selfHostedCSS =
|
|
343
|
+
let selfHostedCSS = ''
|
|
344
344
|
let selfHostedFontFiles: Array<{ name: string; content: Buffer }> = []
|
|
345
345
|
|
|
346
346
|
return {
|
|
347
|
-
name:
|
|
347
|
+
name: 'pyreon-zero-fonts',
|
|
348
348
|
|
|
349
349
|
configResolved(resolvedConfig) {
|
|
350
|
-
isBuild = resolvedConfig.command ===
|
|
350
|
+
isBuild = resolvedConfig.command === 'build'
|
|
351
351
|
},
|
|
352
352
|
|
|
353
353
|
async buildStart() {
|
|
354
354
|
if (isBuild && shouldSelfHost && googleFamilies.length > 0) {
|
|
355
355
|
const cssUrl = googleFontsUrl(googleFamilies, display)
|
|
356
356
|
try {
|
|
357
|
-
const result = await selfHostFonts(cssUrl,
|
|
357
|
+
const result = await selfHostFonts(cssUrl, 'assets/fonts')
|
|
358
358
|
selfHostedCSS = result.css
|
|
359
359
|
selfHostedFontFiles = result.fontFiles
|
|
360
360
|
} catch {
|
|
@@ -367,7 +367,7 @@ export function fontPlugin(config: FontConfig = {}): Plugin {
|
|
|
367
367
|
// Emit self-hosted font files as assets
|
|
368
368
|
for (const file of selfHostedFontFiles) {
|
|
369
369
|
this.emitFile({
|
|
370
|
-
type:
|
|
370
|
+
type: 'asset',
|
|
371
371
|
fileName: `assets/fonts/${file.name}`,
|
|
372
372
|
source: file.content,
|
|
373
373
|
})
|
|
@@ -388,7 +388,7 @@ export function fontPlugin(config: FontConfig = {}): Plugin {
|
|
|
388
388
|
collectLocalFontTags(tags, config, shouldPreload, display)
|
|
389
389
|
|
|
390
390
|
if (tags.length === 0) return html
|
|
391
|
-
return html.replace(
|
|
391
|
+
return html.replace('</head>', `${tags.join('\n')}\n</head>`)
|
|
392
392
|
},
|
|
393
393
|
}
|
|
394
394
|
}
|
|
@@ -408,8 +408,8 @@ function collectGoogleFontTags(
|
|
|
408
408
|
tags.push(`<style>${opts.selfHostedCSS}</style>`)
|
|
409
409
|
if (opts.shouldPreload) {
|
|
410
410
|
for (const file of opts.selfHostedFontFiles.slice(0, opts.googleFamilies.length)) {
|
|
411
|
-
const ext = file.name.split(
|
|
412
|
-
const type = ext ===
|
|
411
|
+
const ext = file.name.split('.').pop()
|
|
412
|
+
const type = ext === 'woff2' ? 'font/woff2' : 'font/woff'
|
|
413
413
|
tags.push(
|
|
414
414
|
`<link rel="preload" href="/assets/fonts/${file.name}" as="font" type="${type}" crossorigin>`,
|
|
415
415
|
)
|
|
@@ -446,6 +446,6 @@ function collectLocalFontTags(
|
|
|
446
446
|
export function fontVariables(families: Record<string, string>): string {
|
|
447
447
|
const vars = Object.entries(families)
|
|
448
448
|
.map(([key, value]) => ` --font-${key}: ${value};`)
|
|
449
|
-
.join(
|
|
449
|
+
.join('\n')
|
|
450
450
|
return `:root {\n${vars}\n}`
|
|
451
451
|
}
|
package/src/fs-router.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FileRoute, RenderMode } from
|
|
1
|
+
import type { FileRoute, RenderMode } from './types'
|
|
2
2
|
|
|
3
3
|
// ─── File-system route conventions ──────────────────────────────────────────
|
|
4
4
|
//
|
|
@@ -25,7 +25,7 @@ import type { FileRoute, RenderMode } from "./types"
|
|
|
25
25
|
// _loading → loading component
|
|
26
26
|
// (group) → route group (directory ignored in URL)
|
|
27
27
|
|
|
28
|
-
const ROUTE_EXTENSIONS = [
|
|
28
|
+
const ROUTE_EXTENSIONS = ['.tsx', '.jsx', '.ts', '.js']
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
31
|
* Parse a set of file paths (relative to routes dir) into FileRoute objects.
|
|
@@ -33,7 +33,7 @@ const ROUTE_EXTENSIONS = [".tsx", ".jsx", ".ts", ".js"]
|
|
|
33
33
|
* @param files Array of file paths like ["index.tsx", "users/[id].tsx"]
|
|
34
34
|
* @param defaultMode Default rendering mode from config
|
|
35
35
|
*/
|
|
36
|
-
export function parseFileRoutes(files: string[], defaultMode: RenderMode =
|
|
36
|
+
export function parseFileRoutes(files: string[], defaultMode: RenderMode = 'ssr'): FileRoute[] {
|
|
37
37
|
return files
|
|
38
38
|
.filter((f) => ROUTE_EXTENSIONS.some((ext) => f.endsWith(ext)))
|
|
39
39
|
.map((filePath) => parseFilePath(filePath, defaultMode))
|
|
@@ -51,19 +51,19 @@ function parseFilePath(filePath: string, defaultMode: RenderMode): FileRoute {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
const fileName = getFileName(route)
|
|
54
|
-
const isLayout = fileName ===
|
|
55
|
-
const isError = fileName ===
|
|
56
|
-
const isLoading = fileName ===
|
|
57
|
-
const isCatchAll = route.includes(
|
|
54
|
+
const isLayout = fileName === '_layout'
|
|
55
|
+
const isError = fileName === '_error'
|
|
56
|
+
const isLoading = fileName === '_loading'
|
|
57
|
+
const isCatchAll = route.includes('[...')
|
|
58
58
|
|
|
59
59
|
// Get directory path (strip groups for consistent grouping)
|
|
60
|
-
const parts = route.split(
|
|
60
|
+
const parts = route.split('/')
|
|
61
61
|
parts.pop() // remove filename
|
|
62
|
-
const dirPath = parts.filter((s) => !(s.startsWith(
|
|
62
|
+
const dirPath = parts.filter((s) => !(s.startsWith('(') && s.endsWith(')'))).join('/')
|
|
63
63
|
|
|
64
64
|
// Convert file path to URL pattern
|
|
65
65
|
const urlPath = filePathToUrlPath(route)
|
|
66
|
-
const depth = urlPath ===
|
|
66
|
+
const depth = urlPath === '/' ? 0 : urlPath.split('/').filter(Boolean).length
|
|
67
67
|
|
|
68
68
|
return {
|
|
69
69
|
filePath,
|
|
@@ -91,18 +91,18 @@ function parseFilePath(filePath: string, defaultMode: RenderMode): FileRoute {
|
|
|
91
91
|
* "_layout" → "/" (layout marker)
|
|
92
92
|
*/
|
|
93
93
|
export function filePathToUrlPath(filePath: string): string {
|
|
94
|
-
const segments = filePath.split(
|
|
94
|
+
const segments = filePath.split('/')
|
|
95
95
|
const urlSegments: string[] = []
|
|
96
96
|
|
|
97
97
|
for (const seg of segments) {
|
|
98
98
|
// Skip route groups "(name)"
|
|
99
|
-
if (seg.startsWith(
|
|
99
|
+
if (seg.startsWith('(') && seg.endsWith(')')) continue
|
|
100
100
|
|
|
101
101
|
// Skip special files
|
|
102
|
-
if (seg ===
|
|
102
|
+
if (seg === '_layout' || seg === '_error' || seg === '_loading') continue
|
|
103
103
|
|
|
104
104
|
// "index" maps to the parent path
|
|
105
|
-
if (seg ===
|
|
105
|
+
if (seg === 'index') continue
|
|
106
106
|
|
|
107
107
|
// Catch-all: [...param] → :param*
|
|
108
108
|
const catchAll = seg.match(/^\[\.\.\.(\w+)\]$/)
|
|
@@ -121,8 +121,8 @@ export function filePathToUrlPath(filePath: string): string {
|
|
|
121
121
|
urlSegments.push(seg)
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
const path = `/${urlSegments.join(
|
|
125
|
-
return path ||
|
|
124
|
+
const path = `/${urlSegments.join('/')}`
|
|
125
|
+
return path || '/'
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
/** Sort routes: static before dynamic, catch-all last. */
|
|
@@ -132,16 +132,16 @@ function sortRoutes(a: FileRoute, b: FileRoute): number {
|
|
|
132
132
|
// Layouts go first within same depth
|
|
133
133
|
if (a.isLayout !== b.isLayout) return a.isLayout ? -1 : 1
|
|
134
134
|
// Static segments before dynamic
|
|
135
|
-
const aDynamic = a.urlPath.includes(
|
|
136
|
-
const bDynamic = b.urlPath.includes(
|
|
135
|
+
const aDynamic = a.urlPath.includes(':')
|
|
136
|
+
const bDynamic = b.urlPath.includes(':')
|
|
137
137
|
if (aDynamic !== bDynamic) return aDynamic ? 1 : -1
|
|
138
138
|
// Alphabetical
|
|
139
139
|
return a.urlPath.localeCompare(b.urlPath)
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
function getFileName(filePath: string): string {
|
|
143
|
-
const parts = filePath.split(
|
|
144
|
-
return parts[parts.length - 1] ??
|
|
143
|
+
const parts = filePath.split('/')
|
|
144
|
+
return parts[parts.length - 1] ?? ''
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
// ─── Route generation (for Vite plugin) ─────────────────────────────────────
|
|
@@ -175,7 +175,7 @@ function getOrCreateChild(node: RouteNode, segment: string): RouteNode {
|
|
|
175
175
|
function resolveNode(root: RouteNode, dirPath: string): RouteNode {
|
|
176
176
|
let node = root
|
|
177
177
|
if (dirPath) {
|
|
178
|
-
for (const segment of dirPath.split(
|
|
178
|
+
for (const segment of dirPath.split('/')) {
|
|
179
179
|
node = getOrCreateChild(node, segment)
|
|
180
180
|
}
|
|
181
181
|
}
|
|
@@ -208,10 +208,10 @@ export function generateRouteModule(files: string[], routesDir: string): string
|
|
|
208
208
|
const imports: string[] = []
|
|
209
209
|
let importCounter = 0
|
|
210
210
|
|
|
211
|
-
function nextImport(filePath: string, exportName =
|
|
211
|
+
function nextImport(filePath: string, exportName = 'default'): string {
|
|
212
212
|
const name = `_${importCounter++}`
|
|
213
213
|
const fullPath = `${routesDir}/${filePath}`
|
|
214
|
-
if (exportName ===
|
|
214
|
+
if (exportName === 'default') {
|
|
215
215
|
imports.push(`import ${name} from "${fullPath}"`)
|
|
216
216
|
} else {
|
|
217
217
|
imports.push(`import { ${exportName} as ${name} } from "${fullPath}"`)
|
|
@@ -225,7 +225,7 @@ export function generateRouteModule(files: string[], routesDir: string): string
|
|
|
225
225
|
const opts: string[] = []
|
|
226
226
|
if (loadingName) opts.push(`loading: ${loadingName}`)
|
|
227
227
|
if (errorName) opts.push(`error: ${errorName}`)
|
|
228
|
-
const optsStr = opts.length > 0 ? `, { ${opts.join(
|
|
228
|
+
const optsStr = opts.length > 0 ? `, { ${opts.join(', ')} }` : ''
|
|
229
229
|
imports.push(`const ${name} = lazy(() => import("${fullPath}")${optsStr})`)
|
|
230
230
|
return name
|
|
231
231
|
}
|
|
@@ -260,7 +260,7 @@ export function generateRouteModule(files: string[], routesDir: string): string
|
|
|
260
260
|
props.push(`${indent} errorComponent: ${mod}.error`)
|
|
261
261
|
}
|
|
262
262
|
|
|
263
|
-
return `${indent}{\n${props.join(
|
|
263
|
+
return `${indent}{\n${props.join(',\n')}\n${indent}}`
|
|
264
264
|
}
|
|
265
265
|
|
|
266
266
|
function wrapWithLayout(
|
|
@@ -271,7 +271,7 @@ export function generateRouteModule(files: string[], routesDir: string): string
|
|
|
271
271
|
): string {
|
|
272
272
|
const layout = node.layout as FileRoute
|
|
273
273
|
const layoutMod = nextModuleImport(layout.filePath)
|
|
274
|
-
const layoutComp = nextImport(layout.filePath,
|
|
274
|
+
const layoutComp = nextImport(layout.filePath, 'layout')
|
|
275
275
|
|
|
276
276
|
const props: string[] = [
|
|
277
277
|
`${indent}path: ${JSON.stringify(layout.urlPath)}`,
|
|
@@ -284,17 +284,17 @@ export function generateRouteModule(files: string[], routesDir: string): string
|
|
|
284
284
|
props.push(`${indent}errorComponent: ${errorName}`)
|
|
285
285
|
}
|
|
286
286
|
if (children.length > 0) {
|
|
287
|
-
props.push(`${indent}children: [\n${children.join(
|
|
287
|
+
props.push(`${indent}children: [\n${children.join(',\n')}\n${indent}]`)
|
|
288
288
|
}
|
|
289
289
|
|
|
290
|
-
return `${indent}{\n${props.map((p) => ` ${p}`).join(
|
|
290
|
+
return `${indent}{\n${props.map((p) => ` ${p}`).join(',\n')}\n${indent}}`
|
|
291
291
|
}
|
|
292
292
|
|
|
293
293
|
/**
|
|
294
294
|
* Generate route definitions for a tree node.
|
|
295
295
|
*/
|
|
296
296
|
function generateNode(node: RouteNode, depth: number): string[] {
|
|
297
|
-
const indent =
|
|
297
|
+
const indent = ' '.repeat(depth + 1)
|
|
298
298
|
|
|
299
299
|
const errorName = node.error ? nextImport(node.error.filePath) : undefined
|
|
300
300
|
const loadingName = node.loading ? nextImport(node.loading.filePath) : undefined
|
|
@@ -320,9 +320,9 @@ export function generateRouteModule(files: string[], routesDir: string): string
|
|
|
320
320
|
|
|
321
321
|
return [
|
|
322
322
|
`import { lazy } from "@pyreon/router"`,
|
|
323
|
-
|
|
323
|
+
'',
|
|
324
324
|
...imports,
|
|
325
|
-
|
|
325
|
+
'',
|
|
326
326
|
// Filter out undefined properties at runtime
|
|
327
327
|
`function clean(routes) {`,
|
|
328
328
|
` return routes.map(r => {`,
|
|
@@ -332,11 +332,11 @@ export function generateRouteModule(files: string[], routesDir: string): string
|
|
|
332
332
|
` return c`,
|
|
333
333
|
` })`,
|
|
334
334
|
`}`,
|
|
335
|
-
|
|
335
|
+
'',
|
|
336
336
|
`export const routes = clean([`,
|
|
337
|
-
routeDefs.join(
|
|
337
|
+
routeDefs.join(',\n'),
|
|
338
338
|
`])`,
|
|
339
|
-
].join(
|
|
339
|
+
].join('\n')
|
|
340
340
|
}
|
|
341
341
|
|
|
342
342
|
/**
|
|
@@ -359,11 +359,11 @@ export function generateMiddlewareModule(files: string[], routesDir: string): st
|
|
|
359
359
|
|
|
360
360
|
return [
|
|
361
361
|
...imports,
|
|
362
|
-
|
|
362
|
+
'',
|
|
363
363
|
`export const routeMiddleware = [`,
|
|
364
|
-
entries.join(
|
|
364
|
+
entries.join(',\n'),
|
|
365
365
|
`].filter(e => e.middleware)`,
|
|
366
|
-
].join(
|
|
366
|
+
].join('\n')
|
|
367
367
|
}
|
|
368
368
|
|
|
369
369
|
/**
|
|
@@ -371,8 +371,8 @@ export function generateMiddlewareModule(files: string[], routesDir: string): st
|
|
|
371
371
|
* Returns paths relative to the routes directory.
|
|
372
372
|
*/
|
|
373
373
|
export async function scanRouteFiles(routesDir: string): Promise<string[]> {
|
|
374
|
-
const { readdir } = await import(
|
|
375
|
-
const { join, relative } = await import(
|
|
374
|
+
const { readdir } = await import('node:fs/promises')
|
|
375
|
+
const { join, relative } = await import('node:path')
|
|
376
376
|
|
|
377
377
|
const files: string[] = []
|
|
378
378
|
|