duto 0.260915.0 → 0.261001.0
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 +1 -1
- package/package.json +1 -1
- package/src/commands/new.ts +55 -30
- package/src/commands/templates/pages/README.md +21 -0
- package/src/commands/templates/pages/_gitignore +24 -0
- package/src/commands/templates/pages/components/locale-select.tsx +59 -0
- package/src/commands/templates/pages/components/select.tsx +95 -0
- package/src/commands/templates/pages/i18n/en.ts +17 -0
- package/src/commands/templates/pages/i18n/index.ts +19 -0
- package/src/commands/templates/pages/i18n/pt-br.ts +17 -0
- package/src/commands/templates/pages/package.json +22 -0
- package/src/commands/templates/pages/pages/404.tsx +12 -0
- package/src/commands/templates/pages/pages/index.tsx +16 -0
- package/src/commands/templates/pages/pages/layout.tsx +24 -0
- package/src/commands/templates/pages/style.css +24 -0
- package/src/commands/templates/pages/tsconfig.json +54 -0
- package/src/commands/templates/pages/types.ts +8 -0
- package/src/commands/templates/server/base/.editorconfig +21 -0
- package/src/commands/templates/{base → server/base}/README.md +1 -1
- package/src/pages/cli/commands/dev.ts +10 -4
- package/src/pages/cli/utils.ts +3 -22
- package/src/pages/client/app.tsx +26 -73
- package/src/pages/client/router.ts +14 -280
- package/src/pages/compiler/aliases.ts +2 -8
- package/src/pages/compiler/ast.ts +1 -538
- package/src/pages/compiler/constants.ts +95 -13
- package/src/pages/compiler/index.ts +20 -126
- package/src/pages/compiler/meta.ts +38 -227
- package/src/pages/compiler/routes.ts +4 -5
- package/src/pages/compiler/types.ts +1 -101
- package/src/pages/compiler/vite-plugin.ts +73 -27
- package/src/pages/i18n/client.ts +18 -6
- package/src/pages/i18n/server.ts +21 -6
- package/src/pages/index.ts +1 -2
- package/src/server/routes.ts +4 -26
- package/src/utils.ts +34 -3
- package/src/pages/compiler/island.ts +0 -108
- /package/src/commands/templates/{base → pages}/.editorconfig +0 -0
- /package/src/commands/templates/{base → server/base}/.env.dev.example +0 -0
- /package/src/commands/templates/{base → server/base}/.env.prod.example +0 -0
- /package/src/commands/templates/{base → server/base}/_gitignore +0 -0
- /package/src/commands/templates/{base → server/base}/actions/blog/index.get.ts +0 -0
- /package/src/commands/templates/{base → server/base}/actions/blog/post/[id].get.ts +0 -0
- /package/src/commands/templates/{base → server/base}/actions/index.get.ts +0 -0
- /package/src/commands/templates/{base → server/base}/configs/duto.ts +0 -0
- /package/src/commands/templates/{base → server/base}/configs/roles.ts +0 -0
- /package/src/commands/templates/{base → server/base}/package.json +0 -0
- /package/src/commands/templates/{base → server/base}/tsconfig.json +0 -0
- /package/src/commands/templates/{workerd → server/workerd}/wrangler.toml +0 -0
|
@@ -1,30 +1,23 @@
|
|
|
1
|
+
import { promisify } from 'node:util'
|
|
2
|
+
import { brotliCompress } from 'node:zlib'
|
|
1
3
|
import { mkdir } from 'node:fs/promises'
|
|
2
4
|
import { join, dirname } from 'node:path'
|
|
3
|
-
import { getLayouts, parsePage, resolveStaticOutputPath } from './meta'
|
|
4
5
|
|
|
5
6
|
import { h } from 'preact'
|
|
6
7
|
import { render } from 'preact-render-to-string'
|
|
7
8
|
import minify from '@minify-html/node'
|
|
8
9
|
|
|
9
|
-
import
|
|
10
|
+
import { JSJSON } from 't0n'
|
|
10
11
|
import { DOCTYPE_RE } from './constants'
|
|
11
|
-
import { getAsset, getChunk
|
|
12
|
-
|
|
13
|
-
import type { IRoute, Metadata, RouteParams, StaticProps, SummaryMetadata } from './types'
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
// import i18n from '../client/i18n'
|
|
12
|
+
import { getAsset, getChunk } from './assets'
|
|
13
|
+
import { getLayouts, resolveStaticOutputPath } from './meta'
|
|
17
14
|
import { setLocale } from '../i18n/client'
|
|
18
15
|
|
|
16
|
+
import type { ResolvedConfig } from 'vite'
|
|
17
|
+
import type { IRoute, Metadata, RouteParams, StaticProps, SummaryMetadata } from './types'
|
|
19
18
|
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
import { brotliCompress } from 'node:zlib'
|
|
23
|
-
|
|
24
|
-
const brCompress = promisify(brotliCompress);
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
export const selfCloseEmptyTags = (html: string, tagName: string) => html.replace(new RegExp(`<${tagName}\\b([^>]*?)>\\s*</${tagName}>`, 'g'), (_, attrs) => `<${tagName}${attrs} />`)
|
|
20
|
+
const brCompress = promisify(brotliCompress)
|
|
28
21
|
|
|
29
22
|
export async function renderPage(
|
|
30
23
|
meta: Metadata,
|
|
@@ -32,40 +25,15 @@ export async function renderPage(
|
|
|
32
25
|
page: IRoute
|
|
33
26
|
) {
|
|
34
27
|
const {
|
|
35
|
-
mod,
|
|
28
|
+
mod,
|
|
36
29
|
hasGetProps, hasGetStaticProps,
|
|
37
30
|
isClientOnly,
|
|
38
|
-
} =
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
// hasGetProps, hasGetStaticProps,
|
|
42
|
-
// isClientOnly,
|
|
43
|
-
// } = page
|
|
44
|
-
|
|
45
|
-
if (!mod?.default) {
|
|
46
|
-
console.warn(`No default export in ${page.filePath} — skipping`)
|
|
47
|
-
return
|
|
48
|
-
}
|
|
31
|
+
} = page
|
|
32
|
+
if (!mod?.default)
|
|
33
|
+
return console.warn(`No default export in ${page.filePath} — skipping`)
|
|
49
34
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
// console.error('hasGetStaticProps:', hasGetStaticProps)
|
|
53
|
-
// console.error('isClientOnly:', isClientOnly)
|
|
54
|
-
|
|
55
|
-
if (page.isInternal || page.is404 || (page.isDynamic && !hasGetStaticProps)) {
|
|
56
|
-
meta.summary.set('/'+ page.fileName, {
|
|
57
|
-
type: 2,
|
|
58
|
-
path: '/'+ page.fileName,
|
|
59
|
-
size: 0,
|
|
60
|
-
sizeBr: 0,
|
|
61
|
-
sizeJS: 0,
|
|
62
|
-
})
|
|
63
|
-
// meta.routes.set(page.fullFilePath, page)
|
|
64
|
-
return
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// console.log(meta.routes.size)
|
|
68
|
-
// meta.routes.set(page.filePath, page)
|
|
35
|
+
if (page.isInternal || page.is404 || (page.isDynamic && !hasGetStaticProps))
|
|
36
|
+
return meta.summary.set('/'+ page.fileName, { type: 2, path: '/'+ page.fileName, size: 0, sizeBr: 0, sizeJS: 0 })
|
|
69
37
|
|
|
70
38
|
const { filePath, pattern, params } = page
|
|
71
39
|
|
|
@@ -108,7 +76,6 @@ export async function renderPage(
|
|
|
108
76
|
const allProps = { ...prop.pageProps, ...prop.routeParams }
|
|
109
77
|
|
|
110
78
|
// @ts-ignore
|
|
111
|
-
// i18n(allProps?.locale || meta.i18n.fallbackLocale, meta.i18n.locales, meta.i18n.messages, meta.i18n.routes, meta.i18n.routeMap)
|
|
112
79
|
allProps?.locale && setLocale(allProps?.locale || meta.i18n.fallbackLocale)
|
|
113
80
|
|
|
114
81
|
const pathname = resolveStaticOutputPath(page, prop.routeParams)
|
|
@@ -138,34 +105,10 @@ export async function renderPage(
|
|
|
138
105
|
}
|
|
139
106
|
// }
|
|
140
107
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
// console.error('needsClient: ', needsClient)
|
|
146
|
-
|
|
147
|
-
const assets = []
|
|
148
|
-
for (const [depPath, dep] of meta.map.get(page.fullFilePath)!.deps)
|
|
149
|
-
assets.push(normalizeId(dep.path))
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
html = buildHtml(assets, html) //, needsClient, allProps, pattern, islands)
|
|
153
|
-
// html = selfCloseEmptyTags(String(minify.minify(
|
|
154
|
-
// Buffer.from(buildHtml(assets, html, needsClient, allProps, pattern, islands)),
|
|
155
|
-
// {}
|
|
156
|
-
// // options != null ? options : {},
|
|
157
|
-
// )), 'i-i')
|
|
158
|
-
|
|
159
|
-
const outFile = join(
|
|
160
|
-
config.root,
|
|
161
|
-
config.build.outDir,
|
|
162
|
-
pathname +'.html'
|
|
163
|
-
)
|
|
164
|
-
const outHTML = meta.minify ? minify.minify(
|
|
165
|
-
Buffer.from(html),
|
|
166
|
-
{}
|
|
167
|
-
// options != null ? options : {},
|
|
168
|
-
) : html
|
|
108
|
+
html = buildHtml(html, Object.keys(allProps).length ? allProps : undefined)
|
|
109
|
+
|
|
110
|
+
const outFile = join(config.root, config.build.outDir, pathname +'.html')
|
|
111
|
+
const outHTML = meta.minify ? minify.minify(Buffer.from(html), {}) : html
|
|
169
112
|
await mkdir(dirname(outFile), {recursive: true})
|
|
170
113
|
await Bun.write(outFile, outHTML)
|
|
171
114
|
|
|
@@ -206,12 +149,8 @@ export async function renderPage(
|
|
|
206
149
|
}
|
|
207
150
|
|
|
208
151
|
function buildHtml(
|
|
209
|
-
_assets: string[],
|
|
210
152
|
html: string,
|
|
211
|
-
|
|
212
|
-
// props?: StaticProps,
|
|
213
|
-
// routePattern?: string,
|
|
214
|
-
// islands?: Island[],
|
|
153
|
+
props?: StaticProps,
|
|
215
154
|
): string {
|
|
216
155
|
if (!(html.includes('<body') || html.includes('<html') || html.includes('<head')))
|
|
217
156
|
html = wrapHtml(html)
|
|
@@ -219,58 +158,14 @@ function buildHtml(
|
|
|
219
158
|
if (!DOCTYPE_RE.test(html))
|
|
220
159
|
html = '<!DOCTYPE html>'+ html
|
|
221
160
|
|
|
222
|
-
// const pageProps = needsClient
|
|
223
|
-
// ? `<script>
|
|
224
|
-
// window.__PROPS__ = ${JSON.stringify(props ?? {})};
|
|
225
|
-
// </script>`
|
|
226
|
-
// : ''
|
|
227
|
-
|
|
228
161
|
const assets = [
|
|
229
162
|
':duto/client/app.tsx',
|
|
230
|
-
// ..._assets,
|
|
231
163
|
]
|
|
232
164
|
|
|
233
165
|
const prepend = assets.map(asset => {
|
|
234
166
|
const href = getAsset(asset)
|
|
235
167
|
return href ? `<link href="${href}" rel=stylesheet>` : null
|
|
236
168
|
}).filter(Boolean).join('')
|
|
237
|
-
// + `<style>d-b,d-p,i-d,i-s{display:contents}</style>`
|
|
238
|
-
// + `<style>d,d-slot,d-s-slot{display:contents}</style>`
|
|
239
|
-
|
|
240
|
-
// d>*,d-slot>*,d-s-slot>*{display:revert}
|
|
241
|
-
|
|
242
|
-
// d {
|
|
243
|
-
// display: block;
|
|
244
|
-
// box-sizing: border-box;
|
|
245
|
-
// }
|
|
246
|
-
|
|
247
|
-
// /* Herda todos os estilos padrão de div */
|
|
248
|
-
// d:not([hidden]) {
|
|
249
|
-
// display: block;
|
|
250
|
-
// }
|
|
251
|
-
|
|
252
|
-
// /* Remove qualquer comportamento de display:contents */
|
|
253
|
-
// d, d-slot, d-s-slot {
|
|
254
|
-
// display: block !important;
|
|
255
|
-
// }
|
|
256
|
-
|
|
257
|
-
// d *,
|
|
258
|
-
// d-slot *,
|
|
259
|
-
// d-s-slot * {
|
|
260
|
-
// visibility: visible !important;
|
|
261
|
-
// opacity: 1 !important;
|
|
262
|
-
// }
|
|
263
|
-
// </style>
|
|
264
|
-
|
|
265
|
-
// <script>class DDiv extends HTMLElement {
|
|
266
|
-
// constructor() {
|
|
267
|
-
// super();
|
|
268
|
-
// }
|
|
269
|
-
// }
|
|
270
|
-
|
|
271
|
-
// if (typeof customElements !== 'undefined' && !customElements.get('d')) {
|
|
272
|
-
// customElements.define('d', DDiv);
|
|
273
|
-
// }</script>
|
|
274
169
|
|
|
275
170
|
if (html.includes('</head>')) {
|
|
276
171
|
html = html.replace('</head>', prepend +'</head>')
|
|
@@ -280,8 +175,7 @@ function buildHtml(
|
|
|
280
175
|
html = prepend + html
|
|
281
176
|
}
|
|
282
177
|
|
|
283
|
-
|
|
284
|
-
const append = assets.map(file => {
|
|
178
|
+
const append = (props ? `<script>(self.$duto=self.$duto||{}).props=${JSJSON(props)}</script>` : '') + assets.map(file => {
|
|
285
179
|
const src = getChunk(file)
|
|
286
180
|
return src ? `<script src="${src}" type=module></script>` : null
|
|
287
181
|
}).filter(Boolean).join('')
|
|
@@ -4,150 +4,65 @@
|
|
|
4
4
|
// https://github.com/cloudflare/vinext/blob/main/packages/vinext/src/entries/pages-client-entry.ts
|
|
5
5
|
// https://github.com/cloudflare/vinext/blob/main/packages/vinext/src/shims/ALS-ARCHITECTURE.md
|
|
6
6
|
|
|
7
|
-
import { dirname, extname
|
|
8
|
-
import { readdirSync } from 'node:fs'
|
|
7
|
+
import { dirname, extname } from 'node:path'
|
|
9
8
|
|
|
10
|
-
import { getEnv,
|
|
9
|
+
import { getEnv, JSJSON, newID } from 't0n'
|
|
11
10
|
|
|
12
11
|
import { getAliases } from './aliases'
|
|
13
|
-
import {
|
|
12
|
+
import { DYNAMIC_RE, INTERNAL_RE, LAYOUT_RE, NF_NAMES, FILE_EXTENSIONS } from './constants'
|
|
13
|
+
import { scan } from '@/utils'
|
|
14
14
|
|
|
15
15
|
import { USE_CLIENT_RE } from './constants'
|
|
16
|
-
import { parseSync } from '@swc/core'
|
|
17
|
-
import { findUsage, getFileMap } from './ast'
|
|
18
|
-
import { replaceIslands } from './island'
|
|
19
|
-
import { mkdir } from 'node:fs/promises'
|
|
20
|
-
|
|
21
16
|
|
|
22
17
|
import getI18n from '../i18n/server'
|
|
23
18
|
import i18n from '../i18n/client'
|
|
24
19
|
|
|
25
20
|
import type {
|
|
26
|
-
PageModule,
|
|
27
21
|
IRoute, RouteParam, RouteParams,
|
|
28
22
|
Metadata,
|
|
29
|
-
ImportUsage,
|
|
30
23
|
SummaryMetadata,
|
|
31
24
|
} from './types'
|
|
32
25
|
|
|
33
|
-
export function getAssets(meta: Metadata): Set<string> {
|
|
34
|
-
const deps = new Set<string>()
|
|
35
|
-
const queue: string[] = []
|
|
36
|
-
const dir = join(meta.root, meta.dir)
|
|
37
|
-
|
|
38
|
-
for (const [path] of meta.map) {
|
|
39
|
-
if (path.startsWith(dir))
|
|
40
|
-
queue.push(path)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
while (queue.length > 0) {
|
|
44
|
-
const path = queue.pop()!
|
|
45
|
-
const imports = meta.map.get(path)!.deps
|
|
46
|
-
if (!imports?.size) continue
|
|
47
|
-
|
|
48
|
-
for (const [dep] of imports) {
|
|
49
|
-
if (!dep.startsWith(meta.root) || dep.startsWith(dir) || deps.has(dep)) continue
|
|
50
|
-
deps.add(dep)
|
|
51
|
-
if (dep in meta.map) queue.push(dep)
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return deps
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
export async function parsePage(page: IRoute, meta: Metadata) {
|
|
60
|
-
const fileMeta = meta.map.get(page.fullFilePath)!
|
|
61
|
-
if (!meta.violations.has(page.fullFilePath)) {
|
|
62
|
-
return page
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const islands: ImportUsage[] = []
|
|
66
|
-
const ast = parseSync(fileMeta.content, { syntax: 'typescript', tsx: true })
|
|
67
|
-
for (const [depPath, dep] of fileMeta.deps) {
|
|
68
|
-
// console.error(depPath, page.fullFilePath)
|
|
69
|
-
if (!meta.violations.has(depPath)) continue
|
|
70
|
-
|
|
71
|
-
const usages = findUsage(fileMeta.content, dep.ref, ast)
|
|
72
|
-
// console.log(usages, dep.ref)
|
|
73
|
-
islands.push(...usages)
|
|
74
|
-
// for (const usage of usages)
|
|
75
|
-
// islands.push(...usage.usages)
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
// console.log(id)
|
|
79
|
-
// console.log(usage)
|
|
80
|
-
// console.log(usage[0].usages)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// // Limpar linhas vazias extras
|
|
84
|
-
// result = result.replace(/^\s*\n/gm, '')
|
|
85
|
-
|
|
86
|
-
const content = await replaceIslands(fileMeta.content, islands)
|
|
87
|
-
// @ts-ignore
|
|
88
|
-
let mod: PageModule = {}
|
|
89
|
-
const tmpPath = join(meta.root, 'tmp', page.filePath)
|
|
90
|
-
try {
|
|
91
|
-
await mkdir(dirname(tmpPath), {recursive: true})
|
|
92
|
-
await Bun.write(tmpPath, content)
|
|
93
|
-
mod = await IMPORT(tmpPath)
|
|
94
|
-
} catch {}
|
|
95
|
-
|
|
96
|
-
return {
|
|
97
|
-
safeFilePath: tmpPath,
|
|
98
|
-
mod, content, islands,
|
|
99
|
-
hasGetStaticProps: typeof mod.getStaticProps === 'function',
|
|
100
|
-
hasGetProps: typeof mod.getProps === 'function',
|
|
101
|
-
isClientOnly: USE_CLIENT_RE.test(content),
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
26
|
|
|
106
27
|
// TODO: https://github.com/cloudflare/vinext/blob/adfc2236cba5f7cde63f32f6fb35c0d892428376/packages/vinext/src/routing/file-matcher.ts#L90
|
|
107
28
|
export async function getPages(meta: Metadata) {
|
|
108
|
-
const files = readdirSync(join(meta.root, meta.dir), {recursive: true})
|
|
109
29
|
const nf = new Map<string, IRoute>()
|
|
110
30
|
const layouts = new Map<string, IRoute>()
|
|
111
31
|
const pages = new Map<string, IRoute>()
|
|
112
32
|
const spages = new Set<string>()
|
|
113
33
|
const routes: IRoute[] = []
|
|
114
34
|
|
|
115
|
-
for (const file of
|
|
116
|
-
if (typeof file !== 'string' || !EXT_RE.test(file)) continue
|
|
117
|
-
|
|
35
|
+
for await (const [file, path, mod] of scan(meta.dir, FILE_EXTENSIONS)) {
|
|
118
36
|
const ext = extname(file)
|
|
119
|
-
const
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
const name = file.replace(EXT_RE, '').split('/').pop() as string
|
|
37
|
+
const filePath = path.split(meta.dir+'/').pop() as string
|
|
38
|
+
const fileName = filePath.replace(ext, '')
|
|
39
|
+
const { pattern, params } = filePathToWouterPattern(fileName)
|
|
123
40
|
|
|
124
|
-
const
|
|
125
|
-
const
|
|
41
|
+
const name = file.replace(ext, '').split('/').pop() as string
|
|
42
|
+
const content = await Bun.file(file).text()
|
|
126
43
|
|
|
127
|
-
// console.error(file, INTERNAL_RE.test(file))
|
|
128
44
|
const page = {
|
|
129
45
|
fileExt: ext.substring(1),
|
|
130
|
-
fileName
|
|
131
|
-
filePath
|
|
132
|
-
fullFilePath,
|
|
46
|
+
fileName,
|
|
47
|
+
filePath,
|
|
48
|
+
fullFilePath: file,
|
|
133
49
|
pattern,
|
|
134
50
|
params,
|
|
135
51
|
is404: name ? NF_NAMES.includes(name) : false,
|
|
136
|
-
isDynamic: DYNAMIC_RE.test(
|
|
137
|
-
isInternal: INTERNAL_RE.test(
|
|
52
|
+
isDynamic: DYNAMIC_RE.test(path),
|
|
53
|
+
isInternal: INTERNAL_RE.test(path),
|
|
138
54
|
|
|
139
55
|
importName: newID(),
|
|
140
56
|
|
|
141
57
|
mod,
|
|
142
|
-
content:
|
|
143
|
-
islands: [],
|
|
58
|
+
content: content,
|
|
144
59
|
layouts: [],
|
|
145
60
|
hasGetStaticProps: typeof mod.getStaticProps === 'function',
|
|
146
61
|
hasGetProps: typeof mod.getProps === 'function',
|
|
147
|
-
isClientOnly: USE_CLIENT_RE.test(
|
|
62
|
+
isClientOnly: USE_CLIENT_RE.test(content),
|
|
148
63
|
}
|
|
149
64
|
|
|
150
|
-
if (LAYOUT_RE.test(
|
|
65
|
+
if (LAYOUT_RE.test(path)) {
|
|
151
66
|
layouts.set(page.fileName, page)
|
|
152
67
|
continue
|
|
153
68
|
}
|
|
@@ -155,14 +70,14 @@ export async function getPages(meta: Metadata) {
|
|
|
155
70
|
if (page.is404) {
|
|
156
71
|
nf.set(page.fileName, page)
|
|
157
72
|
routes.push(page)
|
|
158
|
-
pages.set(
|
|
73
|
+
pages.set(file, page)
|
|
159
74
|
continue
|
|
160
75
|
}
|
|
161
76
|
|
|
162
77
|
if (!page.isInternal)
|
|
163
|
-
pages.set(
|
|
78
|
+
pages.set(file, page)
|
|
164
79
|
|
|
165
|
-
if (!page.isInternal
|
|
80
|
+
if (!page.isInternal)
|
|
166
81
|
routes.push(page)
|
|
167
82
|
|
|
168
83
|
if (!page.isInternal) {
|
|
@@ -170,11 +85,9 @@ export async function getPages(meta: Metadata) {
|
|
|
170
85
|
try {
|
|
171
86
|
const _props = await page.mod.getStaticProps?.()
|
|
172
87
|
const props = Array.isArray(_props) ? _props : [_props]
|
|
173
|
-
for (const prop of props)
|
|
174
|
-
// console.log(prop, file)
|
|
88
|
+
for (const prop of props)
|
|
175
89
|
spages.add('/'+resolveStaticOutputPath(page, prop as any))
|
|
176
|
-
|
|
177
|
-
// spages.add('/'+resolveStaticOutputPath(page, prop as any))
|
|
90
|
+
|
|
178
91
|
} catch(e) {
|
|
179
92
|
console.log('errro', e)
|
|
180
93
|
}
|
|
@@ -192,49 +105,6 @@ export async function getPages(meta: Metadata) {
|
|
|
192
105
|
meta.routes = await sortRoutes(meta, routes)
|
|
193
106
|
}
|
|
194
107
|
|
|
195
|
-
/**
|
|
196
|
-
* A partir do path de um arquivo relativo à raiz de rotas do Next.js
|
|
197
|
-
* (app/ ou pages/), retorna:
|
|
198
|
-
*
|
|
199
|
-
* - layouts: arquivos "layout.{tsx,ts,jsx,js}" aplicáveis à rota, ordenados
|
|
200
|
-
* do mais próximo do arquivo (segmento irmão) ao mais distante (raiz).
|
|
201
|
-
* Ex.: ["users/layout.tsx", "layout.tsx"]
|
|
202
|
-
* - document: o "_document.{tsx,ts,jsx,js}" do Pages Router, se existir na
|
|
203
|
-
* raiz das rotas. Só é checado uma vez no topo, nunca por segmento — é
|
|
204
|
-
* um arquivo único, diferente do layout, que pode ser aninhado.
|
|
205
|
-
*
|
|
206
|
-
* Compatibilidade com a especificação oficial do Next.js:
|
|
207
|
-
* - App Router: nenhum arquivo especial usa prefixo "_" — é "layout", não
|
|
208
|
-
* "_layout". layout.js é o componente mais externo de um route segment e
|
|
209
|
-
* envolve template.js, error.js, loading.js, not-found.js e page.js.
|
|
210
|
-
* - Pages Router: pages/_document.js (com "_") customiza as tags <html> e
|
|
211
|
-
* <body> e existe só uma vez, na raiz de pages/. No App Router esse papel
|
|
212
|
-
* foi assumido pelo root layout.js — não há "_document" equivalente lá.
|
|
213
|
-
*/
|
|
214
|
-
// export async function getLayouts(meta: Metadata, path: string) {
|
|
215
|
-
// const isDir = existsSync(path) && statSync(path).isDirectory()
|
|
216
|
-
// const fileDir = isDir ? path : dirname(path)
|
|
217
|
-
|
|
218
|
-
// const layouts: Page[] = []
|
|
219
|
-
// let currentDir = fileDir
|
|
220
|
-
|
|
221
|
-
// while (true) {
|
|
222
|
-
// const layout = findFileByName(meta, currentDir, 'layout')
|
|
223
|
-
// if (layout && meta.pages.has(layout)) {
|
|
224
|
-
// // const mod = meta.pages.get(layout)?.mod
|
|
225
|
-
// const { mod, content } = await parsePage(meta.pages.get(layout)!, meta)
|
|
226
|
-
// if (mod?.default) layouts.push(mod.default)
|
|
227
|
-
// }
|
|
228
|
-
|
|
229
|
-
// const parentDir = dirname(currentDir)
|
|
230
|
-
// if (parentDir === currentDir) break
|
|
231
|
-
|
|
232
|
-
// currentDir = parentDir
|
|
233
|
-
// }
|
|
234
|
-
|
|
235
|
-
// return layouts
|
|
236
|
-
// }
|
|
237
|
-
|
|
238
108
|
export async function getLayouts(meta: Metadata, path: string) {
|
|
239
109
|
const layouts: IRoute[] = []
|
|
240
110
|
const segments = dirname(path).split(/[\\/]/).filter(Boolean)
|
|
@@ -242,15 +112,12 @@ export async function getLayouts(meta: Metadata, path: string) {
|
|
|
242
112
|
for (let i = segments.length; i >= 0; i--) {
|
|
243
113
|
const dir = segments.slice(0, i).join('/')
|
|
244
114
|
|
|
245
|
-
const
|
|
246
|
-
if (!
|
|
247
|
-
|
|
248
|
-
const { mod } = await parsePage(page, meta) // @ts-ignore
|
|
249
|
-
if (mod?.default) {
|
|
250
|
-
page.mod = mod
|
|
251
|
-
layouts.push(page)
|
|
252
|
-
}
|
|
115
|
+
const layout = meta.layouts.get(dir ? dir +'/_layout' : '_layout') || meta.layouts.get(dir ? dir +'/layout' : 'layout')
|
|
116
|
+
if (!layout) continue
|
|
253
117
|
|
|
118
|
+
// @ts-ignore
|
|
119
|
+
if (layout.mod?.default)
|
|
120
|
+
layouts.push(layout)
|
|
254
121
|
}
|
|
255
122
|
|
|
256
123
|
return layouts
|
|
@@ -263,27 +130,18 @@ export async function getMetadata(root: string, dir: string) {
|
|
|
263
130
|
meta.i18n = await getI18n(meta)
|
|
264
131
|
i18n(meta.i18n.fallbackLocale, meta.i18n.locales, meta.i18n.messages, meta.i18n.routes, meta.i18n.routeMap)
|
|
265
132
|
|
|
266
|
-
meta.aliases = getAliases(root)
|
|
267
|
-
const fileMap = await getFileMap(meta)
|
|
268
|
-
meta.map = fileMap.map
|
|
269
|
-
meta.violations = fileMap.violations
|
|
270
|
-
meta.assets = Array.from(getAssets(meta))
|
|
133
|
+
meta.aliases = await getAliases(root)
|
|
271
134
|
|
|
272
135
|
await getPages(meta)
|
|
273
136
|
|
|
274
137
|
meta.string = `// AUTO-GENERATED FILE - DO NOT EDIT
|
|
275
|
-
${meta.routes.
|
|
276
|
-
${Array.from(meta.layouts.values()).map(
|
|
138
|
+
${meta.routes.filter(r => r.is404).map(r => `\nimport Page${r.importName + (r.hasGetProps ? `, { getProps as getProps${r.importName} }` : '')} from '${r.fullFilePath}'`).join('\n')}
|
|
139
|
+
${Array.from(meta.layouts.values()).map(l => `\nimport Layout${l.importName} from '${l.fullFilePath}'`).join('\n')}
|
|
277
140
|
|
|
278
|
-
export const views = [${meta.routes.map(
|
|
141
|
+
export const views = [${meta.routes.map(r => `['${r.pattern}',${r.is404 ? 'Page'+ r.importName : `'${r.fullFilePath}'`},${Object.keys(r.params).length ? JSJSON(Object.entries(r.params).map(([_,v]) => v)) : '0'}${r.hasGetProps ? (r.is404 ? `,getProps${r.importName}` : `,1`) : (r.layouts.length ? ',0': '')}${r.layouts.length ? ',[' + Object.entries(r.layouts).map(([_,l]) => 'Layout'+l.importName) +']' : ''}]`).join(',')}]
|
|
279
142
|
|
|
280
143
|
export const SRoutes = new Set(${JSJSON([...meta.spages])})
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
` /// + meta.i18n.string
|
|
284
|
-
|
|
285
|
-
// console.error(meta.string)
|
|
286
|
-
// console.log(meta.map.get(`/Users/nicolau/Projects/preact-skeleton/pages/index.tsx`))
|
|
144
|
+
`
|
|
287
145
|
|
|
288
146
|
return meta
|
|
289
147
|
}
|
|
@@ -381,64 +239,19 @@ function getRouteMeta(pattern: string): RouteMeta {
|
|
|
381
239
|
segmentsCount: segments.length,
|
|
382
240
|
}
|
|
383
241
|
}
|
|
384
|
-
// //////////////////////////////////////////////////////////////////////////////////////////
|
|
385
242
|
|
|
386
|
-
// export function sortRoutes(pages: Map<string, IRoute>) {
|
|
387
|
-
// const metas = new Map<string, { score: number, segmentsCount: number }>()
|
|
388
|
-
|
|
389
|
-
// for (const [route, page] of pages)
|
|
390
|
-
// metas.set(route, computeRouteMeta(page.pattern))
|
|
391
|
-
|
|
392
|
-
// const list = Array.from(pages.values()).sort((a, b) => {
|
|
393
|
-
// const metaA = metas.get(a.fullFilePath)!
|
|
394
|
-
// const metaB = metas.get(b.fullFilePath)!
|
|
395
|
-
|
|
396
|
-
// if (metaA.score === metaB.score)
|
|
397
|
-
// return metaB.segmentsCount - metaA.segmentsCount
|
|
398
|
-
|
|
399
|
-
// return metaB.score - metaA.score
|
|
400
|
-
// })
|
|
401
|
-
|
|
402
|
-
// while (list.length && list.at(-1)?.pattern === '/') {
|
|
403
|
-
// const last = list.pop()
|
|
404
|
-
// last && list.unshift(last)
|
|
405
|
-
// }
|
|
406
|
-
|
|
407
|
-
// return list
|
|
408
|
-
// }
|
|
409
|
-
|
|
410
|
-
// function computeRouteMeta(path: string) {
|
|
411
|
-
// const segments = path.split('/').filter(Boolean)
|
|
412
|
-
|
|
413
|
-
// let score = 0
|
|
414
|
-
// for (const segment of segments) {
|
|
415
|
-
// if (segment === '*') {
|
|
416
|
-
// continue
|
|
417
|
-
// } else if (segment.startsWith(':')) {
|
|
418
|
-
// score += 1
|
|
419
|
-
// } else {
|
|
420
|
-
// score += 10
|
|
421
|
-
// }
|
|
422
|
-
// }
|
|
423
|
-
|
|
424
|
-
// return { score, segmentsCount: segments.length }
|
|
425
|
-
// }
|
|
426
|
-
|
|
427
|
-
// //////////////////////////////////////////////////////////////////////////////////////////
|
|
428
243
|
const CATCHALL_NAMES = new Set(['404', 'not-found'])
|
|
429
244
|
|
|
430
|
-
export function filePathToWouterPattern(
|
|
245
|
+
export function filePathToWouterPattern(path: string): {
|
|
431
246
|
pattern: string
|
|
432
247
|
params: Record<string, RouteParam>
|
|
433
248
|
} {
|
|
434
|
-
const withoutExt = filePath.replace(EXT_RE, '')
|
|
435
|
-
|
|
436
249
|
const normalized =
|
|
437
|
-
|
|
250
|
+
path === 'index'
|
|
438
251
|
? ''
|
|
439
|
-
:
|
|
440
|
-
?
|
|
441
|
-
:
|
|
252
|
+
: path.endsWith('/index')
|
|
253
|
+
? path.slice(0, -6)
|
|
254
|
+
: path
|
|
442
255
|
|
|
443
256
|
const segments = normalized ? normalized.split('/') : []
|
|
444
257
|
|
|
@@ -535,8 +348,6 @@ export function filePathToWouterPattern(filePath: string): {
|
|
|
535
348
|
|
|
536
349
|
return { pattern, params }
|
|
537
350
|
}
|
|
538
|
-
// //////////////////////////////////////////////////////////////////////////////////////////
|
|
539
|
-
|
|
540
351
|
|
|
541
352
|
/**
|
|
542
353
|
* Given a static props entry (returned by getStaticProps),
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import { join } from 'pathe'
|
|
2
|
-
import { _root } from '@/utils'
|
|
3
|
-
import type { IRoute, Metadata } from './types'
|
|
4
|
-
import { dirname } from 'node:path'
|
|
1
|
+
import { dirname, join } from 'pathe'
|
|
5
2
|
import { NF_NAMES } from './constants'
|
|
3
|
+
import { _root } from '@/utils'
|
|
4
|
+
import type { Metadata } from './types'
|
|
6
5
|
|
|
7
6
|
export const router = new Bun.FileSystemRouter({
|
|
8
7
|
style: 'nextjs',
|
|
9
8
|
dir: join(_root, 'pages'),
|
|
10
|
-
// origin: 'https://
|
|
9
|
+
// origin: 'https://example.com',
|
|
11
10
|
// assetPrefix: 'assets/',
|
|
12
11
|
})
|
|
13
12
|
export const reload = () => router.reload()
|