duto 0.260915.0 → 0.261011.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 (60) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. package/src/commands/new.ts +55 -30
  4. package/src/commands/templates/pages/README.md +21 -0
  5. package/src/commands/templates/pages/_gitignore +24 -0
  6. package/src/commands/templates/pages/components/html.tsx +55 -0
  7. package/src/commands/templates/pages/components/locale-select.tsx +59 -0
  8. package/src/commands/templates/pages/components/select.tsx +95 -0
  9. package/src/commands/templates/pages/components/theme-select.tsx +60 -0
  10. package/src/commands/templates/pages/i18n/en.ts +23 -0
  11. package/src/commands/templates/pages/i18n/index.ts +19 -0
  12. package/src/commands/templates/pages/i18n/pt-br.ts +23 -0
  13. package/src/commands/templates/pages/package.json +22 -0
  14. package/src/commands/templates/pages/pages/404.tsx +12 -0
  15. package/src/commands/templates/pages/pages/blog/[slug].tsx +88 -0
  16. package/src/commands/templates/pages/pages/blog/index.tsx +74 -0
  17. package/src/commands/templates/pages/pages/index.tsx +26 -0
  18. package/src/commands/templates/pages/pages/layout.tsx +26 -0
  19. package/src/commands/templates/pages/public/favicon.ico +0 -0
  20. package/src/commands/templates/pages/public/favicon.svg +1 -0
  21. package/src/commands/templates/pages/style.css +127 -0
  22. package/src/commands/templates/pages/tsconfig.json +56 -0
  23. package/src/commands/templates/pages/types.ts +8 -0
  24. package/src/commands/templates/server/base/.editorconfig +21 -0
  25. package/src/commands/templates/{base → server/base}/README.md +1 -1
  26. package/src/pages/cli/commands/dev.ts +10 -4
  27. package/src/pages/cli/utils.ts +7 -23
  28. package/src/pages/client/app.tsx +193 -91
  29. package/src/pages/client/link.ts +15 -41
  30. package/src/pages/client/storage.ts +1 -1
  31. package/src/pages/client/theme.ts +49 -0
  32. package/src/pages/compiler/aliases.ts +2 -8
  33. package/src/pages/compiler/ast.ts +1 -538
  34. package/src/pages/compiler/constants.ts +97 -13
  35. package/src/pages/compiler/index.ts +55 -140
  36. package/src/pages/compiler/meta.ts +40 -253
  37. package/src/pages/compiler/routes.ts +4 -5
  38. package/src/pages/compiler/types.ts +16 -125
  39. package/src/pages/compiler/vite-plugin.ts +64 -27
  40. package/src/pages/components/link.tsx +11 -19
  41. package/src/pages/i18n/client.ts +21 -10
  42. package/src/pages/i18n/server.ts +21 -6
  43. package/src/pages/index.ts +4 -22
  44. package/src/server/app.ts +2 -1
  45. package/src/server/routes.ts +4 -26
  46. package/src/utils.ts +34 -3
  47. package/src/pages/client/router.ts +0 -329
  48. package/src/pages/compiler/island.ts +0 -108
  49. /package/src/commands/templates/{base → pages}/.editorconfig +0 -0
  50. /package/src/commands/templates/{base → server/base}/.env.dev.example +0 -0
  51. /package/src/commands/templates/{base → server/base}/.env.prod.example +0 -0
  52. /package/src/commands/templates/{base → server/base}/_gitignore +0 -0
  53. /package/src/commands/templates/{base → server/base}/actions/blog/index.get.ts +0 -0
  54. /package/src/commands/templates/{base → server/base}/actions/blog/post/[id].get.ts +0 -0
  55. /package/src/commands/templates/{base → server/base}/actions/index.get.ts +0 -0
  56. /package/src/commands/templates/{base → server/base}/configs/duto.ts +0 -0
  57. /package/src/commands/templates/{base → server/base}/configs/roles.ts +0 -0
  58. /package/src/commands/templates/{base → server/base}/package.json +0 -0
  59. /package/src/commands/templates/{base → server/base}/tsconfig.json +0 -0
  60. /package/src/commands/templates/{workerd → server/workerd}/wrangler.toml +0 -0
