duto 0.261001.0 → 0.261012.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.
Files changed (32) hide show
  1. package/package.json +22 -26
  2. package/src/commands/templates/pages/components/html.tsx +55 -0
  3. package/src/commands/templates/pages/components/theme-select.tsx +60 -0
  4. package/src/commands/templates/pages/i18n/en.ts +6 -0
  5. package/src/commands/templates/pages/i18n/pt-br.ts +6 -0
  6. package/src/commands/templates/pages/pages/404.tsx +1 -1
  7. package/src/commands/templates/pages/pages/blog/[slug].tsx +88 -0
  8. package/src/commands/templates/pages/pages/blog/index.tsx +74 -0
  9. package/src/commands/templates/pages/pages/index.tsx +17 -7
  10. package/src/commands/templates/pages/pages/layout.tsx +5 -3
  11. package/src/commands/templates/pages/public/favicon.ico +0 -0
  12. package/src/commands/templates/pages/public/favicon.svg +1 -0
  13. package/src/commands/templates/pages/style.css +110 -7
  14. package/src/commands/templates/pages/tsconfig.json +2 -0
  15. package/src/pages/cli/commands/build.ts +1 -2
  16. package/src/pages/cli/utils.ts +8 -6
  17. package/src/pages/client/app.tsx +177 -28
  18. package/src/pages/client/link.ts +15 -41
  19. package/src/pages/client/storage.ts +1 -1
  20. package/src/pages/client/theme.ts +49 -0
  21. package/src/pages/compiler/ast.ts +13 -0
  22. package/src/pages/compiler/bun-plugin.ts +245 -0
  23. package/src/pages/compiler/constants.ts +2 -0
  24. package/src/pages/compiler/index.ts +44 -23
  25. package/src/pages/compiler/meta.ts +7 -31
  26. package/src/pages/compiler/types.ts +15 -25
  27. package/src/pages/components/link.tsx +11 -19
  28. package/src/pages/i18n/client.ts +3 -4
  29. package/src/pages/index.ts +4 -21
  30. package/src/server/app.ts +2 -1
  31. package/src/pages/client/router.ts +0 -63
  32. package/src/pages/compiler/vite-plugin.ts +0 -345
@@ -7,32 +7,32 @@ import { h } from 'preact'
7
7
  import { render } from 'preact-render-to-string'
8
8
  import minify from '@minify-html/node'
9
9
 
10
- import { JSJSON } from 't0n'
11
10
  import { DOCTYPE_RE } from './constants'
12
11
  import { getAsset, getChunk } from './assets'
13
- import { getLayouts, resolveStaticOutputPath } from './meta'
12
+ import { resolveStaticOutputPath } from './meta'
14
13
  import { setLocale } from '../i18n/client'
15
14
 
16
- import type { ResolvedConfig } from 'vite'
17
15
  import type { IRoute, Metadata, RouteParams, StaticProps, SummaryMetadata } from './types'
16
+ import type { DutoOptions } from './bun-plugin'
18
17
 
19
18
 
20
19
  const brCompress = promisify(brotliCompress)
21
20
 
