polen 0.9.0-next.5 → 0.9.0-next.7
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 +42 -0
- 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.d.ts.map +1 -1
- package/build/api/singletons/markdown/markdown.js +33 -11
- 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 +27 -2
- 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/index.d.ts +2 -0
- package/build/lib/shiki/index.d.ts.map +1 -0
- package/build/lib/shiki/index.js +2 -0
- package/build/lib/shiki/index.js.map +1 -0
- package/build/lib/shiki/shiki.d.ts +26 -0
- package/build/lib/shiki/shiki.d.ts.map +1 -0
- package/build/lib/shiki/shiki.js +105 -0
- package/build/lib/shiki/shiki.js.map +1 -0
- 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/CodeBlock.d.ts +17 -0
- package/build/template/components/CodeBlock.d.ts.map +1 -0
- package/build/template/components/CodeBlock.jsx +42 -0
- package/build/template/components/CodeBlock.jsx.map +1 -0
- 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 +3 -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 +37 -2
- 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 -1
- 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 +89 -0
- package/src/api/singletons/markdown/markdown.ts +35 -13
- 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 +27 -2
- package/src/cli/commands/build.ts +5 -0
- package/src/cli/commands/dev.ts +5 -0
- package/src/lib/shiki/index.ts +1 -0
- package/src/lib/shiki/shiki.test.ts +107 -0
- package/src/lib/shiki/shiki.ts +161 -0
- package/src/lib/vite-virtual/identifier.ts +2 -2
- package/src/project-data.ts +1 -0
- package/src/template/components/CodeBlock.tsx +73 -0
- package/src/template/components/Link.tsx +4 -3
- package/src/template/entry.client.tsx +3 -0
- package/src/template/routes/root.tsx +37 -2
- 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/template/styles/code-block.css +186 -0
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"generate.js","sourceRoot":"","sources":["../../../../src/template/server/ssg/generate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAEtC,OAAO,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAA;AAC1C,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAA;AAC1C,OAAO,YAAY,MAAM,sCAAsC,CAAA;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAErD,MAAM,CAAC,MAAM,QAAQ,GAAG,KAAK,EAAE,IAA+B,EAAE,EAAE;IAChE,MAAM,OAAO,GAAiB,KAAK,EAAE,GAAG,EAAE,EAAE;QAC1C,MAAM,
|
1
|
+
{"version":3,"file":"generate.js","sourceRoot":"","sources":["../../../../src/template/server/ssg/generate.ts"],"names":[],"mappings":"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"}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../../src/template/server/view.ts"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../../src/template/server/view.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,IAAI,sCAEf,CAAA"}
|
@@ -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
|
-
export const view = createStaticHandler(routes
|
4
|
+
export const view = createStaticHandler(routes, {
|
5
|
+
basename: PROJECT_DATA.basePath === `/` ? undefined : PROJECT_DATA.basePath.slice(0, -1), // Remove trailing slash for React Router
|
6
|
+
});
|
4
7
|
//# sourceMappingURL=view.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"view.js","sourceRoot":"","sources":["../../../src/template/server/view.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AAEtC,MAAM,CAAC,MAAM,IAAI,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAA"}
|
1
|
+
{"version":3,"file":"view.js","sourceRoot":"","sources":["../../../src/template/server/view.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,YAAY,MAAM,sCAAsC,CAAA;AAC/D,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AAEtC,MAAM,CAAC,MAAM,IAAI,GAAG,mBAAmB,CAAC,MAAM,EAAE;IAC9C,QAAQ,EAAE,YAAY,CAAC,QAAQ,KAAK,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,yCAAyC;CACpI,CAAC,CAAA"}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "polen",
|
3
|
-
"version": "0.9.0-next.
|
3
|
+
"version": "0.9.0-next.7",
|
4
4
|
"type": "module",
|
5
5
|
"description": "A framework for delightful GraphQL developer portals",
|
6
6
|
"author": {
|
@@ -84,6 +84,9 @@
|
|
84
84
|
"@radix-ui/themes": "^3.2.1",
|
85
85
|
"@rolldown/pluginutils": "1.0.0-beta.12",
|
86
86
|
"@rollup/pluginutils": "^5.1.4",
|
87
|
+
"@shikijs/rehype": "^3.6.0",
|
88
|
+
"@shikijs/transformers": "^3.6.0",
|
89
|
+
"@shikijs/twoslash": "^3.6.0",
|
87
90
|
"@swc/core": "^1.11.31",
|
88
91
|
"@types/jsesc": "^3.0.3",
|
89
92
|
"@vitejs/plugin-react": "^4.5.1",
|
@@ -105,16 +108,21 @@
|
|
105
108
|
"react": "^19.1.0",
|
106
109
|
"react-dom": "^19.1.0",
|
107
110
|
"react-router": "^7.6.2",
|
111
|
+
"rehype-stringify": "^10.0.1",
|
108
112
|
"remark": "^15.0.1",
|
109
113
|
"remark-gfm": "^4.0.1",
|
110
114
|
"remark-html": "^16.0.1",
|
115
|
+
"remark-parse": "^11.0.0",
|
116
|
+
"remark-rehype": "^11.1.2",
|
111
117
|
"resolve.imports": "^2.0.3",
|
112
118
|
"rolldown": "1.0.0-beta.12",
|
119
|
+
"shiki": "^3.6.0",
|
113
120
|
"source-map": "^0.7.4",
|
114
121
|
"superjson": "^2.2.2",
|
115
122
|
"tinyglobby": "^0.2.14",
|
116
123
|
"tsx": "^4.19.4",
|
117
124
|
"typescript": "^5.8.3",
|
125
|
+
"unified": "^11.0.5",
|
118
126
|
"vfile": "^6.0.3",
|
119
127
|
"vite": "npm:rolldown-vite@~6.3.18",
|
120
128
|
"vite-plugin-inspect": "^11.1.0",
|
@@ -170,6 +178,7 @@
|
|
170
178
|
"test:unit": "vitest",
|
171
179
|
"dev": "pnpm build:watch:emit",
|
172
180
|
"dev:pokemon": "pnpm polen dev --project examples/pokemon",
|
181
|
+
"build:demos": "zx ./scripts/build-demos.mjs",
|
173
182
|
"build:clean": "pnpm tsc --build tsconfig.build.json --clean && rm -rf build",
|
174
183
|
"build": "tsc --build tsconfig.build.json",
|
175
184
|
"build:watch": "tsc --build tsconfig.build.json --watch",
|
@@ -12,6 +12,7 @@ const buildDefaults = {
|
|
12
12
|
interface BuildConfigInput {
|
13
13
|
debug?: boolean
|
14
14
|
architecture?: Config.BuildArchitecture
|
15
|
+
base?: string
|
15
16
|
}
|
16
17
|
|
17
18
|
export const build = async (buildConfigInput: BuildConfigInput) => {
|
@@ -22,6 +23,7 @@ export const build = async (buildConfigInput: BuildConfigInput) => {
|
|
22
23
|
overrides: {
|
23
24
|
build: {
|
24
25
|
architecture: buildConfig.architecture,
|
26
|
+
...(buildConfig.base ? { base: buildConfig.base } : {}),
|
25
27
|
},
|
26
28
|
advanced: {
|
27
29
|
debug: buildConfig.debug,
|
@@ -24,7 +24,7 @@ export interface ConfigInput {
|
|
24
24
|
*
|
25
25
|
* Relative paths will be resolved relative to this config file.
|
26
26
|
*
|
27
|
-
* @
|
27
|
+
* @default The directory where the config file is located.
|
28
28
|
*/
|
29
29
|
root?: string
|
30
30
|
/**
|
@@ -32,7 +32,7 @@ export interface ConfigInput {
|
|
32
32
|
*
|
33
33
|
* Powered by [Vite Inspect](https://github.com/antfu-collective/vite-plugin-inspect).
|
34
34
|
*
|
35
|
-
* @
|
35
|
+
* @default true
|
36
36
|
*/
|
37
37
|
schema?: SchemaConfigInput
|
38
38
|
schemaAugmentations?: SchemaAugmentation.Augmentation[]
|
@@ -42,12 +42,27 @@ export interface ConfigInput {
|
|
42
42
|
*
|
43
43
|
* Used in the navigation bar and in the title tag.
|
44
44
|
*
|
45
|
-
* @
|
45
|
+
* @default `My Developer Portal`
|
46
46
|
*/
|
47
47
|
title?: string
|
48
48
|
}
|
49
49
|
build?: {
|
50
50
|
architecture?: BuildArchitecture
|
51
|
+
/**
|
52
|
+
* Base public path for the deployed site.
|
53
|
+
*
|
54
|
+
* Use this when deploying to a subdirectory (e.g., GitHub Pages project sites).
|
55
|
+
*
|
56
|
+
* Examples:
|
57
|
+
* - `/` (default) - Deploy to root
|
58
|
+
* - `/my-project/` - Deploy to subdirectory
|
59
|
+
* - `/pr-123/` - PR preview deployments
|
60
|
+
*
|
61
|
+
* Must start and end with `/`.
|
62
|
+
*
|
63
|
+
* @default `/`
|
64
|
+
*/
|
65
|
+
base?: string
|
51
66
|
}
|
52
67
|
advanced?: {
|
53
68
|
explorer?: boolean
|
@@ -64,7 +79,7 @@ export interface ConfigInput {
|
|
64
79
|
* - Global CLI usage against ephemeral projects e.g. a directory with just a
|
65
80
|
* GraphQL Schema file.
|
66
81
|
*
|
67
|
-
* @
|
82
|
+
* @default false
|
68
83
|
*/
|
69
84
|
isSelfContainedMode?: boolean
|
70
85
|
/**
|
@@ -90,7 +105,7 @@ export interface ConfigInput {
|
|
90
105
|
*
|
91
106
|
* - build output is NOT minified.
|
92
107
|
*
|
93
|
-
* @
|
108
|
+
* @default false
|
94
109
|
*/
|
95
110
|
debug?: boolean
|
96
111
|
/**
|
@@ -140,6 +155,7 @@ export interface Config {
|
|
140
155
|
_input: ConfigInput
|
141
156
|
build: {
|
142
157
|
architecture: BuildArchitecture
|
158
|
+
base: string
|
143
159
|
}
|
144
160
|
watch: {
|
145
161
|
also: string[]
|
@@ -193,6 +209,7 @@ const configInputDefaults: Config = {
|
|
193
209
|
},
|
194
210
|
build: {
|
195
211
|
architecture: BuildArchitecture.enum.ssg,
|
212
|
+
base: `/`,
|
196
213
|
},
|
197
214
|
schema: null,
|
198
215
|
ssr: {
|
@@ -231,6 +248,18 @@ export const normalizeInput = async (
|
|
231
248
|
config.build.architecture = configInput.build.architecture
|
232
249
|
}
|
233
250
|
|
251
|
+
if (configInput?.build?.base !== undefined) {
|
252
|
+
// Validate base path
|
253
|
+
const base = configInput.build.base
|
254
|
+
if (!base.startsWith(`/`)) {
|
255
|
+
throw new Error(`Base path must start with "/". Provided: ${base}`)
|
256
|
+
}
|
257
|
+
if (!base.endsWith(`/`)) {
|
258
|
+
throw new Error(`Base path must end with "/". Provided: ${base}`)
|
259
|
+
}
|
260
|
+
config.build.base = base
|
261
|
+
}
|
262
|
+
|
234
263
|
if (configInput?.advanced?.debug !== undefined) {
|
235
264
|
config.advanced.debug = configInput.advanced.debug
|
236
265
|
}
|
package/src/api/schema/read.ts
CHANGED
@@ -0,0 +1,89 @@
|
|
1
|
+
import { describe, expect, test } from 'vitest'
|
2
|
+
import { parse } from './markdown.js'
|
3
|
+
|
4
|
+
describe(`markdown parser with syntax highlighting`, () => {
|
5
|
+
test(`parse highlights code blocks`, async () => {
|
6
|
+
const markdown = `
|
7
|
+
# Hello
|
8
|
+
|
9
|
+
\`\`\`javascript
|
10
|
+
const x = 42
|
11
|
+
console.log(x)
|
12
|
+
\`\`\`
|
13
|
+
`
|
14
|
+
const result = await parse(markdown)
|
15
|
+
|
16
|
+
expect(result).toContain(`<h1>Hello</h1>`)
|
17
|
+
expect(result).toContain(`<pre`)
|
18
|
+
expect(result).toContain(`shiki`)
|
19
|
+
expect(result).toContain(`console`)
|
20
|
+
expect(result).toContain(`42`)
|
21
|
+
})
|
22
|
+
|
23
|
+
// Note: parseSync cannot be used with async rehype plugins like Shiki
|
24
|
+
// This is a known limitation - syntax highlighting requires async processing
|
25
|
+
|
26
|
+
test(`parse supports GraphQL syntax`, async () => {
|
27
|
+
const markdown = `
|
28
|
+
\`\`\`graphql
|
29
|
+
type Query {
|
30
|
+
user(id: ID!): User
|
31
|
+
}
|
32
|
+
\`\`\`
|
33
|
+
`
|
34
|
+
const result = await parse(markdown)
|
35
|
+
|
36
|
+
expect(result).toContain(`type`)
|
37
|
+
expect(result).toContain(`Query`)
|
38
|
+
// Check that both ID and ! are present (they may be in separate spans)
|
39
|
+
expect(result).toContain(`> ID<`)
|
40
|
+
expect(result).toContain(`>!</`)
|
41
|
+
})
|
42
|
+
|
43
|
+
test(`parse handles inline code`, async () => {
|
44
|
+
const markdown = `This is \`inline code\` in a sentence.`
|
45
|
+
const result = await parse(markdown)
|
46
|
+
|
47
|
+
expect(result).toContain(`<code>inline code</code>`)
|
48
|
+
})
|
49
|
+
|
50
|
+
test(`parse supports GitHub Flavored Markdown`, async () => {
|
51
|
+
const markdown = `
|
52
|
+
| Column 1 | Column 2 |
|
53
|
+
|----------|----------|
|
54
|
+
| Cell 1 | Cell 2 |
|
55
|
+
|
56
|
+
- [x] Task 1
|
57
|
+
- [ ] Task 2
|
58
|
+
`
|
59
|
+
const result = await parse(markdown)
|
60
|
+
|
61
|
+
expect(result).toContain(`<table>`)
|
62
|
+
expect(result).toContain(`<input`)
|
63
|
+
expect(result).toContain(`checked`)
|
64
|
+
})
|
65
|
+
|
66
|
+
test(`parse handles code blocks without language`, async () => {
|
67
|
+
const markdown = `
|
68
|
+
\`\`\`
|
69
|
+
plain text without language
|
70
|
+
\`\`\`
|
71
|
+
`
|
72
|
+
const result = await parse(markdown)
|
73
|
+
|
74
|
+
expect(result).toContain(`<pre`)
|
75
|
+
expect(result).toContain(`plain text without language`)
|
76
|
+
})
|
77
|
+
|
78
|
+
test(`parse preserves theme CSS variables`, async () => {
|
79
|
+
const markdown = `
|
80
|
+
\`\`\`javascript
|
81
|
+
const theme = "light"
|
82
|
+
\`\`\`
|
83
|
+
`
|
84
|
+
const result = await parse(markdown)
|
85
|
+
|
86
|
+
expect(result).toContain(`--shiki-light`)
|
87
|
+
expect(result).toContain(`--shiki-dark`)
|
88
|
+
})
|
89
|
+
})
|
@@ -1,21 +1,43 @@
|
|
1
|
-
import
|
2
|
-
import
|
3
|
-
import
|
1
|
+
import rehypeShiki from '@shikijs/rehype'
|
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'
|
4
7
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
.use(
|
9
|
-
.
|
8
|
+
// Create a processor with Shiki for syntax highlighting (async only)
|
9
|
+
const createProcessorWithShiki = () => {
|
10
|
+
return unified()
|
11
|
+
.use(remarkParse)
|
12
|
+
.use(remarkGfm)
|
13
|
+
.use(remarkRehype)
|
14
|
+
.use(rehypeShiki, {
|
15
|
+
themes: {
|
16
|
+
light: `github-light`,
|
17
|
+
dark: `tokyo-night`,
|
18
|
+
},
|
19
|
+
defaultColor: false,
|
20
|
+
cssVariablePrefix: `--shiki-`,
|
21
|
+
})
|
22
|
+
.use(rehypeStringify)
|
23
|
+
}
|
24
|
+
|
25
|
+
// Create a processor without syntax highlighting for sync processing
|
26
|
+
const createProcessorSync = () => {
|
27
|
+
return unified()
|
28
|
+
.use(remarkParse)
|
29
|
+
.use(remarkGfm)
|
30
|
+
.use(remarkRehype)
|
31
|
+
.use(rehypeStringify)
|
32
|
+
}
|
10
33
|
|
34
|
+
export const parse = async (content: string): Promise<string> => {
|
35
|
+
const result = await createProcessorWithShiki().process(content)
|
11
36
|
return String(result)
|
12
37
|
}
|
13
38
|
|
14
39
|
export const parseSync = (content: string): string => {
|
15
|
-
|
16
|
-
|
17
|
-
.use(RemarkHtml)
|
18
|
-
.processSync(content)
|
19
|
-
|
40
|
+
// Note: Syntax highlighting is not available in sync mode due to @shikijs/rehype being async-only
|
41
|
+
const result = createProcessorSync().processSync(content)
|
20
42
|
return String(result)
|
21
43
|
}
|
@@ -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,6 +8,7 @@ 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
14
|
|
@@ -123,6 +124,22 @@ export const Pages = ({
|
|
123
124
|
...mdx({
|
124
125
|
jsxImportSource: `polen/react`,
|
125
126
|
remarkPlugins: [remarkGfm],
|
127
|
+
rehypePlugins: [
|
128
|
+
[
|
129
|
+
rehypeShiki,
|
130
|
+
{
|
131
|
+
themes: {
|
132
|
+
light: `github-light`,
|
133
|
+
dark: `tokyo-night`,
|
134
|
+
},
|
135
|
+
defaultColor: false,
|
136
|
+
cssVariablePrefix: `--shiki-`,
|
137
|
+
transformers: [
|
138
|
+
// Line numbers will be handled via CSS
|
139
|
+
],
|
140
|
+
},
|
141
|
+
],
|
142
|
+
],
|
126
143
|
}),
|
127
144
|
},
|
128
145
|
|
@@ -240,7 +257,11 @@ export const Pages = ({
|
|
240
257
|
const pathExp = FileRouter.pathToExpression([child.value.name])
|
241
258
|
const title = Str.titlizeSlug(child.value.name)
|
242
259
|
navbarPages.push({
|
243
|
-
|
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,
|
244
265
|
title,
|
245
266
|
})
|
246
267
|
}
|
@@ -248,7 +269,11 @@ export const Pages = ({
|
|
248
269
|
const pathExp = FileRouter.pathToExpression([child.value.name])
|
249
270
|
const title = Str.titlizeSlug(child.value.name)
|
250
271
|
navbarPages.push({
|
251
|
-
|
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,
|
252
277
|
title,
|
253
278
|
})
|
254
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
|
},
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from './shiki.ts'
|