@@ -0,0 +1,74 @@
1
+ // 'use client'
2
+ import { t, Link } from 'duto'
3
+ import type { Posts } from '@/types'
4
+ // import { Counter } from '@/components/counter2'
5
+
6
+ type Props = {
7
+ posts?: Posts,
8
+ }
9
+
10
+ export { Html } from '@/components/html'
11
+
12
+ export async function getStaticProps() {
13
+ const posts = (await (await fetch('https://jsonplaceholder.typicode.com/posts')).json())
14
+ ?.sort(() => 0.5 - Math.random())
15
+ .slice(0, 10)
16
+
17
+ return { posts }
18
+ }
19
+
20
+ export default function Blog({ posts }: Props) {
21
+ return (
22
+ <>
23
+ <h1 class="title">Blog</h1>
24
+
25
+ <div class="highlight">
26
+ {t`b1`}&nbsp;<b><i>getStaticProps()</i></b> (SSG)
27
+ </div>
28
+
29
+ {!posts?.length && (
30
+ <p class="mt-8">No posts found.</p>
31
+ )}
32
+
33
+ <div class="mt-8 flex flex-col">
34
+ {posts?.map((post) => (
35
+ <Link to={`/blog/${post.id}`} key={post.id}
36
+ class="group block relative p-4 border-b border-gray-200 dark:border-zinc-700/70 transition-all duration-300 ease-out"
37
+ >
38
+ <div class="flex items-start gap-4">
39
+ <span class="text-sm font-mono text-gray-400 group-hover:text-sky-gradient mt-0.5 min-w-[24px]">
40
+ #{post.id}
41
+ </span>
42
+
43
+ <div class="flex-1 min-w-0">
44
+ <h2 class="text-base font-medium group-hover:text-sky-gradient">
45
+ {post.title}
46
+ </h2>
47
+ <p class="mt-1 text-sm text-gray-500 group-hover:text-gray-800 dark:group-hover:text-gray-400 line-clamp-2 pr-6">
48
+ {post.body}
49
+ </p>
50
+ </div>
51
+
52
+ <div class="absolute right-0 top-[35%] flex-shrink-0 bg-indigo-50 group-hover:bg-gray-100 dark:bg-gray-600/90 dark:group-hover:bg-gray-500 rounded-full p-1 transition-all duration-300 group-hover:translate-x-1">
53
+ <svg
54
+ class="size-5 text-gray-400 group-hover:text-sky-500 dark:group-hover:text-gray-300"
55
+ fill="none"
56
+ stroke="currentColor"
57
+ viewBox="0 0 24 24"
58
+ >
59
+ <path
60
+ strokeLinecap="round"
61
+ strokeLinejoin="round"
62
+ strokeWidth={2}
63
+ d="M9 5l7 7-7 7"
64
+ />
65
+ </svg>
66
+ </div>
67
+ </div>
68
+
69
+ </Link>
70
+ ))}
71
+ </div>
72
+ </>
73
+ )
74
+ }
@@ -0,0 +1,26 @@
1
+ import { t, Link } from 'duto'
2
+
3
+ export { Html } from '@/components/html'
4
+
5
+ export default function Index() {
6
+ return (
7
+ <div class="relative space-y-8">
8
+ <h1 class="title text-sky-gradient lg:mt-2">{t`title`}</h1>
9
+ <p class="sub-title">{t`description`}</p>
10
+ <div class="divide-y divide-gray-300 dark:divide-zinc-700/70">
11
+ {[
12
+ ['https://hub.bi/docs/duto', t`gotodocs`],
13
+ ['/blog', t`Blog`],
14
+ ].map(([href, label]) => (
15
+ <Link
16
+ href={href}
17
+ class="group flex items-center justify-between gap-4 py-4 px-2.5"
18
+ >
19
+ <span class="font-semibold group-hover:text-sky-gradient">{label}</span>
20
+ <span class="text-lg mr-3 transition-transform group-hover:text-sky-600 dark:group-hover:text-sky-300 group-hover:translate-x-1">→</span>
21
+ </Link>
22
+ ))}
23
+ </div>
24
+ </div>
25
+ )
26
+ }
@@ -0,0 +1,26 @@
1
+ import type { ComponentChildren } from 'preact'
2
+
3
+ import LocaleSelect from '@/components/locale-select'
4
+ import ThemeSelect from '@/components/theme-select'
5
+
6
+ export default function Layout({ children }: { children: ComponentChildren }) {
7
+ return (
8
+ <>
9
+ <div class='absolute top-10 right-10'>
10
+ <ThemeSelect class='mr-5' />
11
+ <LocaleSelect />
12
+ </div>
13
+
14
+ <main class="flex flex-col justify-center items-center px-6 py-16 min-h-[calc(100vh-3.75rem)]" children={children} />
15
+
16
+ <footer class="py-[1.1rem] relative text-base lex flex-row items-center mx-auto">
17
+ <a href="https://hub.bi?ref=duto" class="no-underline group flex items-center justify-center" target="_blank" rel="noopener noreferrer">
18
+ Powered by
19
+ <span class="group-hover:underline flex items-center">
20
+ <svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 20 20" aria-hidden="true" class="mx-1 text-xl" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M16.555 5.412a8.028 8.028 0 0 0-3.503-2.81 14.899 14.899 0 0 1 1.663 4.472 8.547 8.547 0 0 0 1.84-1.662ZM13.326 7.825a13.43 13.43 0 0 0-2.413-5.773 8.087 8.087 0 0 0-1.826 0 13.43 13.43 0 0 0-2.413 5.773A8.473 8.473 0 0 0 10 8.5c1.18 0 2.304-.24 3.326-.675ZM6.514 9.376A9.98 9.98 0 0 0 10 10c1.226 0 2.4-.22 3.486-.624a13.54 13.54 0 0 1-.351 3.759A13.54 13.54 0 0 1 10 13.5c-1.079 0-2.128-.127-3.134-.366a13.538 13.538 0 0 1-.352-3.758ZM5.285 7.074a14.9 14.9 0 0 1 1.663-4.471 8.028 8.028 0 0 0-3.503 2.81c.529.638 1.149 1.199 1.84 1.66ZM17.334 6.798a7.973 7.973 0 0 1 .614 4.115 13.47 13.47 0 0 1-3.178 1.72 15.093 15.093 0 0 0 .174-3.939 10.043 10.043 0 0 0 2.39-1.896ZM2.666 6.798a10.042 10.042 0 0 0 2.39 1.896 15.196 15.196 0 0 0 .174 3.94 13.472 13.472 0 0 1-3.178-1.72 7.973 7.973 0 0 1 .615-4.115ZM10 15c.898 0 1.778-.079 2.633-.23a13.473 13.473 0 0 1-1.72 3.178 8.099 8.099 0 0 1-1.826 0 13.47 13.47 0 0 1-1.72-3.178c.855.151 1.735.23 2.633.23ZM14.357 14.357a14.912 14.912 0 0 1-1.305 3.04 8.027 8.027 0 0 0 4.345-4.345c-.953.542-1.971.981-3.04 1.305ZM6.948 17.397a8.027 8.027 0 0 1-4.345-4.345c.953.542 1.971.981 3.04 1.305a14.912 14.912 0 0 0 1.305 3.04Z"></path></svg>
21
+ HUB</span>
22
+ </a>
23
+ </footer>
24
+ </>
25
+ )
26
+ }
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="840" height="840" viewBox="0 0 840 840" fill="none"><style>path{color:black}@media (prefers-color-scheme: dark){path{color:#c6c6c6}}</style><path fill-rule="evenodd" clip-rule="evenodd" d="M832.965 446.25C837.573 438.269 839.999 429.216 839.999 420C839.999 410.784 837.573 401.731 832.965 393.75L645.173 78.75C640.565 70.7692 633.938 64.1418 625.957 59.534C617.976 54.9262 608.923 52.5002 599.708 52.5H240.293C231.077 52.5002 222.024 54.9262 214.043 59.534C206.063 64.1418 199.435 70.7692 194.828 78.75L7.03518 393.75C2.42735 401.731 0.001544 410.784 0.001544 420C0.001544 429.216 2.42735 438.269 7.03518 446.25L194.828 761.25C199.435 769.231 206.063 775.858 214.043 780.466C222.024 785.074 231.077 787.5 240.293 787.5H599.708C608.923 787.5 617.976 785.074 625.957 780.466C633.938 775.858 640.565 769.231 645.173 761.25L832.965 446.25Z" fill="currentColor"></path></svg>
@@ -0,0 +1,127 @@
1
+ @import "tailwindcss";
2
+
3
+ @custom-variant dark (&:where(.dark, .dark *));
4
+
5
+ @layer base {
6
+ * {@apply border-border}
7
+ /* body {@apply bg-background text-foreground} */
8
+ }
9
+
10
+ @utility s {
11
+ @apply w-[--value] h-[--value];
12
+ }
13
+
14
+ @variant children (& > *);
15
+
16
+
17
+ @theme {
18
+ --font-sans:
19
+ -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial,
20
+ "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", "Twemoji Mozilla",
21
+ sans-serif;
22
+ --font-mono:
23
+ ui-monospace, "SFMono-Regular", "SF Mono", Menlo, Consolas,
24
+ "Liberation Mono", monospace;
25
+ --font-serif:
26
+ Georgia, Garamond, Cambria, "Times New Roman", Times, ui-serif, serif;
27
+
28
+ --font-pixel: PixAntiqua, ui-sans-serif, system-ui, sans-serif;
29
+ /* Medium headers*/
30
+ /* sohne, "Helvetica Neue", Helvetica, Arial, sans-serif; */
31
+
32
+ --color-black: #0D0F14;
33
+ --color-white: #fff;
34
+ --color-text: #F041FF;
35
+
36
+ --color-accent: var(--color-gray-100);
37
+ /* --color-primary: #3F224D; */
38
+ --color-muted: #545864;
39
+
40
+ --color-border: var(--color-gray-200);
41
+ --color-grid: #e5e5e5;
42
+
43
+ --color-blue: #3245FF;
44
+ --color-purple: #BC52EE;
45
+ --color-purple-dark: #3F224D;
46
+ --color-red: #D83333;
47
+ --color-pink: #F041FF;
48
+ --color-pink-light: #E8C4F9;
49
+ --color-orange: #F8E42E;
50
+ --color-yellow: #FF7D54;
51
+ --color-hover: #E8C4F9;
52
+ --color-green: #4AF2C8;
53
+
54
+ --color-dark-100: #858B98;
55
+ --color-dark-300: #343841;
56
+ --color-dark-400: #18191E;
57
+ --color-dark-500: #4B4B4B;
58
+ --color-dark-600: #2C2C2C;
59
+ --color-dark-700: #11172A;
60
+ --color-dark-800: #0C0F19;
61
+ --color-dark-900: #060913;
62
+
63
+
64
+ --sky-grad-1: rgb(2, 132, 199);
65
+ --sky-grad-2: rgb(14, 165, 233);
66
+ --sky-grad-3: rgb(56, 189, 248);
67
+ }
68
+
69
+ .dark {
70
+ --color-white: #F2F6FA;
71
+
72
+ --color-accent: #17191E;
73
+ --color-primary: #BC52EE;
74
+ --color-muted: #BFC1C9;
75
+
76
+ --color-border: color-mix(in oklab, var(--color-gray-100) 10%, transparent);
77
+
78
+
79
+ --sky-grad-1: rgb(112, 209, 255);
80
+ --sky-grad-2: rgb(173, 228, 255);
81
+ --sky-grad-3: rgb(219, 243, 255);
82
+ }
83
+
84
+ /* App styles */
85
+
86
+ html, body {
87
+ @apply overscroll-y-none;
88
+ /* font-size-adjust: ex-height 0.5; */
89
+
90
+ /* Standardize line height across different system fonts */
91
+ /* line-height: 1.5; */
92
+ /* Consider setting letter-spacing for more consistent text blocks */
93
+ /* letter-spacing: 0.01em; */
94
+
95
+ /* Advanced font metric overrides (modern browsers only) */
96
+ /* ascent-override: 90%;
97
+ descent-override: 25%;
98
+ line-gap-override: 0%; */
99
+ }
100
+
101
+ .text-sky-gradient,
102
+ .group-hover\:text-sky-gradient:is(:where(.group):hover *),
103
+ .hover\:text-sky-gradient:hover {
104
+ @apply bg-clip-text text-transparent;
105
+ background-image: radial-gradient(
106
+ 138.06% 1036.51% at 95.25% -2.54%,
107
+ var(--sky-grad-1) 14.06%,
108
+ var(--sky-grad-2) 51.02%,
109
+ var(--sky-grad-3) 79.09%
110
+ );
111
+ }
112
+
113
+ /* .text-sky-gradient,
114
+ .group-hover\:text-sky-gradient:is(:where(.group):hover *),
115
+ .hover\:text-sky-gradient:hover
116
+ {
117
+ @apply bg-clip-text text-transparent;
118
+ background-image: radial-gradient(138.06% 1036.51% at 95.25% -2.54%, rgb(112, 209, 255) 14.06%, rgb(173, 228, 255) 51.02%, rgb(219, 243, 255) 79.09%);
119
+ } */
120
+
121
+ .title {
122
+ @apply text-4xl lg:text-[3.5rem] leading-[1.1] font-semibold tracking-tight text-balance
123
+ }
124
+
125
+ .sub-title {
126
+ @apply mt-4 max-w-[60ch] text-lg text-balance md:mt-6 md:text-xl
127
+ }
@@ -0,0 +1,56 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "lib": ["ES2023", "DOM", "DOM.Iterable"],
6
+ "types": ["vite/client", "bun-types", "node"],
7
+
8
+ /* Bundler mode */
9
+ "moduleResolution": "bundler",
10
+ "allowImportingTsExtensions": true,
11
+ "verbatimModuleSyntax": true,
12
+ "moduleDetection": "force",
13
+ "noEmit": true,
14
+ "jsx": "react-jsx",
15
+ "jsxImportSource": "preact",
16
+ "useDefineForClassFields": true,
17
+
18
+ /* Linting */
19
+ "strict": true,
20
+ "skipLibCheck": true,
21
+ "noUnusedLocals": true,
22
+ "noUnusedParameters": true,
23
+ "erasableSyntaxOnly": true,
24
+ "noFallthroughCasesInSwitch": true,
25
+ "noUncheckedSideEffectImports": true,
26
+
27
+ "paths": {
28
+ "react": ["./node_modules/preact/compat/"],
29
+ "react-dom": ["./node_modules/preact/compat/"],
30
+ // "@duto/*": ["./@duto/*"],
31
+ // "duto/*": ["./node_modules/duto/*"],
32
+ // "~icons/*": ["./@iconify-json/*"],
33
+ "@/*": ["./*"]
34
+ }
35
+ },
36
+ "include": [
37
+ "components",
38
+ "configs",
39
+ "enums",
40
+ "libs",
41
+ "i18n",
42
+ "layouts",
43
+ "pages",
44
+ "public",
45
+ "tests/**/*",
46
+ "utils",
47
+ "i18n.ts",
48
+ "i18n.tsx",
49
+ "config.ts",
50
+ "types.ts"
51
+ ],
52
+ "exclude": [
53
+ ".duto",
54
+ "node_modules"
55
+ ]
56
+ }
@@ -0,0 +1,8 @@
1
+
2
+ export type Posts = Post[]
3
+ export type Post = {
4
+ id: number | string,
5
+ userid?: string,
6
+ title: string,
7
+ body: string,
8
+ }
@@ -0,0 +1,21 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ end_of_line = lf
6
+ insert_final_newline = true
7
+ trim_trailing_whitespace = true
8
+ indent_style = space
9
+ indent_size = 2
10
+
11
+ # [*.{js,jsx,ts,tsx,json,yaml,yml}]
12
+ # Inherits all settings from [*] and applies to these extensions
13
+
14
+ [*.{json,jsonc}]
15
+ insert_final_newline = false
16
+
17
+ [*.md]
18
+ trim_trailing_whitespace = false
19
+
20
+ [Dockerfile]
21
+ indent_size = 4
@@ -1,4 +1,4 @@
1
- # Duto - Starter Template
1
+ # Duto Server - Starter Template
2
2
 