22
21
  export async function renderPage(
23
22
  meta: Metadata,
24
- config: ResolvedConfig,
23
+ config: DutoOptions,
25
24
  page: IRoute
26
25
  ) {
27
26
  const {
28
27
  mod,
28
+ layouts,
29
29
  hasGetProps, hasGetStaticProps,
30
- isClientOnly,
30
+ useClient,
31
31
  } = page
32
32
  if (!mod?.default)
33
33
  return console.warn(`No default export in ${page.filePath} — skipping`)
34
34
 
35
- if (page.isInternal || page.is404 || (page.isDynamic && !hasGetStaticProps))
35
+ if (page.isInternal || (!page.useRaw && !page.useHtml && page.is404) || (page.isDynamic && !hasGetStaticProps))
36
36
  return meta.summary.set('/'+ page.fileName, { type: 2, path: '/'+ page.fileName, size: 0, sizeBr: 0, sizeJS: 0 })
37
37
 
38
38
  const { filePath, pattern, params } = page
@@ -70,44 +70,54 @@ export async function renderPage(
70
70
  props.push({ routeParams: {}, pageProps: {} })
71
71
  }
72
72
 
73
- const layouts = await getLayouts(meta, page.filePath)
74
-
73
+ const sProps = []
75
74
  for (const prop of props) {
76
75
  const allProps = { ...prop.pageProps, ...prop.routeParams }
76
+ Object.keys(allProps).length && sProps.push(allProps)
77
77
 
78
78
  // @ts-ignore
79
- allProps?.locale && setLocale(allProps?.locale || meta.i18n.fallbackLocale)
79
+ allProps?.locale && await setLocale(allProps?.locale || meta.i18n.fallbackLocale)
80
80
 
81
81
  const pathname = resolveStaticOutputPath(page, prop.routeParams)
82
+
83
+ // Shims
82
84
  // TODO: melhorar isso para impedir erros do wouter e afins
83
85
  // @ts-ignore
84
86
  global.location = { pathname: '/'+ (pathname === 'index' ? '' : pathname) }
87
+ global.location.href = global.location.pathname
85
88
  // @ts-ignore
86
- global.window = { $duto: {
87
- sroutes: meta.spages,
88
- navigate: {},
89
- route: { pattern: page.pattern, params: prop.routeParams, path: global.location.pathname },
90
- } }
89
+ global.window = {
90
+ location: global.location,
91
+ $duto: {
92
+ navigate: {},
93
+ route: { pattern: page.pattern, params: prop.routeParams, path: global.location.pathname },
94
+ }
95
+ }
91
96
 
92
97
  let html = ''
93
98
 
94
- // if (!isClientOnly) { // TODO: fazer funcionar com `use client`
99
+ if (!useClient) {
95
100
  try {
96
101
  let el = h(mod.default, allProps as any)
97
102
  for (const layout of layouts)
98
103
  el = h(layout.mod.default, null, el)
99
104
 
105
+ // @ts-ignore
106
+ const shell = mod?.Html || mod?.html || mod?.HTML
107
+ // @ts-ignore
108
+ if (shell) el = h(shell, allProps, el)
109
+
100
110
  html = render(el)
101
111
  } catch (e) {
102
112
  console.error(` SSR render failed for ${filePath}: ${e}`)
103
113
  console.warn(e)
104
114
  html = ''
105
115
  }
106
- // }
116
+ }
107
117
 
108
- html = buildHtml(html, Object.keys(allProps).length ? allProps : undefined)
118
+ html = buildHtml(page, html, Object.keys(allProps).length ? allProps : undefined)
109
119
 
110
- const outFile = join(config.root, config.build.outDir, pathname +'.html')
120
+ const outFile = join(config.root, config.outDir, pathname +'.html')
111
121
  const outHTML = meta.minify ? minify.minify(Buffer.from(html), {}) : html
112
122
  await mkdir(dirname(outFile), {recursive: true})
113
123
  await Bun.write(outFile, outHTML)
@@ -144,16 +154,22 @@ export async function renderPage(
144
154
  sizeJS: 0,
145
155
  })
146
156
  }
147
-
148
157
  }
158
+
159
+ if (sProps.length)
160
+ page.props = sProps.length < 2 ? sProps[0] : sProps
149
161
  }
150
162
 
