polen 0.9.0-next.6 → 0.9.0-next.8
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 +66 -4
- package/build/api/builder/builder.d.ts +1 -0
- package/build/api/builder/builder.d.ts.map +1 -1
- package/build/api/builder/builder.js +1 -0
- package/build/api/builder/builder.js.map +1 -1
- package/build/api/config/configurator.d.ts +21 -5
- package/build/api/config/configurator.d.ts.map +1 -1
- package/build/api/config/configurator.js +12 -0
- package/build/api/config/configurator.js.map +1 -1
- package/build/api/config-resolver/resolve.d.ts +1 -1
- package/build/api/config-resolver/resolve.js +1 -1
- package/build/api/config-resolver/vite.d.ts.map +1 -1
- package/build/api/config-resolver/vite.js +1 -0
- package/build/api/config-resolver/vite.js.map +1 -1
- package/build/api/schema/read.d.ts +1 -1
- package/build/api/singletons/markdown/markdown.js +4 -4
- package/build/api/singletons/markdown/markdown.js.map +1 -1
- package/build/api/utils/asset-url/asset-url.d.ts +20 -0
- package/build/api/utils/asset-url/asset-url.d.ts.map +1 -0
- package/build/api/utils/asset-url/asset-url.js +35 -0
- package/build/api/utils/asset-url/asset-url.js.map +1 -0
- package/build/api/utils/asset-url/index.d.ts +2 -0
- package/build/api/utils/asset-url/index.d.ts.map +1 -0
- package/build/api/utils/asset-url/index.js +2 -0
- package/build/api/utils/asset-url/index.js.map +1 -0
- package/build/api/vite/plugins/core.d.ts.map +1 -1
- package/build/api/vite/plugins/core.js +10 -4
- package/build/api/vite/plugins/core.js.map +1 -1
- package/build/api/vite/plugins/pages.d.ts.map +1 -1
- package/build/api/vite/plugins/pages.js +11 -3
- package/build/api/vite/plugins/pages.js.map +1 -1
- package/build/cli/commands/build.js +2 -0
- package/build/cli/commands/build.js.map +1 -1
- package/build/cli/commands/dev.js +2 -0
- package/build/cli/commands/dev.js.map +1 -1
- package/build/lib/shiki/shiki.d.ts +2 -2
- package/build/lib/shiki/shiki.d.ts.map +1 -1
- package/build/lib/shiki/shiki.js +3 -3
- package/build/lib/shiki/shiki.js.map +1 -1
- package/build/lib/vite-virtual/identifier.d.ts +2 -2
- package/build/project-data.d.ts +1 -0
- package/build/project-data.d.ts.map +1 -1
- package/build/template/components/Link.d.ts.map +1 -1
- package/build/template/components/Link.jsx +2 -1
- package/build/template/components/Link.jsx.map +1 -1
- package/build/template/entry.client.jsx +2 -0
- package/build/template/entry.client.jsx.map +1 -1
- package/build/template/routes/root.d.ts.map +1 -1
- package/build/template/routes/root.jsx +7 -4
- package/build/template/routes/root.jsx.map +1 -1
- package/build/template/server/manifest.d.ts +1 -1
- package/build/template/server/manifest.d.ts.map +1 -1
- package/build/template/server/manifest.js +6 -5
- package/build/template/server/manifest.js.map +1 -1
- package/build/template/server/render-page.d.ts.map +1 -1
- package/build/template/server/render-page.jsx +2 -1
- package/build/template/server/render-page.jsx.map +1 -1
- package/build/template/server/ssg/generate.d.ts.map +1 -1
- package/build/template/server/ssg/generate.js +50 -7
- package/build/template/server/ssg/generate.js.map +1 -1
- package/build/template/server/view.d.ts.map +1 -1
- package/build/template/server/view.js +4 -1
- package/build/template/server/view.js.map +1 -1
- package/package.json +10 -6
- package/src/api/builder/builder.ts +2 -0
- package/src/api/config/configurator.ts +34 -5
- package/src/api/config-resolver/resolve.ts +1 -1
- package/src/api/config-resolver/vite.ts +1 -0
- package/src/api/schema/read.ts +1 -1
- package/src/api/singletons/markdown/markdown.test.ts +7 -7
- package/src/api/singletons/markdown/markdown.ts +4 -4
- package/src/api/utils/asset-url/asset-url.test.ts +47 -0
- package/src/api/utils/asset-url/asset-url.ts +38 -0
- package/src/api/utils/asset-url/index.ts +1 -0
- package/src/api/vite/plugins/core.ts +10 -4
- package/src/api/vite/plugins/pages.ts +11 -3
- package/src/cli/commands/build.ts +5 -0
- package/src/cli/commands/dev.ts +5 -0
- package/src/lib/shiki/index.ts +1 -1
- package/src/lib/shiki/shiki.ts +7 -7
- package/src/lib/vite-virtual/identifier.ts +2 -2
- package/src/project-data.ts +1 -0
- package/src/template/components/Link.tsx +4 -3
- package/src/template/entry.client.tsx +2 -0
- package/src/template/routes/root.tsx +7 -4
- package/src/template/server/manifest.ts +6 -3
- package/src/template/server/render-page.tsx +2 -1
- package/src/template/server/ssg/generate.ts +70 -7
- package/src/template/server/view.ts +4 -1
package/src/api/schema/read.ts
CHANGED
@@ -12,7 +12,7 @@ console.log(x)
|
|
12
12
|
\`\`\`
|
13
13
|
`
|
14
14
|
const result = await parse(markdown)
|
15
|
-
|
15
|
+
|
16
16
|
expect(result).toContain(`<h1>Hello</h1>`)
|
17
17
|
expect(result).toContain(`<pre`)
|
18
18
|
expect(result).toContain(`shiki`)
|
@@ -32,7 +32,7 @@ type Query {
|
|
32
32
|
\`\`\`
|
33
33
|
`
|
34
34
|
const result = await parse(markdown)
|
35
|
-
|
35
|
+
|
36
36
|
expect(result).toContain(`type`)
|
37
37
|
expect(result).toContain(`Query`)
|
38
38
|
// Check that both ID and ! are present (they may be in separate spans)
|
@@ -43,7 +43,7 @@ type Query {
|
|
43
43
|
test(`parse handles inline code`, async () => {
|
44
44
|
const markdown = `This is \`inline code\` in a sentence.`
|
45
45
|
const result = await parse(markdown)
|
46
|
-
|
46
|
+
|
47
47
|
expect(result).toContain(`<code>inline code</code>`)
|
48
48
|
})
|
49
49
|
|
@@ -57,7 +57,7 @@ type Query {
|
|
57
57
|
- [ ] Task 2
|
58
58
|
`
|
59
59
|
const result = await parse(markdown)
|
60
|
-
|
60
|
+
|
61
61
|
expect(result).toContain(`<table>`)
|
62
62
|
expect(result).toContain(`<input`)
|
63
63
|
expect(result).toContain(`checked`)
|
@@ -70,7 +70,7 @@ plain text without language
|
|
70
70
|
\`\`\`
|
71
71
|
`
|
72
72
|
const result = await parse(markdown)
|
73
|
-
|
73
|
+
|
74
74
|
expect(result).toContain(`<pre`)
|
75
75
|
expect(result).toContain(`plain text without language`)
|
76
76
|
})
|
@@ -82,8 +82,8 @@ const theme = "light"
|
|
82
82
|
\`\`\`
|
83
83
|
`
|
84
84
|
const result = await parse(markdown)
|
85
|
-
|
85
|
+
|
86
86
|
expect(result).toContain(`--shiki-light`)
|
87
87
|
expect(result).toContain(`--shiki-dark`)
|
88
88
|
})
|
89
|
-
})
|
89
|
+
})
|
@@ -1,9 +1,9 @@
|
|
1
|
-
import { unified } from 'unified'
|
2
|
-
import remarkParse from 'remark-parse'
|
3
|
-
import remarkGfm from 'remark-gfm'
|
4
|
-
import remarkRehype from 'remark-rehype'
|
5
1
|
import rehypeShiki from '@shikijs/rehype'
|
6
2
|
import rehypeStringify from 'rehype-stringify'
|
3
|
+
import remarkGfm from 'remark-gfm'
|
4
|
+
import remarkParse from 'remark-parse'
|
5
|
+
import remarkRehype from 'remark-rehype'
|
6
|
+
import { unified } from 'unified'
|
7
7
|
|
8
8
|
// Create a processor with Shiki for syntax highlighting (async only)
|
9
9
|
const createProcessorWithShiki = () => {
|
@@ -0,0 +1,47 @@
|
|
1
|
+
import { describe, expect, test } from 'vitest'
|
2
|
+
import { assetUrl, faviconUrl, joinPaths, pageUrl } from './asset-url.js'
|
3
|
+
|
4
|
+
describe('asset-url helpers', () => {
|
5
|
+
describe('joinPaths', () => {
|
6
|
+
test('joins base path with asset path', () => {
|
7
|
+
expect(joinPaths('/', 'assets/style.css')).toBe('/assets/style.css')
|
8
|
+
expect(joinPaths('/my-app/', 'assets/style.css')).toBe('/my-app/assets/style.css')
|
9
|
+
expect(joinPaths('/my-app/', '/assets/style.css')).toBe('/my-app/assets/style.css')
|
10
|
+
})
|
11
|
+
|
12
|
+
test('handles trailing slash in base', () => {
|
13
|
+
expect(joinPaths('/base/', 'path')).toBe('/base/path')
|
14
|
+
})
|
15
|
+
|
16
|
+
test('handles leading slash in path', () => {
|
17
|
+
expect(joinPaths('/base/', '/path')).toBe('/base/path')
|
18
|
+
})
|
19
|
+
})
|
20
|
+
|
21
|
+
describe('assetUrl', () => {
|
22
|
+
test('creates asset URLs with base path', () => {
|
23
|
+
expect(assetUrl('assets/app.js', '/')).toBe('/assets/app.js')
|
24
|
+
expect(assetUrl('assets/app.js', '/my-app/')).toBe('/my-app/assets/app.js')
|
25
|
+
expect(assetUrl('/assets/app.js', '/my-app/')).toBe('/my-app/assets/app.js')
|
26
|
+
})
|
27
|
+
})
|
28
|
+
|
29
|
+
describe('faviconUrl', () => {
|
30
|
+
test('creates favicon URLs with base path', () => {
|
31
|
+
expect(faviconUrl('logo.ico', '/')).toBe('/logo.ico')
|
32
|
+
expect(faviconUrl('logo.ico', '/my-app/')).toBe('/my-app/logo.ico')
|
33
|
+
expect(faviconUrl('/logo.ico', '/my-app/')).toBe('/my-app/logo.ico')
|
34
|
+
})
|
35
|
+
})
|
36
|
+
|
37
|
+
describe('pageUrl', () => {
|
38
|
+
test('creates page URLs with base path', () => {
|
39
|
+
expect(pageUrl('/', '/')).toBe('/')
|
40
|
+
expect(pageUrl('', '/')).toBe('/')
|
41
|
+
expect(pageUrl('/', '/my-app/')).toBe('/my-app/')
|
42
|
+
expect(pageUrl('', '/my-app/')).toBe('/my-app/')
|
43
|
+
expect(pageUrl('about', '/my-app/')).toBe('/my-app/about')
|
44
|
+
expect(pageUrl('/about', '/my-app/')).toBe('/my-app/about')
|
45
|
+
})
|
46
|
+
})
|
47
|
+
})
|
@@ -0,0 +1,38 @@
|
|
1
|
+
/**
|
2
|
+
* Helper functions for generating asset URLs that respect the base path configuration.
|
3
|
+
*/
|
4
|
+
|
5
|
+
/**
|
6
|
+
* Join a base path with an asset path, handling leading/trailing slashes correctly.
|
7
|
+
*/
|
8
|
+
export const joinPaths = (base: string, path: string): string => {
|
9
|
+
// Remove leading slash from path if present
|
10
|
+
const cleanPath = path.startsWith(`/`) ? path.slice(1) : path
|
11
|
+
// Base already has trailing slash by validation
|
12
|
+
return base + cleanPath
|
13
|
+
}
|
14
|
+
|
15
|
+
/**
|
16
|
+
* Create an asset URL from a path, respecting the base configuration.
|
17
|
+
*/
|
18
|
+
export const assetUrl = (path: string, base: string): string => {
|
19
|
+
return joinPaths(base, path)
|
20
|
+
}
|
21
|
+
|
22
|
+
/**
|
23
|
+
* Create a favicon URL from a path, respecting the base configuration.
|
24
|
+
*/
|
25
|
+
export const faviconUrl = (path: string, base: string): string => {
|
26
|
+
return assetUrl(path, base)
|
27
|
+
}
|
28
|
+
|
29
|
+
/**
|
30
|
+
* Create a page URL from a path, respecting the base configuration.
|
31
|
+
*/
|
32
|
+
export const pageUrl = (path: string, base: string): string => {
|
33
|
+
// For pages, we want to ensure no double slashes
|
34
|
+
if (path === `/` || path === ``) {
|
35
|
+
return base
|
36
|
+
}
|
37
|
+
return joinPaths(base, path)
|
38
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from './asset-url.ts'
|
@@ -190,9 +190,13 @@ export const Core = (config: Config.Config): Vite.PluginOption[] => {
|
|
190
190
|
const schemaNavbar = navbarData.get('schema')
|
191
191
|
schemaNavbar.length = 0 // Clear existing
|
192
192
|
if (schema) {
|
193
|
-
|
193
|
+
// IMPORTANT: Always ensure paths start with '/' for React Router compatibility.
|
194
|
+
// Without the leading slash, React Router treats paths as relative, which causes
|
195
|
+
// hydration mismatches between SSR (where base path is prepended) and client
|
196
|
+
// (where basename is configured). This ensures consistent behavior.
|
197
|
+
schemaNavbar.push({ pathExp: `/reference`, title: `Reference` })
|
194
198
|
if (schema.versions.length > 1) {
|
195
|
-
schemaNavbar.push({ pathExp:
|
199
|
+
schemaNavbar.push({ pathExp: `/changelog`, title: `Changelog` })
|
196
200
|
}
|
197
201
|
}
|
198
202
|
|
@@ -203,6 +207,7 @@ export const Core = (config: Config.Config): Vite.PluginOption[] => {
|
|
203
207
|
const projectData: ProjectData = {
|
204
208
|
schema,
|
205
209
|
faviconPath: `/logo.svg`,
|
210
|
+
basePath: config.build.base,
|
206
211
|
paths: config.paths.project,
|
207
212
|
server: {
|
208
213
|
static: {
|
@@ -210,8 +215,9 @@ export const Core = (config: Config.Config): Vite.PluginOption[] => {
|
|
210
215
|
// relative from CWD of process that boots n1ode server
|
211
216
|
// can easily break! Use path relative in server??
|
212
217
|
directory: `./` + config.paths.project.relative.build.root,
|
213
|
-
// Uses Hono route syntax
|
214
|
-
route: `/` + config.paths.project.relative.build.relative.assets
|
218
|
+
// Uses Hono route syntax - includes base path
|
219
|
+
route: config.build.base.slice(0, -1) + `/` + config.paths.project.relative.build.relative.assets
|
220
|
+
+ `/*`,
|
215
221
|
},
|
216
222
|
},
|
217
223
|
}
|
@@ -8,9 +8,9 @@ import { Tree } from '#lib/tree/index'
|
|
8
8
|
import { debug } from '#singletons/debug'
|
9
9
|
import { superjson } from '#singletons/superjson'
|
10
10
|
import mdx from '@mdx-js/rollup'
|
11
|
+
import rehypeShiki from '@shikijs/rehype'
|
11
12
|
import { Path, Str } from '@wollybeard/kit'
|
12
13
|
import remarkGfm from 'remark-gfm'
|
13
|
-
import rehypeShiki from '@shikijs/rehype'
|
14
14
|
|
15
15
|
const _debug = debug.sub(`vite-plugin-pages`)
|
16
16
|
|
@@ -257,7 +257,11 @@ export const Pages = ({
|
|
257
257
|
const pathExp = FileRouter.pathToExpression([child.value.name])
|
258
258
|
const title = Str.titlizeSlug(child.value.name)
|
259
259
|
navbarPages.push({
|
260
|
-
|
260
|
+
// IMPORTANT: Always ensure paths start with '/' for React Router compatibility.
|
261
|
+
// Without the leading slash, React Router treats paths as relative, which causes
|
262
|
+
// hydration mismatches between SSR (where base path is prepended) and client
|
263
|
+
// (where basename is configured). This ensures consistent behavior.
|
264
|
+
pathExp: pathExp.startsWith('/') ? pathExp : '/' + pathExp,
|
261
265
|
title,
|
262
266
|
})
|
263
267
|
}
|
@@ -265,7 +269,11 @@ export const Pages = ({
|
|
265
269
|
const pathExp = FileRouter.pathToExpression([child.value.name])
|
266
270
|
const title = Str.titlizeSlug(child.value.name)
|
267
271
|
navbarPages.push({
|
268
|
-
|
272
|
+
// IMPORTANT: Always ensure paths start with '/' for React Router compatibility.
|
273
|
+
// Without the leading slash, React Router treats paths as relative, which causes
|
274
|
+
// hydration mismatches between SSR (where base path is prepended) and client
|
275
|
+
// (where basename is configured). This ensures consistent behavior.
|
276
|
+
pathExp: pathExp.startsWith('/') ? pathExp : '/' + pathExp,
|
269
277
|
title,
|
270
278
|
})
|
271
279
|
}
|
@@ -11,6 +11,10 @@ const args = Command.create()
|
|
11
11
|
`--architecture -a`,
|
12
12
|
Api.Config.BuildArchitecture.default('ssg').describe('Which kind of application architecture to output.'),
|
13
13
|
)
|
14
|
+
.parameter(
|
15
|
+
`--base -b`,
|
16
|
+
z.string().optional().describe('Base public path for deployment (e.g., /my-project/)'),
|
17
|
+
)
|
14
18
|
.settings({
|
15
19
|
parameters: {
|
16
20
|
environment: {
|
@@ -33,4 +37,5 @@ const args = Command.create()
|
|
33
37
|
await Api.Builder.build({
|
34
38
|
...(args.debug === false ? {} : { debug: args.debug }),
|
35
39
|
...(args.architecture === 'ssg' ? {} : { architecture: args.architecture }),
|
40
|
+
...(args.base ? { base: args.base } : {}),
|
36
41
|
})
|
package/src/cli/commands/dev.ts
CHANGED
@@ -14,6 +14,10 @@ const args = Command.create()
|
|
14
14
|
// @ts-expect-error
|
15
15
|
z.string().optional().describe(`The path to the project directory. Default is CWD (current working directory).`),
|
16
16
|
)
|
17
|
+
.parameter(
|
18
|
+
`--base -b`,
|
19
|
+
z.string().optional().describe('Base public path for deployment (e.g., /my-project/)'),
|
20
|
+
)
|
17
21
|
.settings({
|
18
22
|
parameters: {
|
19
23
|
environment: {
|
@@ -32,6 +36,7 @@ const dir = ensureOptionalAbsoluteWithCwd(args.project) as string
|
|
32
36
|
const viteUserConfig = await Api.ConfigResolver.fromFile({
|
33
37
|
dir,
|
34
38
|
overrides: {
|
39
|
+
...(args.base ? { build: { base: args.base } } : {}),
|
35
40
|
advanced: {
|
36
41
|
debug: args.debug,
|
37
42
|
},
|
package/src/lib/shiki/index.ts
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export * from './shiki.ts'
|
1
|
+
export * from './shiki.ts'
|
package/src/lib/shiki/shiki.ts
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
import { createHighlighter, type Highlighter, type BundledTheme, type BundledLanguage } from 'shiki'
|
2
1
|
import {
|
3
|
-
transformerNotationHighlight,
|
4
2
|
transformerNotationDiff,
|
5
3
|
transformerNotationFocus,
|
4
|
+
transformerNotationHighlight,
|
6
5
|
transformerRenderWhitespace,
|
7
6
|
} from '@shikijs/transformers'
|
7
|
+
import { type BundledLanguage, type BundledTheme, createHighlighter, type Highlighter } from 'shiki'
|
8
8
|
|
9
9
|
export interface ShikiOptions {
|
10
10
|
themes?: {
|
@@ -88,7 +88,7 @@ export interface CodeHighlightOptions {
|
|
88
88
|
theme?: 'light' | 'dark'
|
89
89
|
showLineNumbers?: boolean
|
90
90
|
highlightLines?: number[]
|
91
|
-
diffLines?: { add: number[]
|
91
|
+
diffLines?: { add: number[]; remove: number[] }
|
92
92
|
focusLines?: number[]
|
93
93
|
showInvisibles?: boolean
|
94
94
|
}
|
@@ -104,7 +104,7 @@ export async function highlightCode({
|
|
104
104
|
showInvisibles = false,
|
105
105
|
}: CodeHighlightOptions): Promise<string> {
|
106
106
|
const highlighter = await getHighlighter()
|
107
|
-
|
107
|
+
|
108
108
|
const themes = {
|
109
109
|
light: DEFAULT_THEMES.light,
|
110
110
|
dark: DEFAULT_THEMES.dark,
|
@@ -119,7 +119,7 @@ export async function highlightCode({
|
|
119
119
|
name: `line-numbers`,
|
120
120
|
pre(node: any) {
|
121
121
|
node.properties[`data-line-numbers`] = `true`
|
122
|
-
}
|
122
|
+
},
|
123
123
|
})
|
124
124
|
}
|
125
125
|
|
@@ -131,7 +131,7 @@ export async function highlightCode({
|
|
131
131
|
if (highlightLines.includes(line)) {
|
132
132
|
node.properties[`data-highlighted`] = `true`
|
133
133
|
}
|
134
|
-
}
|
134
|
+
},
|
135
135
|
})
|
136
136
|
}
|
137
137
|
|
@@ -158,4 +158,4 @@ export async function highlightCode({
|
|
158
158
|
}
|
159
159
|
|
160
160
|
// Re-export types
|
161
|
-
export type {
|
161
|
+
export type { BundledLanguage, BundledTheme, Highlighter } from 'shiki'
|
@@ -2,7 +2,7 @@ import { createId, markNoPlugins, normalizeId } from './id.ts'
|
|
2
2
|
|
3
3
|
export interface Options {
|
4
4
|
/**
|
5
|
-
* @
|
5
|
+
* @default '/'
|
6
6
|
*/
|
7
7
|
separator?: string
|
8
8
|
/**
|
@@ -10,7 +10,7 @@ export interface Options {
|
|
10
10
|
|
11
11
|
* @see https://vitejs.dev/guide/api-plugin.html#virtual-modules-convention
|
12
12
|
|
13
|
-
* @
|
13
|
+
* @default false
|
14
14
|
*/
|
15
15
|
allowPluginProcessing?: boolean
|
16
16
|
}
|
package/src/project-data.ts
CHANGED
@@ -52,11 +52,12 @@ export const getPathActiveReport = (
|
|
52
52
|
// Normalize both paths for comparison
|
53
53
|
const normalizedPath = pathExp.startsWith('/') ? pathExp.slice(1) : pathExp
|
54
54
|
const normalizedCurrentPath = currentPathExp.startsWith('/') ? currentPathExp.slice(1) : currentPathExp
|
55
|
-
|
55
|
+
|
56
56
|
const isDirect = normalizedCurrentPath === normalizedPath
|
57
|
-
const isdescendant = normalizedCurrentPath.startsWith(normalizedPath + '/')
|
57
|
+
const isdescendant = normalizedCurrentPath.startsWith(normalizedPath + '/')
|
58
|
+
&& normalizedCurrentPath !== normalizedPath
|
58
59
|
const is = isDirect || isdescendant
|
59
|
-
|
60
|
+
|
60
61
|
return {
|
61
62
|
is,
|
62
63
|
isDirect,
|
@@ -6,6 +6,7 @@ import '@radix-ui/themes/styles.css'
|
|
6
6
|
import { ReactDomClient } from '#dep/react-dom-client/index'
|
7
7
|
import { StrictMode } from 'react'
|
8
8
|
import { createBrowserRouter, RouterProvider } from 'react-router'
|
9
|
+
import PROJECT_DATA from 'virtual:polen/project/data.jsonsuper'
|
9
10
|
import { routes } from './routes.jsx'
|
10
11
|
|
11
12
|
// SPA
|
@@ -20,6 +21,7 @@ import { routes } from './routes.jsx'
|
|
20
21
|
|
21
22
|
const router = createBrowserRouter(routes, {
|
22
23
|
hydrationData: window.__staticRouterHydrationData,
|
24
|
+
basename: PROJECT_DATA.basePath === `/` ? undefined : PROJECT_DATA.basePath.slice(0, -1), // Remove trailing slash for React Router
|
23
25
|
})
|
24
26
|
|
25
27
|
ReactDomClient.hydrateRoot(
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import { assetUrl, faviconUrl } from '#api/utils/asset-url/index'
|
1
2
|
import type { ReactRouter } from '#dep/react-router/index'
|
2
3
|
import { createRoute } from '#lib/react-router-aid/react-router-aid'
|
3
4
|
import { GitHubLogoIcon } from '@radix-ui/react-icons'
|
@@ -40,12 +41,12 @@ export const Component = () => {
|
|
40
41
|
{import.meta.env.DEV && <link rel='stylesheet' href={radixStylesUrl} />}
|
41
42
|
<link
|
42
43
|
rel='icon'
|
43
|
-
href={PROJECT_DATA.faviconPath.replace(`.svg`, `.ico`) + `?v=1
|
44
|
+
href={faviconUrl(PROJECT_DATA.faviconPath.replace(`.svg`, `.ico`) + `?v=1`, PROJECT_DATA.basePath)}
|
44
45
|
sizes='256 x 256'
|
45
46
|
/>
|
46
47
|
<link
|
47
48
|
rel='icon'
|
48
|
-
href={PROJECT_DATA.faviconPath + `?v=1
|
49
|
+
href={faviconUrl(PROJECT_DATA.faviconPath + `?v=1`, PROJECT_DATA.basePath)}
|
49
50
|
sizes='any'
|
50
51
|
type='image/svg+xml'
|
51
52
|
/>
|
@@ -120,7 +121,8 @@ const Layout = () => {
|
|
120
121
|
my='8'
|
121
122
|
mx='auto'
|
122
123
|
>
|
123
|
-
<style>
|
124
|
+
<style>
|
125
|
+
{`
|
124
126
|
/* Shiki code blocks */
|
125
127
|
pre.shiki {
|
126
128
|
margin: 1rem 0;
|
@@ -151,7 +153,8 @@ const Layout = () => {
|
|
151
153
|
background: transparent;
|
152
154
|
display: block;
|
153
155
|
}
|
154
|
-
`}
|
156
|
+
`}
|
157
|
+
</style>
|
155
158
|
{header}
|
156
159
|
{isShowSidebar && (
|
157
160
|
<Sidebar
|
@@ -1,25 +1,28 @@
|
|
1
|
+
import { assetUrl } from '#api/utils/asset-url/index'
|
1
2
|
import type { Vite } from '#dep/vite/index'
|
2
3
|
import { Group, Str } from '@wollybeard/kit'
|
3
4
|
|
4
5
|
export const injectManifestIntoHtml = (
|
5
6
|
html: string,
|
6
7
|
manifest: Vite.Manifest,
|
8
|
+
basePath: string,
|
7
9
|
): string => {
|
8
|
-
const assets = getRelevantAsssetsFromManifest(manifest)
|
10
|
+
const assets = getRelevantAsssetsFromManifest(manifest, basePath)
|
9
11
|
return injectAssetsIntoHtml(html, assets)
|
10
12
|
}
|
11
13
|
|
12
14
|
const getRelevantAsssetsFromManifest = (
|
13
15
|
manifest: Vite.Manifest,
|
16
|
+
basePath: string,
|
14
17
|
): HttpAssetGroupSet => {
|
15
18
|
const htmlAssets: HttpAsset[] = []
|
16
19
|
|
17
20
|
for (const manifestChunk of Object.values(manifest)) {
|
18
21
|
if (manifestChunk.isEntry) {
|
19
|
-
htmlAssets.push({ type: `js`, path:
|
22
|
+
htmlAssets.push({ type: `js`, path: assetUrl(manifestChunk.file, basePath) })
|
20
23
|
}
|
21
24
|
for (const cssItem of manifestChunk.css ?? []) {
|
22
|
-
htmlAssets.push({ type: `css`, path:
|
25
|
+
htmlAssets.push({ type: `css`, path: assetUrl(cssItem, basePath) })
|
23
26
|
}
|
24
27
|
}
|
25
28
|
|
@@ -6,6 +6,7 @@ import { Arr } from '@wollybeard/kit'
|
|
6
6
|
import { StrictMode } from 'react'
|
7
7
|
import * as ReactDomServer from 'react-dom/server'
|
8
8
|
import { createStaticRouter, StaticRouterProvider } from 'react-router'
|
9
|
+
import PROJECT_DATA from 'virtual:polen/project/data.jsonsuper'
|
9
10
|
import viteClientAssetManifest from 'virtual:polen/vite/client/manifest'
|
10
11
|
import { injectManifestIntoHtml } from './manifest.ts'
|
11
12
|
import { view } from './view.ts'
|
@@ -29,7 +30,7 @@ export const renderPage = (
|
|
29
30
|
}
|
30
31
|
|
31
32
|
if (__BUILDING__) {
|
32
|
-
html = injectManifestIntoHtml(html, viteClientAssetManifest)
|
33
|
+
html = injectManifestIntoHtml(html, viteClientAssetManifest, PROJECT_DATA.basePath)
|
33
34
|
}
|
34
35
|
|
35
36
|
// todo: what is this?
|
@@ -8,7 +8,22 @@ import { getRoutesPaths } from './get-route-paths.ts'
|
|
8
8
|
|
9
9
|
export const generate = async (view: ReactRouter.StaticHandler) => {
|
10
10
|
const handler: Hono.Handler = async (ctx) => {
|
11
|
-
|
11
|
+
// For SSG, we need to create a request with the base path prepended
|
12
|
+
// so React Router can match it correctly
|
13
|
+
const url = new URL(ctx.req.raw.url)
|
14
|
+
const basePath = PROJECT_DATA.basePath === '/' ? '' : PROJECT_DATA.basePath.slice(0, -1)
|
15
|
+
|
16
|
+
// Create a new request with the base path prepended to the pathname
|
17
|
+
const modifiedRequest = new Request(
|
18
|
+
`${url.protocol}//${url.host}${basePath}${url.pathname}${url.search}`,
|
19
|
+
{
|
20
|
+
method: ctx.req.raw.method,
|
21
|
+
headers: ctx.req.raw.headers,
|
22
|
+
body: ctx.req.raw.body,
|
23
|
+
},
|
24
|
+
)
|
25
|
+
|
26
|
+
const staticHandlerContext = await view.query(modifiedRequest)
|
12
27
|
if (staticHandlerContext instanceof Response) {
|
13
28
|
return staticHandlerContext
|
14
29
|
}
|
@@ -21,12 +36,60 @@ export const generate = async (view: ReactRouter.StaticHandler) => {
|
|
21
36
|
app.get(routePath, handler)
|
22
37
|
}
|
23
38
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
})
|
39
|
+
// For large schemas, we need to process in smaller batches to avoid memory issues
|
40
|
+
const BATCH_SIZE = 50
|
41
|
+
const totalPaths = routePaths.length
|
42
|
+
console.log(`[info] Generating ${totalPaths} static pages...`)
|
43
|
+
|
44
|
+
for (let i = 0; i < totalPaths; i += BATCH_SIZE) {
|
45
|
+
const batchPaths = routePaths.slice(i, i + BATCH_SIZE)
|
46
|
+
const batchApp = new Hono.Hono()
|
47
|
+
|
48
|
+
// Create a custom handler for batch processing that includes base path handling
|
49
|
+
const batchHandler: Hono.Handler = async (ctx) => {
|
50
|
+
// For SSG, we need to create a request with the base path prepended
|
51
|
+
const url = new URL(ctx.req.raw.url)
|
52
|
+
const basePath = PROJECT_DATA.basePath === '/' ? '' : PROJECT_DATA.basePath.slice(0, -1)
|
53
|
+
|
54
|
+
// Create a new request with the base path prepended to the pathname
|
55
|
+
const modifiedRequest = new Request(
|
56
|
+
`${url.protocol}//${url.host}${basePath}${url.pathname}${url.search}`,
|
57
|
+
{
|
58
|
+
method: ctx.req.raw.method,
|
59
|
+
headers: ctx.req.raw.headers,
|
60
|
+
body: ctx.req.raw.body,
|
61
|
+
},
|
62
|
+
)
|
63
|
+
|
64
|
+
const staticHandlerContext = await view.query(modifiedRequest)
|
65
|
+
if (staticHandlerContext instanceof Response) {
|
66
|
+
return staticHandlerContext
|
67
|
+
}
|
68
|
+
return renderPage(staticHandlerContext)
|
69
|
+
}
|
28
70
|
|
29
|
-
|
30
|
-
|
71
|
+
// Register only the routes for this batch
|
72
|
+
for (const routePath of batchPaths) {
|
73
|
+
batchApp.get(routePath, batchHandler)
|
74
|
+
}
|
75
|
+
|
76
|
+
console.log(
|
77
|
+
`[info] Processing batch ${Math.floor(i / BATCH_SIZE) + 1}/${
|
78
|
+
Math.ceil(totalPaths / BATCH_SIZE)
|
79
|
+
} (${batchPaths.length} pages)...`,
|
80
|
+
)
|
81
|
+
|
82
|
+
const result = await Hono.SSG.toSSG(batchApp, NodeFs, {
|
83
|
+
concurrency: 5, // Reduced concurrency for memory efficiency
|
84
|
+
dir: PROJECT_DATA.paths.relative.build.root,
|
85
|
+
})
|
86
|
+
|
87
|
+
if (!result.success) {
|
88
|
+
throw new Error(`Failed to generate static site at batch ${Math.floor(i / BATCH_SIZE) + 1}`, {
|
89
|
+
cause: result.error,
|
90
|
+
})
|
91
|
+
}
|
31
92
|
}
|
93
|
+
|
94
|
+
console.log(`[info] Successfully generated ${totalPaths} static pages.`)
|
32
95
|
}
|
@@ -1,4 +1,7 @@
|
|
1
1
|
import { createStaticHandler } from 'react-router'
|
2
|
+
import PROJECT_DATA from 'virtual:polen/project/data.jsonsuper'
|
2
3
|
import { routes } from '../routes.jsx'
|
3
4
|
|
4
|
-
export const view = createStaticHandler(routes
|
5
|
+
export const view = createStaticHandler(routes, {
|
6
|
+
basename: PROJECT_DATA.basePath === `/` ? undefined : PROJECT_DATA.basePath.slice(0, -1), // Remove trailing slash for React Router
|
7
|
+
})
|