polen 0.9.0-next.2 → 0.9.0-next.4
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/build/api/server/report-error.d.ts +2 -0
- package/build/api/server/report-error.d.ts.map +1 -0
- package/build/api/server/report-error.js +47 -0
- package/build/api/server/report-error.js.map +1 -0
- package/build/api/vite/data/navbar.d.ts +9 -0
- package/build/api/vite/data/navbar.d.ts.map +1 -0
- package/build/api/vite/data/navbar.js +6 -0
- package/build/api/vite/data/navbar.js.map +1 -0
- package/build/api/vite/plugins/core.d.ts.map +1 -1
- package/build/api/vite/plugins/core.js +36 -104
- package/build/api/vite/plugins/core.js.map +1 -1
- package/build/api/vite/plugins/pages.d.ts +25 -0
- package/build/api/vite/plugins/pages.d.ts.map +1 -0
- package/build/api/vite/plugins/pages.js +273 -0
- package/build/api/vite/plugins/pages.js.map +1 -0
- package/build/api/vite/plugins/serve.d.ts.map +1 -1
- package/build/api/vite/plugins/serve.js +5 -26
- package/build/api/vite/plugins/serve.js.map +1 -1
- package/build/cli/commands/dev.js +9 -1
- package/build/cli/commands/dev.js.map +1 -1
- package/build/lib/debug/environment-variable.d.ts +1 -0
- package/build/lib/debug/environment-variable.d.ts.map +1 -1
- package/build/lib/debug/environment-variable.js +30 -15
- package/build/lib/debug/environment-variable.js.map +1 -1
- package/build/lib/extensible-data/extensible-data.d.ts +17 -0
- package/build/lib/extensible-data/extensible-data.d.ts.map +1 -0
- package/build/lib/extensible-data/extensible-data.js +24 -0
- package/build/lib/extensible-data/extensible-data.js.map +1 -0
- package/build/lib/extensible-data/index.d.ts +2 -0
- package/build/lib/extensible-data/index.d.ts.map +1 -0
- package/build/lib/extensible-data/index.js +2 -0
- package/build/lib/extensible-data/index.js.map +1 -0
- package/build/lib/kit-temp.d.ts +2 -0
- package/build/lib/kit-temp.d.ts.map +1 -1
- package/build/lib/kit-temp.js +10 -1
- package/build/lib/kit-temp.js.map +1 -1
- package/build/lib/react-router-loader/react-router-loader.d.ts.map +1 -1
- package/build/lib/react-router-loader/react-router-loader.js +0 -1
- package/build/lib/react-router-loader/react-router-loader.js.map +1 -1
- package/build/lib/vite-plugin-json/index.d.ts +2 -0
- package/build/lib/vite-plugin-json/index.d.ts.map +1 -0
- package/build/lib/vite-plugin-json/index.js +2 -0
- package/build/lib/vite-plugin-json/index.js.map +1 -0
- package/build/lib/vite-plugin-json/vite-plugin-json.d.ts +64 -0
- package/build/lib/vite-plugin-json/vite-plugin-json.d.ts.map +1 -0
- package/build/lib/vite-plugin-json/vite-plugin-json.js +59 -0
- package/build/lib/vite-plugin-json/vite-plugin-json.js.map +1 -0
- package/build/lib/vite-plugin-reactive-data/index.d.ts +2 -0
- package/build/lib/vite-plugin-reactive-data/index.d.ts.map +1 -0
- package/build/lib/vite-plugin-reactive-data/index.js +2 -0
- package/build/lib/vite-plugin-reactive-data/index.js.map +1 -0
- package/build/lib/vite-plugin-reactive-data/vite-plugin-reactive-data.d.ts +39 -0
- package/build/lib/vite-plugin-reactive-data/vite-plugin-reactive-data.d.ts.map +1 -0
- package/build/lib/vite-plugin-reactive-data/vite-plugin-reactive-data.js +92 -0
- package/build/lib/vite-plugin-reactive-data/vite-plugin-reactive-data.js.map +1 -0
- package/build/lib/vite-plugins/build-logger.d.ts.map +1 -1
- package/build/lib/vite-plugins/build-logger.js +9 -8
- package/build/lib/vite-plugins/build-logger.js.map +1 -1
- package/build/project-data.d.ts +0 -11
- 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 +4 -3
- package/build/template/components/Link.jsx.map +1 -1
- package/build/template/routes/changelog.jsx +1 -1
- package/build/template/routes/changelog.jsx.map +1 -1
- package/build/template/routes/reference.jsx +1 -1
- package/build/template/routes/reference.jsx.map +1 -1
- package/build/template/routes/root.d.ts.map +1 -1
- package/build/template/routes/root.jsx +5 -3
- package/build/template/routes/root.jsx.map +1 -1
- package/build/template/server/app.js +1 -1
- package/build/template/server/app.js.map +1 -1
- package/build/template/server/render-page.d.ts.map +1 -1
- package/build/template/server/render-page.jsx +4 -1
- package/build/template/server/render-page.jsx.map +1 -1
- package/build/template/server/ssg/generate.js +1 -1
- package/build/template/server/ssg/generate.js.map +1 -1
- package/build/template/server/ssg/get-route-paths.js +1 -1
- package/build/template/server/ssg/get-route-paths.js.map +1 -1
- package/package.json +3 -1
- package/src/api/server/report-error.ts +61 -0
- package/src/api/vite/data/navbar.ts +15 -0
- package/src/api/vite/plugins/core.ts +38 -116
- package/src/api/vite/plugins/pages.ts +332 -0
- package/src/api/vite/plugins/serve.ts +5 -26
- package/src/cli/commands/dev.ts +9 -1
- package/src/lib/debug/environment-variable.ts +31 -14
- package/src/lib/extensible-data/extensible-data.ts +38 -0
- package/src/lib/extensible-data/index.ts +1 -0
- package/src/lib/kit-temp.ts +12 -1
- package/src/lib/react-router-loader/react-router-loader.ts +0 -1
- package/src/lib/vite-plugin-json/index.ts +1 -0
- package/src/lib/vite-plugin-json/vite-plugin-json.ts +128 -0
- package/src/lib/vite-plugin-reactive-data/index.ts +1 -0
- package/src/lib/vite-plugin-reactive-data/vite-plugin-reactive-data.ts +131 -0
- package/src/lib/vite-plugins/build-logger.ts +10 -8
- package/src/project-data.ts +0 -13
- package/src/template/components/Link.tsx +6 -3
- package/src/template/routes/changelog.tsx +1 -1
- package/src/template/routes/reference.tsx +1 -1
- package/src/template/routes/root.tsx +5 -3
- package/src/template/server/app.ts +1 -1
- package/src/template/server/render-page.tsx +4 -1
- package/src/template/server/ssg/generate.ts +1 -1
- package/src/template/server/ssg/get-route-paths.ts +1 -1
- package/build/api/vite/plugins/pages-tree.d.ts +0 -16
- package/build/api/vite/plugins/pages-tree.d.ts.map +0 -1
- package/build/api/vite/plugins/pages-tree.js +0 -153
- package/build/api/vite/plugins/pages-tree.js.map +0 -1
- package/src/api/vite/plugins/pages-tree.ts +0 -187
@@ -1,38 +1,32 @@
|
|
1
1
|
import type { Config } from '#api/config/index'
|
2
|
+
import { NavbarData } from '#api/vite/data/navbar'
|
2
3
|
import { VitePluginSelfContainedMode } from '#cli/_/self-contained-mode'
|
3
4
|
import type { ReactRouter } from '#dep/react-router/index'
|
4
5
|
import type { Vite } from '#dep/vite/index'
|
5
|
-
import {
|
6
|
-
import {
|
7
|
-
import { Tree } from '#lib/tree/index'
|
6
|
+
import { VitePluginJson } from '#lib/vite-plugin-json/index'
|
7
|
+
import { VitePluginReactiveData } from '#lib/vite-plugin-reactive-data/index'
|
8
8
|
import { ViteVirtual } from '#lib/vite-virtual/index'
|
9
9
|
import { debug } from '#singletons/debug'
|
10
|
+
import { superjson } from '#singletons/superjson'
|
10
11
|
import { Json, Str } from '@wollybeard/kit'
|
11
|
-
import
|
12
|
-
import type { ProjectData, SidebarIndex, SiteNavigationItem } from '../../../project-data.ts'
|
13
|
-
import { superjson } from '../../../singletons/superjson.ts'
|
12
|
+
import type { ProjectData } from '../../../project-data.ts'
|
14
13
|
import { SchemaAugmentation } from '../../schema-augmentation/index.ts'
|
15
14
|
import { Schema } from '../../schema/index.ts'
|
16
15
|
import { createLogger } from '../logger.ts'
|
17
16
|
import { polenVirtual } from '../vi.ts'
|
18
|
-
import {
|
17
|
+
import { Pages } from './pages.ts'
|
19
18
|
|
20
19
|
const _debug = debug.sub(`vite-plugin-core`)
|
21
20
|
|
22
21
|
const viTemplateVariables = polenVirtual([`template`, `variables`])
|
23
22
|
const viTemplateSchemaAugmentations = polenVirtual([`template`, `schema-augmentations`])
|
24
|
-
const viProjectData = polenVirtual([`project`, `data`])
|
23
|
+
const viProjectData = polenVirtual([`project`, `data.jsonsuper`], { allowPluginProcessing: true })
|
25
24
|
|
26
25
|
export interface ProjectPagesModule {
|
27
26
|
pages: ReactRouter.RouteObject[]
|
28
27
|
}
|
29
28
|
|
30
29
|
export const Core = (config: Config.Config): Vite.PluginOption[] => {
|
31
|
-
// State for current pages data (updated by pages plugin)
|
32
|
-
let currentPagesData: FileRouter.ScanResult | null = null
|
33
|
-
let currentTreeData: FileRouter.RouteTreeNode | null = null
|
34
|
-
let viteDevServer: Vite.ViteDevServer | null = null
|
35
|
-
|
36
30
|
// Schema cache management
|
37
31
|
let schemaCache: Awaited<ReturnType<typeof Schema.readOrThrow>> | null = null
|
38
32
|
|
@@ -52,6 +46,7 @@ export const Core = (config: Config.Config): Vite.PluginOption[] => {
|
|
52
46
|
}
|
53
47
|
|
54
48
|
const plugins: Vite.Plugin[] = []
|
49
|
+
const navbarData = NavbarData()
|
55
50
|
|
56
51
|
// Note: The main use for this right now is to resolve the react imports
|
57
52
|
// from the mdx vite plugin which have to go through the Polen exports since Polen keeps those deps bundled.
|
@@ -64,26 +59,19 @@ export const Core = (config: Config.Config): Vite.PluginOption[] => {
|
|
64
59
|
}))
|
65
60
|
}
|
66
61
|
|
62
|
+
const json = VitePluginJson.create({
|
63
|
+
codec: {
|
64
|
+
validate: superjson,
|
65
|
+
importPath: import.meta.resolve('#singletons/superjson'),
|
66
|
+
importExport: 'superjson',
|
67
|
+
},
|
68
|
+
filter: {
|
69
|
+
moduleTypes: ['jsonsuper'],
|
70
|
+
},
|
71
|
+
})
|
72
|
+
|
67
73
|
return [
|
68
74
|
...plugins,
|
69
|
-
|
70
|
-
// Self-contained pages plugin
|
71
|
-
...createPagesPlugin({
|
72
|
-
config,
|
73
|
-
onPagesChange: (pages) => {
|
74
|
-
currentPagesData = pages
|
75
|
-
// Invalidate project data virtual module to regenerate navigation/sidebar
|
76
|
-
if (viteDevServer) {
|
77
|
-
const projectDataModule = viteDevServer.moduleGraph.getModuleById(viProjectData.resolved)
|
78
|
-
if (projectDataModule) {
|
79
|
-
viteDevServer.moduleGraph.invalidateModule(projectDataModule)
|
80
|
-
}
|
81
|
-
}
|
82
|
-
},
|
83
|
-
onTreeChange: (tree) => {
|
84
|
-
currentTreeData = tree
|
85
|
-
},
|
86
|
-
}),
|
87
75
|
/**
|
88
76
|
* If a `polen*` import is encountered from the user's project, resolve it to the currently
|
89
77
|
* running source code of Polen rather than the user's node_modules.
|
@@ -95,9 +83,9 @@ export const Core = (config: Config.Config): Vite.PluginOption[] => {
|
|
95
83
|
* 2. Secondary: Using Polen CLI on a project that does not have Polen installed.
|
96
84
|
* (User would likely not want to do this because they would not be able to achieve type safety)
|
97
85
|
*/
|
98
|
-
|
99
86
|
{
|
100
87
|
name: `polen:internal-import-alias`,
|
88
|
+
enforce: 'pre' as const,
|
101
89
|
resolveId(id, importer) {
|
102
90
|
const d = debug.sub(`vite-plugin:internal-import-alias`)
|
103
91
|
|
@@ -133,11 +121,20 @@ export const Core = (config: Config.Config): Vite.PluginOption[] => {
|
|
133
121
|
return to
|
134
122
|
},
|
135
123
|
},
|
124
|
+
json,
|
125
|
+
VitePluginReactiveData.create({
|
126
|
+
moduleId: `virtual:polen/project/data/navbar`,
|
127
|
+
data: navbarData.value,
|
128
|
+
codec: superjson,
|
129
|
+
name: `polen-navbar`,
|
130
|
+
moduleType: 'jsonsuper',
|
131
|
+
}),
|
132
|
+
...Pages({
|
133
|
+
config,
|
134
|
+
navbarData,
|
135
|
+
}),
|
136
136
|
{
|
137
137
|
name: `polen:core`,
|
138
|
-
configureServer(server) {
|
139
|
-
viteDevServer = server
|
140
|
-
},
|
141
138
|
config(_, { command }) {
|
142
139
|
// isServing = command === `serve`
|
143
140
|
return {
|
@@ -187,81 +184,15 @@ export const Core = (config: Config.Config): Vite.PluginOption[] => {
|
|
187
184
|
identifier: viProjectData,
|
188
185
|
async loader() {
|
189
186
|
_debug(`loadingViProjectDataVirtualModule`)
|
190
|
-
// todo: parallel
|
191
187
|
const schema = await readSchema()
|
192
188
|
|
193
|
-
// Get pages data from the pages plugin or load initially
|
194
|
-
if (!currentPagesData) {
|
195
|
-
_debug(`loadingPagesDataInitially`)
|
196
|
-
currentPagesData = await FileRouter.scan({
|
197
|
-
dir: config.paths.project.absolute.pages,
|
198
|
-
glob: `**/*.{md,mdx}`,
|
199
|
-
})
|
200
|
-
// Report any diagnostics from initial scan
|
201
|
-
reportDiagnostics(currentPagesData.diagnostics)
|
202
|
-
}
|
203
|
-
if (!currentTreeData) {
|
204
|
-
_debug(`loadingTreeDataInitially`)
|
205
|
-
currentTreeData = await getRouteTree(config)
|
206
|
-
}
|
207
|
-
const pagesScanResult = currentPagesData
|
208
|
-
const routeTree = currentTreeData
|
209
|
-
_debug(`usingPageRoutesFromPagesPlugin`, pagesScanResult.routes.length)
|
210
|
-
|
211
|
-
const siteNavigationItems: SiteNavigationItem[] = []
|
212
|
-
|
213
|
-
//
|
214
|
-
// ━━ Build Navbar
|
215
|
-
//
|
216
|
-
|
217
|
-
// Process first-level children as navigation items
|
218
|
-
for (const child of routeTree.children) {
|
219
|
-
if (child.value.type === 'directory') {
|
220
|
-
// Check if this directory has an index file
|
221
|
-
const hasIndex = child.children.some(c => c.value.type === 'file' && c.value.name === 'index')
|
222
|
-
|
223
|
-
if (hasIndex) {
|
224
|
-
const pathExp = FileRouter.pathToExpression([child.value.name])
|
225
|
-
const title = Str.titlizeSlug(child.value.name)
|
226
|
-
siteNavigationItems.push({
|
227
|
-
pathExp: pathExp.startsWith('/') ? pathExp.slice(1) : pathExp,
|
228
|
-
title,
|
229
|
-
})
|
230
|
-
}
|
231
|
-
} else if (child.value.type === 'file' && child.value.name !== 'index') {
|
232
|
-
const pathExp = FileRouter.pathToExpression([child.value.name])
|
233
|
-
const title = Str.titlizeSlug(child.value.name)
|
234
|
-
siteNavigationItems.push({
|
235
|
-
pathExp: pathExp.startsWith('/') ? pathExp.slice(1) : pathExp,
|
236
|
-
title,
|
237
|
-
})
|
238
|
-
}
|
239
|
-
}
|
240
|
-
|
241
189
|
// ━ Schema presence causes adding some navbar items
|
190
|
+
const schemaNavbar = navbarData.get('schema')
|
191
|
+
schemaNavbar.length = 0 // Clear existing
|
242
192
|
if (schema) {
|
243
|
-
|
193
|
+
schemaNavbar.push({ pathExp: `reference`, title: `Reference` })
|
244
194
|
if (schema.versions.length > 1) {
|
245
|
-
|
246
|
-
}
|
247
|
-
}
|
248
|
-
|
249
|
-
//
|
250
|
-
// ━━ Build Sidebar
|
251
|
-
//
|
252
|
-
|
253
|
-
const sidebarIndex: SidebarIndex = {}
|
254
|
-
|
255
|
-
// Build sidebar for each top-level directory
|
256
|
-
for (const child of routeTree.children) {
|
257
|
-
if (child.value.type === 'directory') {
|
258
|
-
const pathExp = `/${child.value.name}`
|
259
|
-
// Create a subtree starting from this directory
|
260
|
-
const subtree = Tree.node(child.value, child.children)
|
261
|
-
// Pass the directory name as base path so paths are built correctly
|
262
|
-
const sidebar = FileRouter.Sidebar.buildFromTree(subtree, [child.value.name])
|
263
|
-
_debug(`Built sidebar for ${pathExp}:`, sidebar)
|
264
|
-
sidebarIndex[pathExp] = sidebar
|
195
|
+
schemaNavbar.push({ pathExp: `changelog`, title: `Changelog` })
|
265
196
|
}
|
266
197
|
}
|
267
198
|
|
@@ -271,10 +202,7 @@ export const Core = (config: Config.Config): Vite.PluginOption[] => {
|
|
271
202
|
|
272
203
|
const projectData: ProjectData = {
|
273
204
|
schema,
|
274
|
-
siteNavigationItems,
|
275
|
-
sidebarIndex,
|
276
205
|
faviconPath: `/logo.svg`,
|
277
|
-
pagesScanResult: pagesScanResult,
|
278
206
|
paths: config.paths.project,
|
279
207
|
server: {
|
280
208
|
static: {
|
@@ -288,14 +216,8 @@ export const Core = (config: Config.Config): Vite.PluginOption[] => {
|
|
288
216
|
},
|
289
217
|
}
|
290
218
|
|
291
|
-
|
292
|
-
|
293
|
-
import { superjson } from '#singletons/superjson'
|
294
|
-
|
295
|
-
export const PROJECT_DATA = superjson.parse('${projectDataCode}')
|
296
|
-
`
|
297
|
-
|
298
|
-
return content
|
219
|
+
// Return just the JSON string - let the JSON plugin handle the transformation
|
220
|
+
return superjson.stringify(projectData)
|
299
221
|
},
|
300
222
|
},
|
301
223
|
),
|
@@ -0,0 +1,332 @@
|
|
1
|
+
import type { Config } from '#api/config/index'
|
2
|
+
import type { NavbarDataRegistry } from '#api/vite/data/navbar'
|
3
|
+
import { polenVirtual } from '#api/vite/vi'
|
4
|
+
import type { Vite } from '#dep/vite/index'
|
5
|
+
import { reportDiagnostics } from '#lib/file-router/diagnostic-reporter'
|
6
|
+
import { FileRouter } from '#lib/file-router/index'
|
7
|
+
import { Tree } from '#lib/tree/index'
|
8
|
+
import { debug } from '#singletons/debug'
|
9
|
+
import { superjson } from '#singletons/superjson'
|
10
|
+
import mdx from '@mdx-js/rollup'
|
11
|
+
import { Path, Str } from '@wollybeard/kit'
|
12
|
+
import remarkGfm from 'remark-gfm'
|
13
|
+
|
14
|
+
const _debug = debug.sub(`vite-plugin-pages`)
|
15
|
+
|
16
|
+
export const viProjectPages = polenVirtual([`project`, `pages.jsx`], { allowPluginProcessing: true })
|
17
|
+
export const viProjectPagesData = polenVirtual([`project`, `data`, 'pages.jsonsuper'], { allowPluginProcessing: true })
|
18
|
+
|
19
|
+
export interface PagesTreePluginOptions {
|
20
|
+
config: Config.Config
|
21
|
+
navbarData?: NavbarDataRegistry
|
22
|
+
onPagesChange?: (pages: FileRouter.ScanResult) => void
|
23
|
+
onTreeChange?: (tree: FileRouter.RouteTreeNode) => void
|
24
|
+
}
|
25
|
+
|
26
|
+
export interface ProjectDataPages {
|
27
|
+
sidebarIndex: SidebarIndex
|
28
|
+
pagesScanResult: FileRouter.ScanResult
|
29
|
+
}
|
30
|
+
|
31
|
+
export interface SidebarIndex {
|
32
|
+
[pathExpression: string]: FileRouter.Sidebar.Sidebar
|
33
|
+
}
|
34
|
+
|
35
|
+
/**
|
36
|
+
* Pages plugin with tree support
|
37
|
+
*/
|
38
|
+
export const Pages = ({
|
39
|
+
config,
|
40
|
+
navbarData,
|
41
|
+
onPagesChange,
|
42
|
+
onTreeChange,
|
43
|
+
}: PagesTreePluginOptions): Vite.Plugin[] => {
|
44
|
+
let currentPagesData: FileRouter.ScanResult | null = null
|
45
|
+
let currentTreeData: FileRouter.RouteTreeNode | null = null
|
46
|
+
|
47
|
+
// State management
|
48
|
+
let pagesCache: FileRouter.ScanResult | null = null
|
49
|
+
let treeCache: FileRouter.RouteTreeNode | null = null
|
50
|
+
|
51
|
+
// Helper functions
|
52
|
+
const scanPages = async () => {
|
53
|
+
if (!pagesCache) {
|
54
|
+
_debug(`Scanning pages - cache is null, loading fresh data`)
|
55
|
+
pagesCache = await FileRouter.scan({
|
56
|
+
dir: config.paths.project.absolute.pages,
|
57
|
+
glob: `**/*.{md,mdx}`,
|
58
|
+
})
|
59
|
+
_debug(`Found ${String(pagesCache.routes.length)} pages`)
|
60
|
+
} else {
|
61
|
+
_debug(`Using cached pages`)
|
62
|
+
}
|
63
|
+
return pagesCache
|
64
|
+
}
|
65
|
+
|
66
|
+
const scanTree = async () => {
|
67
|
+
if (!treeCache) {
|
68
|
+
_debug(`Scanning tree - cache is null, loading fresh data`)
|
69
|
+
const result = await FileRouter.scanTree({
|
70
|
+
dir: config.paths.project.absolute.pages,
|
71
|
+
glob: `**/*.{md,mdx}`,
|
72
|
+
})
|
73
|
+
treeCache = result.routeTree
|
74
|
+
_debug(`Built route tree`)
|
75
|
+
} else {
|
76
|
+
_debug(`Using cached tree`)
|
77
|
+
}
|
78
|
+
return treeCache
|
79
|
+
}
|
80
|
+
|
81
|
+
const clearCache = () => {
|
82
|
+
_debug(`Clearing pages and tree cache`)
|
83
|
+
pagesCache = null
|
84
|
+
treeCache = null
|
85
|
+
}
|
86
|
+
|
87
|
+
const isPageFile = (file: string) => {
|
88
|
+
return (file.endsWith(`.md`) || file.endsWith(`.mdx`))
|
89
|
+
&& file.includes(config.paths.project.absolute.pages)
|
90
|
+
}
|
91
|
+
|
92
|
+
const generatePagesModule = (pagesScanResult: FileRouter.ScanResult): string => {
|
93
|
+
const $ = {
|
94
|
+
pages: `pages`,
|
95
|
+
}
|
96
|
+
|
97
|
+
const s = Str.Builder()
|
98
|
+
s`export const ${$.pages} = []`
|
99
|
+
|
100
|
+
// Generate imports and route objects
|
101
|
+
for (const route of pagesScanResult.routes) {
|
102
|
+
const filePathExp = Path.format(route.file.path.absolute)
|
103
|
+
const pathExp = FileRouter.routeToPathExpression(route)
|
104
|
+
const ident = Str.Case.camel(`page ` + Str.titlizeSlug(pathExp))
|
105
|
+
|
106
|
+
s`
|
107
|
+
import ${ident} from '${filePathExp}'
|
108
|
+
|
109
|
+
${$.pages}.push({
|
110
|
+
path: '${pathExp}',
|
111
|
+
Component: ${ident}
|
112
|
+
})
|
113
|
+
`
|
114
|
+
}
|
115
|
+
|
116
|
+
return s.render()
|
117
|
+
}
|
118
|
+
|
119
|
+
return [
|
120
|
+
// Plugin 1: MDX Processing
|
121
|
+
{
|
122
|
+
enforce: `pre` as const,
|
123
|
+
...mdx({
|
124
|
+
jsxImportSource: `polen/react`,
|
125
|
+
remarkPlugins: [remarkGfm],
|
126
|
+
}),
|
127
|
+
},
|
128
|
+
|
129
|
+
// Plugin 2: Pages Management
|
130
|
+
{
|
131
|
+
name: `polen:pages`,
|
132
|
+
|
133
|
+
// Dev server configuration
|
134
|
+
configureServer(server) {
|
135
|
+
// Add pages directory to watcher
|
136
|
+
_debug(`configureServer: watch pages directory`, config.paths.project.absolute.pages)
|
137
|
+
server.watcher.add(config.paths.project.absolute.pages)
|
138
|
+
},
|
139
|
+
|
140
|
+
// Hot update handling
|
141
|
+
async handleHotUpdate({ file, server, modules }) {
|
142
|
+
_debug(`handleHotUpdate`, file)
|
143
|
+
if (!isPageFile(file)) return
|
144
|
+
|
145
|
+
_debug(`Page file changed:`, file)
|
146
|
+
|
147
|
+
// Check if this is a content-only change to an existing page
|
148
|
+
const oldPages = pagesCache
|
149
|
+
|
150
|
+
// Clear cache and rescan
|
151
|
+
clearCache()
|
152
|
+
const newPages = await scanPages()
|
153
|
+
currentPagesData = newPages
|
154
|
+
|
155
|
+
// Check if page structure changed (added/removed pages)
|
156
|
+
const structureChanged = !oldPages
|
157
|
+
|| oldPages.routes.length !== newPages.routes.length
|
158
|
+
|| !oldPages.routes.every((oldRoute, i) =>
|
159
|
+
oldRoute.file.path.absolute === newPages.routes[i]?.file.path.absolute
|
160
|
+
)
|
161
|
+
|
162
|
+
if (structureChanged) {
|
163
|
+
_debug(`Page structure changed, triggering full reload`)
|
164
|
+
|
165
|
+
// Invalidate virtual module
|
166
|
+
const mod = server.moduleGraph.getModuleById(viProjectPages.id)
|
167
|
+
if (mod) {
|
168
|
+
server.moduleGraph.invalidateModule(mod)
|
169
|
+
_debug(`Invalidated pages virtual module`)
|
170
|
+
}
|
171
|
+
|
172
|
+
// Notify about changes
|
173
|
+
if (onPagesChange) {
|
174
|
+
reportDiagnostics(newPages.diagnostics)
|
175
|
+
onPagesChange(newPages)
|
176
|
+
}
|
177
|
+
|
178
|
+
if (onTreeChange) {
|
179
|
+
const tree = await scanTree()
|
180
|
+
onTreeChange(tree)
|
181
|
+
currentTreeData = tree
|
182
|
+
}
|
183
|
+
|
184
|
+
// Trigger full reload for structure changes
|
185
|
+
server.ws.send({ type: `full-reload` })
|
186
|
+
return []
|
187
|
+
} else {
|
188
|
+
_debug(`Page content changed, allowing HMR`)
|
189
|
+
// Let default HMR handle the MDX file change
|
190
|
+
return modules
|
191
|
+
}
|
192
|
+
},
|
193
|
+
resolveId(id) {
|
194
|
+
if (id === viProjectPagesData.id) {
|
195
|
+
return viProjectPagesData.resolved
|
196
|
+
}
|
197
|
+
},
|
198
|
+
load: {
|
199
|
+
// filter: {
|
200
|
+
// id: viProjectPagesData.resolved,
|
201
|
+
// },
|
202
|
+
async handler(id) {
|
203
|
+
if (id !== viProjectPagesData.resolved) return
|
204
|
+
_debug(`viProjectDataPages`)
|
205
|
+
|
206
|
+
// Get pages data from the pages plugin or load initially
|
207
|
+
if (!currentPagesData) {
|
208
|
+
_debug(`loadingPagesDataInitially`)
|
209
|
+
currentPagesData = await FileRouter.scan({
|
210
|
+
dir: config.paths.project.absolute.pages,
|
211
|
+
glob: `**/*.{md,mdx}`,
|
212
|
+
})
|
213
|
+
// Report any diagnostics from initial scan
|
214
|
+
reportDiagnostics(currentPagesData.diagnostics)
|
215
|
+
}
|
216
|
+
if (!currentTreeData) {
|
217
|
+
_debug(`loadingTreeDataInitially`)
|
218
|
+
currentTreeData = await getRouteTree(config)
|
219
|
+
}
|
220
|
+
const pagesScanResult = currentPagesData
|
221
|
+
const routeTree = currentTreeData
|
222
|
+
_debug(`usingPageRoutesFromPagesPlugin`, pagesScanResult.routes.length)
|
223
|
+
|
224
|
+
//
|
225
|
+
// ━━ Build Navbar
|
226
|
+
//
|
227
|
+
|
228
|
+
// Update navbar if provided
|
229
|
+
if (navbarData) {
|
230
|
+
const navbarPages = navbarData.get('pages')
|
231
|
+
navbarPages.length = 0 // Clear existing
|
232
|
+
|
233
|
+
// Process first-level children as navigation items
|
234
|
+
for (const child of routeTree.children) {
|
235
|
+
if (child.value.type === 'directory') {
|
236
|
+
// Check if this directory has an index file
|
237
|
+
const hasIndex = child.children.some(c => c.value.type === 'file' && c.value.name === 'index')
|
238
|
+
|
239
|
+
if (hasIndex) {
|
240
|
+
const pathExp = FileRouter.pathToExpression([child.value.name])
|
241
|
+
const title = Str.titlizeSlug(child.value.name)
|
242
|
+
navbarPages.push({
|
243
|
+
pathExp: pathExp.startsWith('/') ? pathExp.slice(1) : pathExp,
|
244
|
+
title,
|
245
|
+
})
|
246
|
+
}
|
247
|
+
} else if (child.value.type === 'file' && child.value.name !== 'index') {
|
248
|
+
const pathExp = FileRouter.pathToExpression([child.value.name])
|
249
|
+
const title = Str.titlizeSlug(child.value.name)
|
250
|
+
navbarPages.push({
|
251
|
+
pathExp: pathExp.startsWith('/') ? pathExp.slice(1) : pathExp,
|
252
|
+
title,
|
253
|
+
})
|
254
|
+
}
|
255
|
+
}
|
256
|
+
}
|
257
|
+
|
258
|
+
//
|
259
|
+
// ━━ Build Sidebar
|
260
|
+
//
|
261
|
+
|
262
|
+
const sidebarIndex: SidebarIndex = {}
|
263
|
+
|
264
|
+
// Build sidebar for each top-level directory
|
265
|
+
for (const child of routeTree.children) {
|
266
|
+
if (child.value.type === 'directory') {
|
267
|
+
const pathExp = `/${child.value.name}`
|
268
|
+
// Create a subtree starting from this directory
|
269
|
+
const subtree = Tree.node(child.value, child.children)
|
270
|
+
// Pass the directory name as base path so paths are built correctly
|
271
|
+
const sidebar = FileRouter.Sidebar.buildFromTree(subtree, [child.value.name])
|
272
|
+
_debug(`Built sidebar for ${pathExp}:`, sidebar)
|
273
|
+
sidebarIndex[pathExp] = sidebar
|
274
|
+
}
|
275
|
+
}
|
276
|
+
|
277
|
+
//
|
278
|
+
// ━━ Put It All together
|
279
|
+
//
|
280
|
+
|
281
|
+
const projectDataPages: ProjectDataPages = {
|
282
|
+
sidebarIndex,
|
283
|
+
pagesScanResult: pagesScanResult,
|
284
|
+
}
|
285
|
+
|
286
|
+
// Return just the JSON string - let the JSON plugin handle the transformation
|
287
|
+
return superjson.stringify(projectDataPages)
|
288
|
+
},
|
289
|
+
},
|
290
|
+
},
|
291
|
+
// Plugin 4: Virtual Module for Pages Routes
|
292
|
+
{
|
293
|
+
name: 'polen:pages:routes',
|
294
|
+
resolveId(id) {
|
295
|
+
if (id === viProjectPages.id) {
|
296
|
+
return viProjectPages.resolved
|
297
|
+
}
|
298
|
+
},
|
299
|
+
load: {
|
300
|
+
// filter: {
|
301
|
+
// id: viProjectPages.resolved,
|
302
|
+
// },
|
303
|
+
handler: async (id) => {
|
304
|
+
if (id !== viProjectPages.resolved) return
|
305
|
+
|
306
|
+
_debug(`Loading viProjectPages virtual module`)
|
307
|
+
|
308
|
+
// Ensure we have pages data
|
309
|
+
if (!currentPagesData) {
|
310
|
+
currentPagesData = await scanPages()
|
311
|
+
reportDiagnostics(currentPagesData.diagnostics)
|
312
|
+
}
|
313
|
+
|
314
|
+
// Generate the module code
|
315
|
+
return {
|
316
|
+
code: generatePagesModule(currentPagesData),
|
317
|
+
moduleType: 'js',
|
318
|
+
}
|
319
|
+
},
|
320
|
+
},
|
321
|
+
},
|
322
|
+
]
|
323
|
+
}
|
324
|
+
|
325
|
+
// Helper to get tree
|
326
|
+
export const getRouteTree = async (config: Config.Config): Promise<FileRouter.RouteTreeNode> => {
|
327
|
+
const result = await FileRouter.scanTree({
|
328
|
+
dir: config.paths.project.absolute.pages,
|
329
|
+
glob: `**/*.{md,mdx}`,
|
330
|
+
})
|
331
|
+
return result.routeTree
|
332
|
+
}
|
@@ -1,11 +1,11 @@
|
|
1
1
|
import type { Config } from '#api/config/index'
|
2
|
+
import { reportError } from '#api/server/report-error'
|
2
3
|
import type { Hono } from '#dep/hono/index'
|
3
4
|
import type { Vite } from '#dep/vite/index'
|
5
|
+
import { ResponseInternalServerError } from '#lib/kit-temp'
|
4
6
|
import { debug } from '#singletons/debug'
|
5
7
|
import * as HonoNodeServer from '@hono/node-server'
|
6
|
-
import { Err
|
7
|
-
import cleanStack from 'clean-stack'
|
8
|
-
import { ErrorParser } from 'youch-core'
|
8
|
+
import { Err } from '@wollybeard/kit'
|
9
9
|
|
10
10
|
type App = Hono.Hono
|
11
11
|
|
@@ -28,25 +28,7 @@ export const Serve = (
|
|
28
28
|
if (Err.is(error)) {
|
29
29
|
// ━ Clean Stack Trace
|
30
30
|
server.ssrFixStacktrace(error)
|
31
|
-
|
32
|
-
pathFilter: (path) => {
|
33
|
-
return !path.match(/.*rolldown-vite.*/)
|
34
|
-
},
|
35
|
-
basePath: config.paths.project.rootDir,
|
36
|
-
// pretty: true,
|
37
|
-
})
|
38
|
-
error.stack = stack
|
39
|
-
// ━ Log Error
|
40
|
-
Err.log(error)
|
41
|
-
const parser = new ErrorParser()
|
42
|
-
const parsedError = await parser.parse(error)
|
43
|
-
const snippet = parsedError.frames[0]?.source?.map(line => {
|
44
|
-
return line.lineNumber.toString().padStart(4, ' ') + `: ` + line.chunk
|
45
|
-
}).join(`\n`)
|
46
|
-
if (snippet) {
|
47
|
-
console.log('-----------------------------')
|
48
|
-
console.log(snippet)
|
49
|
-
}
|
31
|
+
reportError(error)
|
50
32
|
return error
|
51
33
|
}
|
52
34
|
throw error
|
@@ -97,10 +79,7 @@ export const Serve = (
|
|
97
79
|
const app = await appPromise
|
98
80
|
if (Err.is(app)) {
|
99
81
|
// Err.log(app)
|
100
|
-
return
|
101
|
-
status: Http.Status.InternalServerError.code,
|
102
|
-
statusText: Http.Status.InternalServerError.description,
|
103
|
-
})
|
82
|
+
return ResponseInternalServerError()
|
104
83
|
}
|
105
84
|
const response = await app.fetch(request, { viteDevServer: server })
|
106
85
|
return response
|
package/src/cli/commands/dev.ts
CHANGED
@@ -8,6 +8,7 @@ import { Err, Path } from '@wollybeard/kit'
|
|
8
8
|
import { z } from 'zod'
|
9
9
|
|
10
10
|
const args = Command.create()
|
11
|
+
.parameter(`--debug -d`, z.boolean().optional())
|
11
12
|
.parameter(
|
12
13
|
`--project -p`,
|
13
14
|
// @ts-expect-error
|
@@ -28,7 +29,14 @@ const args = Command.create()
|
|
28
29
|
|
29
30
|
const dir = ensureOptionalAbsoluteWithCwd(args.project) as string
|
30
31
|
|
31
|
-
const viteUserConfig = await Api.ConfigResolver.fromFile({
|
32
|
+
const viteUserConfig = await Api.ConfigResolver.fromFile({
|
33
|
+
dir,
|
34
|
+
overrides: {
|
35
|
+
advanced: {
|
36
|
+
debug: args.debug,
|
37
|
+
},
|
38
|
+
},
|
39
|
+
})
|
32
40
|
|
33
41
|
const viteDevServer = await Err.tryCatch(() => Vite.createServer(viteUserConfig))
|
34
42
|
|