151
163
  function buildHtml(
164
+ page: IRoute,
152
165
  html: string,
153
- props?: StaticProps,
166
+ props: StaticProps = {},
154
167
  ): string {
168
+ if (page.useRaw) return html
155
169
  if (!(html.includes('<body') || html.includes('<html') || html.includes('<head')))
156
170
  html = wrapHtml(html)
171
+ else
172
+ html = html.replace('<body', '<body hidden')
157
173
 
158
174
  if (!DOCTYPE_RE.test(html))
159
175
  html = '<!DOCTYPE html>'+ html
@@ -164,7 +180,8 @@ function buildHtml(
164
180
 
165
181
  const prepend = assets.map(asset => {
166
182
  const href = getAsset(asset)
167
- return href ? `<link href="${href}" rel=stylesheet>` : null
183
+ // return href ? `<link rel="stylesheet" href="${href}">` : null
184
+ return href ? `<link rel="preload" href="${href}" as="style" onload="this.rel='stylesheet'">` : null
168
185
  }).filter(Boolean).join('')
169
186
 
170
187
  if (html.includes('</head>')) {
@@ -175,9 +192,13 @@ function buildHtml(
175
192
  html = prepend + html
176
193
  }
177
194
 
178
- const append = (props ? `<script>(self.$duto=self.$duto||{}).props=${JSJSON(props)}</script>` : '') + assets.map(file => {
195
+ if (page.useHtml) props.__raw = true
196
+
197
+ // const append = (Object.keys(props).length ? `<script>(self.$duto=self.$duto||{}).props=${JSJSON(props)}</script>` : '') + assets.map(file => {
198
+ const append = assets.map(file => {
179
199
  const src = getChunk(file)
180
- return src ? `<script src="${src}" type=module></script>` : null
200
+ return src ? `<script type=module src="${src}"></script>` : null
201
+ // return src ? `<script type=module src="${src}"${(Object.keys(props).length ? ` props='${JSON.stringify(props)}'` : '')}></script>` : null
181
202
  }).filter(Boolean).join('')
182
203
 
183
204
  if (html.includes('</body>'))
@@ -1,15 +1,9 @@
1
- // https://github.com/cloudflare/vinext/blob/main/packages/vinext/src/routing/utils.ts
2
-
3
- // https://github.com/cloudflare/vinext/blob/adfc2236cba5f7cde63f32f6fb35c0d892428376/packages/vinext/src/build/prerender.ts#L203
4
- // https://github.com/cloudflare/vinext/blob/main/packages/vinext/src/entries/pages-client-entry.ts
5
- // https://github.com/cloudflare/vinext/blob/main/packages/vinext/src/shims/ALS-ARCHITECTURE.md
6
-
7
1
  import { dirname, extname } from 'node:path'
8
2
 
9
3
  import { getEnv, JSJSON, newID } from 't0n'
10
4
 
11
5
  import { getAliases } from './aliases'
12
- import { DYNAMIC_RE, INTERNAL_RE, LAYOUT_RE, NF_NAMES, FILE_EXTENSIONS } from './constants'
6
+ import { DYNAMIC_RE, INTERNAL_RE, LAYOUT_RE, NF_NAMES, FILE_EXTENSIONS, USE_RAW_RE, USE_HTML_RE } from './constants'
13
7
  import { scan } from '@/utils'
14
8
 
15
9
  import { USE_CLIENT_RE } from './constants'
@@ -23,13 +17,10 @@ import type {
23
17
  SummaryMetadata,
24
18
  } from './types'
25
19
 
26
-
27
- // TODO: https://github.com/cloudflare/vinext/blob/adfc2236cba5f7cde63f32f6fb35c0d892428376/packages/vinext/src/routing/file-matcher.ts#L90
28
20
  export async function getPages(meta: Metadata) {
29
21
  const nf = new Map<string, IRoute>()
30
22
  const layouts = new Map<string, IRoute>()
31
23
  const pages = new Map<string, IRoute>()
32
- const spages = new Set<string>()
33
24
  const routes: IRoute[] = []
34
25
 
35
26
  for await (const [file, path, mod] of scan(meta.dir, FILE_EXTENSIONS)) {
@@ -59,7 +50,9 @@ export async function getPages(meta: Metadata) {
59
50
  layouts: [],
60
51
  hasGetStaticProps: typeof mod.getStaticProps === 'function',
61
52
  hasGetProps: typeof mod.getProps === 'function',
62
- isClientOnly: USE_CLIENT_RE.test(content),
53
+ useClient: USE_CLIENT_RE.test(content),
54
+ useRaw: USE_RAW_RE.test(content),
55
+ useHtml: USE_HTML_RE.test(content),
63
56
  }
64
57
 
65
58
  if (LAYOUT_RE.test(path)) {
@@ -77,31 +70,13 @@ export async function getPages(meta: Metadata) {
77
70
  if (!page.isInternal)
78
71
  pages.set(file, page)
79
72
 
80
- if (!page.isInternal)
73
+ if (!page.isInternal && !page.useRaw && !page.useHtml)
81
74
  routes.push(page)
82
-
83
- if (!page.isInternal) {
84
- if (page.isDynamic && page.hasGetStaticProps) {
85
- try {
86
- const _props = await page.mod.getStaticProps?.()
87
- const props = Array.isArray(_props) ? _props : [_props]
88
- for (const prop of props)
89
- spages.add('/'+resolveStaticOutputPath(page, prop as any))
90
-
91
- } catch(e) {
92
- console.log('errro', e)
93
- }
94
- } else if (!page.isDynamic) {
95
- spages.add(page.pattern)
96
- }
97
- }
98
-
99
75
  }
100
76
 
101
77
  meta.nf = nf
102
78
  meta.layouts = layouts
103
79
  meta.pages = pages
104
- meta.spages = spages
105
80
  meta.routes = await sortRoutes(meta, routes)
106
81
  }
107
82
 
@@ -140,7 +115,6 @@ ${Array.from(meta.layouts.values()).map(l => `\nimport Layout${l.importName} fro
140
115
 
141
116
  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(',')}]
142
117
 
143
- export const SRoutes = new Set(${JSJSON([...meta.spages])})
144
118
  `
145
119
 
146
120
  return meta
@@ -153,6 +127,8 @@ export const SRoutes = new Set(${JSJSON([...meta.spages])})
153
127
 
154
128
 
155
129
  // //////////////////////////////////////////////////////////////////////////////////////////
130
+ // https://github.com/cloudflare/vinext/blob/main/packages/vinext/src/routing/utils.ts
131
+
156
132
  type RouteMeta = {
157
133
  staticSegments: number,
158
134
  dynamicSegments: number,
@@ -1,10 +1,8 @@
1
- // import type { ComponentType, FunctionComponent, VNode } from 'preact'
2
- import type { Platform } from '$/cli/types'
3
1
  import type { FunctionComponent, VNode } from 'preact'
2
+ import type { Platform } from '$/cli/types'
4
3
 
5
4
  export type PluginOptions = {
6
5
  root?: string,
7
- // Directory to scan for pages, relative to Vite root. Default: "./pages"
8
6
  pagesDir?: string,
9
7
  }
10
8
 
@@ -43,8 +41,7 @@ export type Metadata = {
43
41
  aliases: Record<string, string>,
44
42
  layouts: Map<string, IRoute>, // all layouts
45
43
  nf: Map<string, IRoute>, // all 404
46
- pages: Map<string, IRoute>, // all
47
- spages: Set<string>, // ssg pages
44
+ pages: Map<string, IRoute>, // all pages
48
45
  routes: Routes, // client-side
49
46
  // routes: Map<string, IRoute>, // client-side
50
47
  i18n: I18nMetadata,
@@ -64,15 +61,17 @@ export type PageModule<P = {}> = {
64
61
  * getStaticProps — build-only.
65
62
  * For static pages (no dynamic segments): returns a single props object.
66
63
  * For dynamic pages: returns an array of { [routeParam]: value, ...props }
67
- *
68
64
  */
69
65
  export type GetStaticProps =
70
66
  | (() => StaticProps | Promise<StaticProps>)
71
67
  | (() => StaticProps[] | Promise<StaticProps[]>)
72
68
  export type StaticProps = Record<string, unknown>
73
69
 
74
- export type GetProps = (params: RouteParams) => StaticProps | Promise<StaticProps>
75
70
  export type RouteParams = Record<string, string | string[] | undefined>
71
+ export type GetProps = (params: RouteParams) => StaticProps | Promise<StaticProps>
72
+ export type Params = Record<string, RouteParams>
73
+
74
+ export type View = [string, Page, Params | 0, GetProps | 0 | 1 | null, Page[]]
76
75
 
77
76
  export type Routes = IRoute[]
78
77
  export type IRoute = {
@@ -80,34 +79,25 @@ export type IRoute = {
80
79
  mod: PageModule,
81
80
  hasGetStaticProps: boolean,
82
81
  hasGetProps: boolean,
83
- isClientOnly: boolean,
82
+ useClient: boolean,
83
+ useRaw: boolean,
84
+ useHtml: boolean,
84
85
  layouts: IRoute[],
85
86
  importName: string,
86
87
 
88
+ props?: StaticProps,
89
+
87
90
  ////////////////////////////
88
91
 
89
92
  fileExt: string,
90
93
  fileName: string,
91
- /** Original file path relative to pages dir, e.g. `blog/[slug].tsx` */
92
- filePath: string,
94
+ filePath: string, // Original file path relative to pages dir, e.g. `blog/[slug].tsx`
93
95
  fullFilePath: string,
94
- /** Wouter-compatible pattern, e.g. `/blog/:slug` */
95
- pattern: string,
96
- /** Params extracted from the path segments */
97
- params: Record<string, RouteParam>,
98
- // params: RouteParam[],
99
- /**
100
- * Similar to the "params" field, but with more associated metadata. For example, for `/site/[blog]/[...slug].tsx`, the segments are:
101
- *
102
- * 1. `{ content: 'site', dynamic: false, spread: false }`
103
- * 2. `{ content: 'blog', dynamic: true, spread: false }`
104
- * 3. `{ content: '...slug', dynamic: true, spread: true }`
105
- */
106
- // segments: RoutePart[][]; // alternativa ao "params"
96
+ pattern: string, // Wouter-compatible pattern, e.g. `/blog/:slug`
97
+ params: Params,
107
98
  is404: boolean,
108
- /** True if this route has any dynamic segments */
99
+
109
100
  isDynamic: boolean,
110
- /** True if this route are internal */
111
101
  isInternal: boolean,
112
102
  }
113
103
 
@@ -1,4 +1,4 @@
1
- import { Link as WouterLink, useLocation } from 'wouter-preact'
1
+ import { useLocation } from 'wouter-preact'
2
2
  import type { LinkProps } from 'wouter-preact'
3
3
 
4
4
  const isExternalUrl = (href?: string) =>
@@ -12,27 +12,19 @@ export const Link = ({
12
12
  href = to,
13
13
  ...rest
14
14
  }: LinkProps) => {
15
- const isExternal = isExternalUrl(rest.href = href)
16
- const isSRoute = window?.$duto?.sroutes?.has(href)
17
-
18
- if (isExternal) {
15
+ if (isExternalUrl(rest.href = href)) {
19
16
  rest.target = '_blank'
20
17
  rest.rel = 'noopener noreferrer'
18
+ } else {
19
+ rest.is = 'i-l'
21
20
  }
22
21
 
23
- if (!href || isExternal || isSRoute) {
24
- const [pathname] = useLocation()
25
- const baseClass = typeof rest.class === 'string' || !rest?.class
26
- ? (rest.class || '') as string
27
- : ''
28
- rest.class = baseClass + (pathname === href ? ' active' : '')
29
-
30
- !href && (delete rest.href)
31
- return <a is='i-l' {...rest} />
32
- }
33
-
34
- if (typeof rest.class === 'string' || !rest?.class)
35
- rest.className = a => (rest.class || '') + (a ? ' active' : '')
22
+ const [pathname] = useLocation()
23
+ const baseClass = typeof rest.class === 'string' || !rest?.class
24
+ ? (rest.class || '') as string
25
+ : ''
26
+ rest.class = baseClass + (pathname === href ? ' active' : '')
36
27
 
37
- return <WouterLink is='i-l' {...rest} />
28
+ !href && (delete rest.href)
29
+ return <a {...rest} />
38
30
  }
@@ -1,6 +1,5 @@
1
1
  import { h, type JSX } from 'preact'
2
2
  import { local } from '#/client/storage'
3
- import { navigate } from '..'
4
3
 
5
4
  const accepted = (lang: string | undefined, locales: string[] = [], fallback: string) => lang && locales.includes(lang) ? lang : fallback
6
5
 
@@ -41,7 +40,7 @@ const getAccepted = (lang: string, locales: string[] = [], defaultLocale = '') =
41
40
  return defaultLocale
42
41
  }
43
42
 
44
- const detect = (locales: string[], defaultLocale: string) => {
43
+ export const detect = (locales: string[], defaultLocale: string) => {
45
44
  if (!defaultLocale) defaultLocale = 'en'
46
45
  if (typeof window === 'undefined') return defaultLocale
47
46
 
@@ -125,7 +124,7 @@ export const cached = () => local.get('lang') as string || ''
125
124
  export const updateWidth = (el: HTMLSelectElement) => {
126
125
  if (el) {
127
126
  const option = el.querySelector(`option[value="${el.value}"]`) as HTMLOptionElement
128
- const length = option.textContent.split(' ')[0]?.length || 0
127
+ const length = option?.textContent.split(' ')[0]?.length || 0
129
128
  el.style.width = (length * 15.7)+ 'px'
130
129
  }
131
130
  }
@@ -153,7 +152,7 @@ export const r = (key: string, lang?: string) => {
153
152
  const path = '/'+ lang + (key ? '/'+ route(key, lang) : '')
154
153
 
155
154
  if (!location.pathname.endsWith(path))
156
- navigate(path)
155
+ self.$duto?.navigate(path)
157
156
 
158
157
  // return '/' + lang + '/' + (key in _routes[lang] ? _routes[lang][key] : key)
159
158
  }
@@ -1,27 +1,10 @@
1
1
  export {
2
- Redirect,
3
- useLocation, useParams, useSearch, useSearchParams,
4
- matchRoute,
5
- } from 'wouter-preact'
6
-
7
- export {
8
- t, r, d,
9
- getLocale, setLocale,
10
- isPrefixed,
2
+ route, r, redirect,
3
+ t, tl, d,
4
+ getLocale, setLocale, isPrefixed,
11
5
  } from './i18n/client'
12
6
 
13
7
  export { local } from './client/storage'
14
8
 
15
- export const navigate = <S = any>(
16
- to: string | URL,
17
- options?: { replace?: boolean; state?: S; transition?: boolean }
18
- ) => {
19
- if (window?.$duto?.sroutes?.has(to)) {
20
- location.pathname = to
21
- return
22
- }
23
-
24
- window?.$duto?.navigate || useLocation()[1](to, options)
25
- }
26
-
9
+ export * from './client/theme'
27
10
  export { Link } from './components/link'
package/src/server/app.ts CHANGED
@@ -10,6 +10,7 @@ import { isDev } from './utils/environment'
10
10
  import { getVerb } from './utils'
11
11
  import { registerMiddleware, resolveHandle, resolveMw } from './handle'
12
12
 
13
+ const NFHandler = () => response.notFound()
13
14
  async function EHandler(e: Error | HTTPResponseError) {
14
15
  console.error(e)
15
16
 
@@ -74,7 +75,7 @@ export default function createApp<E extends Env>(options?: ServerOptions<E>) {
74
75
 
75
76
  // @ts-ignore
76
77
  app.onError(options?.onError || EHandler)
77
- app.notFound(options?.notFound || response.notFound)
78
+ app.notFound(options?.notFound || NFHandler)
78
79
 
79
80
  if (options?.init) options.init(app)
80
81
 
@@ -1,63 +0,0 @@
1
- import { render, h } from 'preact'
2
- import type { Page, GetProps, IRoute } from '#/compiler/types'
3
-
4
- function normalizeParams(
5
- raw: Record<string, string>,
6
- paramDefs: IRoute['params']
7
- ): Record<string, string | string[] | undefined> {
8
- const result: Record<string, string | string[] | undefined> = {};
9
- for (const def of paramDefs) {
10
- const val = raw[def.name];
11
- if (def.catchAll) {
12
- result[def.name] = val
13
- ? val.split('/').filter(Boolean)
14
- : def.optional ? undefined : []
15
- } else {
16
- result[def.name] = val === undefined && def.optional ? undefined : val;
17
- }
18
- }
19
- return result
20
- }
21
-
22
- export async function renderRoute(
23
- container: HTMLElement,
24
- Component: Page,
25
- rawParams: Record<string, string>,
26
- paramDefs?: IRoute['params'] | 0,
27
- getProps?: GetProps | 0 | 1,
28
- layouts?: Page[]
29
- ) {
30
- while (document.body.firstChild)
31
- document.body.removeChild(document.body.firstChild)
32
-
33
- let props: Record<string, unknown> = paramDefs ? normalizeParams(rawParams, paramDefs) : rawParams
34
-
35
- if (typeof Component === 'string') {
36
- const mod = await import(Component)
37
- Component = mod.default
38
- getProps = getProps === 1 ? mod.getProps : 0
39
- }
40
-
41
- // @ts-ignore
42
- const sProps = self.$duto?.props
43
- if (typeof sProps === 'object' && sProps !== null) {
44
- Object.assign(props, sProps)
45
- } else if (typeof getProps === 'function') {
46
- try { // TODO: melhorar tipagem do props
47
- const fetched = await Promise.resolve(getProps(props as Record<string, string | string[] | undefined>))
48
- props = { ...fetched, ...props }
49
- } catch (e) {
50
- console.error('[ssg] getProps failed:', e)
51
- }
52
- }
53
-
54
-
55
- let el = h(Component, props as any)
56
-
57
- const _layouts = layouts ? (Array.isArray(layouts) ? layouts : [layouts]) : []
58
- for (const layout of _layouts)
59
- el = h(layout, null, el)
60
-
61
- render(el, container)
62
- // render(h(Component, props as any), container)
63
- }