3
3
  This template should help get you started developing.
4
4
 
@@ -26,20 +26,26 @@ export default command({
26
26
  name: 'dev',
27
27
  description: '🧪 Start dev server\n',
28
28
  }, // @ts-ignore
29
- args,
29
+ args: {
30
+ ...args,
31
+ minify: {
32
+ description: 'Minify the result',
33
+ type: 'boolean',
34
+ default: true,
35
+ },
36
+ },
30
37
  async run({ args }) {
31
38
  const config = await getConfig()
32
39
  const duto = getEnv('duto', {})
33
40
  const desiredPort = Number(args.port || duto?.dev?.port || 3000)
34
41
  const host = String(args.host || duto?.dev?.host || 'localhost')
35
- // const desiredPort = args.port ? Number(args.port) : (config?.preview?.port ? Number(config.preview.port) : 3000)
36
- // const host = args.host ? String(args.host) : (config?.preview?.host ? String(config.preview.host) : 'localhost')
37
42
 
43
+ const minify = args.minify ?? true
38
44
  let buildProcess: Bun.Subprocess | null = null
39
45
 
40
46
  const _build = async () => {
41
47
  if (buildProcess) await killProcess(buildProcess)
42
- buildProcess = Bun.spawn(['duto', 'build', '--hmr'], {stdin: 'inherit', stdout: 'ignore', stderr: 'inherit'})
48
+ buildProcess = Bun.spawn(['duto', 'build', '--hmr', minify ? '' : '--no-minify'], {stdin: 'inherit', stdout: 'ignore', stderr: 'inherit'})
43
49
 
44
50
  try {
45
51
  const code = await buildProcess.exited
@@ -8,6 +8,7 @@ import config from '#/compiler/vite-plugin'
8
8
  import { _root } from '@/utils'
9
9
  import { match, match404 } from '#/compiler/routes'
10
10
  import type { Metadata, PluginOptions } from '#/compiler/types'
11
+ import { EXTENSIONS_LIST, NF_NAMES } from '#/compiler/constants'
11
12
 
12
13
  export async function getConfig(name = 'config'): Promise<UserConfig & PluginOptions> {
13
14
  let opts = {} as UserConfig
@@ -16,18 +17,6 @@ export async function getConfig(name = 'config'): Promise<UserConfig & PluginOpt
16
17
  return config(opts)
17
18
  }
18
19
 
19
- // export const formatTime = (ms: number) => {
20
- // if (ms < 1000) return `${ms}ms`
21
- // return `${(ms / 1000).toFixed(2)}s`
22
- // }
23
- export const formatTime = (ms: number) => {
24
- if (ms < 0.001) return `${(ms * 1_000_000).toFixed(2)}ns`
25
- if (ms < 1) return `${(ms * 1000).toFixed(2)}µs`
26
- if (ms < 1000) return `${ms.toFixed(2)}ms`
27
- if (ms < 60000) return `${(ms / 1000).toFixed(2)}s`
28
- return `${Math.floor(ms / 60000)}m ${((ms % 60000) / 1000).toFixed(1)}s`
29
- }
30
-
31
20
  const statusColorMap = new Map([
32
21
  [5, red],
33
22
  [4, yellow],
@@ -93,29 +82,23 @@ export function preview(
93
82
  let file = Bun.file(join(_root, dist, path))
94
83
 
95
84
  if (await file.exists()) {
96
- // route = path
97
85
  res = new Response(file)
98
86
  } else {
99
87
  matched = match(path)
100
-
101
- // console.log(matched)
102
- route = matched?.name || match404(meta, path)
103
-
88
+ const r404 = match404(meta, path) || '404'
89
+ route = matched?.name || r404
104
90
  res = new Response(null, { status: 404 })
105
91
 
106
- // for (const asset of path !== '/' && matched && matched.kind === 'exact' ? [
107
- // path,
108
- // join(path, 'index'),
109
- // ] : ['index']) {
110
92
  for (const asset of [
111
93
  path,
112
94
  join(path, 'index'),
95
+ r404,
113
96
  'index',
114
97
  ]) {
115
98
  file = Bun.file(join(_root, dist, asset +'.html'))
116
99
 
117
100
  if (await file.exists()) {
118
- // if (route === '/' || !route) route = asset
101
+ NF_NAMES.includes(asset.split('/').pop()!) && (route = r404)
119
102
  res = new Response(file)
120
103
  break
121
104
  }
@@ -128,7 +111,8 @@ export function preview(
128
111
  status = 500
129
112
  throw err
130
113
  } finally {
131
- if (route || matched) {
114
+ if (EXTENSIONS_LIST.has(path.split('.').pop()!.toLowerCase())) {
115
+ } else if (route || matched) {
132
116
  const elapsed = `${Math.max(1, Math.ceil(performance.now() - start))}ms`
133
117
 
134
118
  console.log([