@remix-run/cli 0.2.0 → 0.3.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 (84) hide show
  1. package/dist/lib/bootstrap-project.d.ts.map +1 -1
  2. package/dist/lib/bootstrap-project.js +32 -9
  3. package/dist/lib/cli.d.ts +29 -0
  4. package/dist/lib/cli.d.ts.map +1 -1
  5. package/dist/lib/cli.js +26 -4
  6. package/dist/lib/commands/completion.d.ts.map +1 -1
  7. package/dist/lib/commands/completion.js +5 -1
  8. package/dist/lib/commands/doctor.js +18 -18
  9. package/dist/lib/commands/routes.js +3 -3
  10. package/dist/lib/completion.js +1 -5
  11. package/dist/lib/controller-files.d.ts +0 -1
  12. package/dist/lib/controller-files.d.ts.map +1 -1
  13. package/dist/lib/controller-files.js +3 -5
  14. package/dist/lib/controller-ownership.d.ts +9 -9
  15. package/dist/lib/controller-ownership.d.ts.map +1 -1
  16. package/dist/lib/controller-ownership.js +56 -91
  17. package/dist/lib/doctor/controller-findings.d.ts +1 -1
  18. package/dist/lib/doctor/controller-findings.d.ts.map +1 -1
  19. package/dist/lib/doctor/controller-findings.js +15 -87
  20. package/dist/lib/doctor/controller-fix-plans.d.ts.map +1 -1
  21. package/dist/lib/doctor/controller-fix-plans.js +13 -24
  22. package/dist/lib/doctor/controller-placeholders.d.ts +2 -3
  23. package/dist/lib/doctor/controller-placeholders.d.ts.map +1 -1
  24. package/dist/lib/doctor/controller-placeholders.js +18 -149
  25. package/dist/lib/doctor/controllers.js +1 -1
  26. package/dist/lib/doctor/project.js +60 -52
  27. package/dist/lib/doctor/types.d.ts +2 -2
  28. package/dist/lib/doctor/types.d.ts.map +1 -1
  29. package/dist/lib/load-route-map-worker.js +17 -9
  30. package/dist/lib/route-map.d.ts +1 -1
  31. package/dist/lib/route-map.d.ts.map +1 -1
  32. package/dist/lib/route-map.js +29 -17
  33. package/package.json +3 -3
  34. package/src/lib/bootstrap-project.ts +39 -13
  35. package/src/lib/cli.ts +39 -4
  36. package/src/lib/commands/completion.ts +6 -1
  37. package/src/lib/commands/doctor.ts +18 -21
  38. package/src/lib/commands/routes.ts +3 -3
  39. package/src/lib/completion.ts +1 -5
  40. package/src/lib/controller-files.ts +4 -8
  41. package/src/lib/controller-ownership.ts +78 -141
  42. package/src/lib/doctor/controller-findings.ts +20 -97
  43. package/src/lib/doctor/controller-fix-plans.ts +13 -29
  44. package/src/lib/doctor/controller-placeholders.ts +17 -189
  45. package/src/lib/doctor/controllers.ts +1 -1
  46. package/src/lib/doctor/project.ts +60 -52
  47. package/src/lib/doctor/types.ts +1 -5
  48. package/src/lib/load-route-map-worker.ts +19 -10
  49. package/src/lib/route-map.ts +61 -16
  50. package/{bootstrap → template}/.agents/skills/remix/SKILL.md +160 -73
  51. package/{bootstrap → template}/.agents/skills/remix/references/assets-and-browser-modules.md +22 -14
  52. package/{bootstrap → template}/.agents/skills/remix/references/auth-and-sessions.md +41 -18
  53. package/{bootstrap → template}/.agents/skills/remix/references/data-and-validation.md +21 -5
  54. package/{bootstrap → template}/.agents/skills/remix/references/middleware-and-server.md +43 -53
  55. package/{bootstrap → template}/.agents/skills/remix/references/routing-and-controllers.md +111 -44
  56. package/{bootstrap → template}/.agents/skills/remix/references/testing-patterns.md +17 -1
  57. package/{bootstrap → template}/AGENTS.md +10 -9
  58. package/template/README.md +29 -0
  59. package/template/app/actions/controller.tsx +18 -0
  60. package/template/app/assets/entry.ts +8 -0
  61. package/{bootstrap/app/ui → template/app/assets}/prompt-button.tsx +2 -1
  62. package/{bootstrap → template}/app/assets.ts +5 -3
  63. package/template/app/middleware/render.tsx +43 -0
  64. package/template/app/router.ts +20 -0
  65. package/{bootstrap → template}/app/routes.ts +1 -2
  66. package/{bootstrap → template}/app/ui/document.tsx +11 -4
  67. package/{bootstrap → template}/app/ui/scaffold-home-page.tsx +39 -38
  68. package/template/gitignore +4 -0
  69. package/{bootstrap → template}/package.json +5 -6
  70. package/template/public/favicon.svg +11 -0
  71. package/{bootstrap → template}/server.ts +10 -11
  72. package/{bootstrap → template}/tsconfig.json +3 -2
  73. package/bootstrap/README.md +0 -27
  74. package/bootstrap/app/assets/entry.ts +0 -19
  75. package/bootstrap/app/controllers/auth.tsx +0 -21
  76. package/bootstrap/app/controllers/home.tsx +0 -11
  77. package/bootstrap/app/router.ts +0 -16
  78. package/bootstrap/app/ui/layout.tsx +0 -22
  79. package/bootstrap/app/utils/render.tsx +0 -26
  80. /package/{bootstrap → template}/.agents/skills/remix/references/animate-elements.md +0 -0
  81. /package/{bootstrap → template}/.agents/skills/remix/references/component-model.md +0 -0
  82. /package/{bootstrap → template}/.agents/skills/remix/references/create-mixins.md +0 -0
  83. /package/{bootstrap → template}/.agents/skills/remix/references/hydration-frames-navigation.md +0 -0
  84. /package/{bootstrap → template}/.agents/skills/remix/references/mixins-styling-events.md +0 -0
@@ -1,13 +1,15 @@
1
1
  import { createAssetServer } from 'remix/assets'
2
2
 
3
- export const assets = createAssetServer({
3
+ const rootDir = process.cwd()
4
+
5
+ export const assetServer = createAssetServer({
4
6
  basePath: '/assets',
5
- rootDir: process.cwd(),
7
+ rootDir,
6
8
  fileMap: {
7
9
  'app/*path': 'app/*path',
8
10
  'node_modules/*path': 'node_modules/*path',
9
11
  },
10
- allow: ['app/assets/**', 'app/ui/prompt-button.tsx', 'node_modules/**'],
12
+ allow: ['app/assets/**', 'node_modules/**'],
11
13
  deny: ['app/**/*.server.*'],
12
14
  sourceMaps: process.env.NODE_ENV === 'development' ? 'external' : undefined,
13
15
  scripts: {
@@ -0,0 +1,43 @@
1
+ import * as path from 'node:path'
2
+
3
+ import { renderWith } from 'remix/middleware/render'
4
+ import { createHtmlResponse } from 'remix/response/html'
5
+ import type { RemixNode } from 'remix/ui'
6
+ import { renderToStream } from 'remix/ui/server'
7
+
8
+ import { assetServer } from '../assets.ts'
9
+
10
+ export function render() {
11
+ return renderWith(
12
+ () =>
13
+ function render(node: RemixNode, init?: ResponseInit) {
14
+ let stream = renderToStream(node, {
15
+ // Server rendering turns client entries into browser module URLs.
16
+ async resolveClientEntry(entryId, component) {
17
+ if (!entryId.startsWith('file://')) {
18
+ throw new Error(
19
+ `Expected \`import.meta.url\` for clientEntry ID, received '${entryId}'`,
20
+ )
21
+ }
22
+
23
+ return {
24
+ href: await assetServer.getHref(entryId),
25
+ exportName: entryId.split('#')[1] || component.name || titleCaseFileName(entryId),
26
+ }
27
+ },
28
+ })
29
+
30
+ return createHtmlResponse(stream, init)
31
+ },
32
+ )
33
+ }
34
+
35
+ function titleCaseFileName(fileUrl: string): string {
36
+ let url = new URL(fileUrl)
37
+ let fileName = path.basename(url.pathname, path.extname(url.pathname))
38
+ return fileName
39
+ .split(/[^A-Za-z0-9]+/)
40
+ .filter(Boolean)
41
+ .map((segment) => segment[0]!.toUpperCase() + segment.slice(1))
42
+ .join('')
43
+ }
@@ -0,0 +1,20 @@
1
+ import { createRouter, type MiddlewareContext } from 'remix/router'
2
+ import { staticFiles } from 'remix/middleware/static'
3
+
4
+ import controller from './actions/controller.tsx'
5
+ import { render } from './middleware/render.tsx'
6
+ import { routes } from './routes.ts'
7
+
8
+ type AppContext = MiddlewareContext<[ReturnType<typeof render>]>
9
+
10
+ declare module 'remix/router' {
11
+ interface RouterTypes {
12
+ context: AppContext
13
+ }
14
+ }
15
+
16
+ export const router = createRouter<AppContext>({
17
+ middleware: [staticFiles('./public', { index: false }), render()],
18
+ })
19
+
20
+ router.map(routes, controller)
@@ -1,7 +1,6 @@
1
- import { get, route } from 'remix/fetch-router/routes'
1
+ import { get, route } from 'remix/routes'
2
2
 
3
3
  export const routes = route({
4
4
  assets: get('/assets/*path'),
5
5
  home: '/',
6
- auth: '/auth',
7
6
  })
@@ -1,26 +1,33 @@
1
- import type { RemixNode } from 'remix/ui'
1
+ import { css, type RemixNode } from 'remix/ui'
2
2
 
3
3
  import { routes } from '../routes.ts'
4
4
 
5
5
  export interface DocumentProps {
6
6
  children?: RemixNode
7
+ head?: RemixNode
7
8
  title?: string
8
9
  }
9
10
 
10
- const DEFAULT_TITLE = decodeURIComponent('%%RMX_APP_DISPLAY_NAME_URI_COMPONENT%%')
11
+ const DEFAULT_TITLE = readAppDisplayName('%%RMX_APP_DISPLAY_NAME_URI_COMPONENT%%')
11
12
 
12
13
  export function Document() {
13
- return ({ title = DEFAULT_TITLE, children }: DocumentProps) => (
14
+ return ({ children, head, title = DEFAULT_TITLE }: DocumentProps) => (
14
15
  <html lang="en">
15
16
  <head>
16
17
  <meta charSet="utf-8" />
17
18
  <meta name="viewport" content="width=device-width, initial-scale=1" />
19
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
18
20
  <title>{title}</title>
21
+ {head}
19
22
  </head>
20
- <body>
23
+ <body mix={css({ margin: 0 })}>
21
24
  {children}
22
25
  <script type="module" src={routes.assets.href({ path: 'app/assets/entry.ts' })}></script>
23
26
  </body>
24
27
  </html>
25
28
  )
26
29
  }
30
+
31
+ function readAppDisplayName(value: string): string {
32
+ return value.startsWith('%%') ? 'Remix App' : decodeURIComponent(value)
33
+ }
@@ -1,31 +1,16 @@
1
- // Delete this file and put your own home page in app/controllers/home.tsx
1
+ // Delete this file and put your own home page in app/actions/controller.tsx
2
2
  import { css, type RemixNode } from 'remix/ui'
3
3
 
4
- import { PromptButton } from './prompt-button.tsx'
5
- import { routes } from '../routes.ts'
6
-
7
- const APP_DISPLAY_NAME = decodeURIComponent('%%RMX_APP_DISPLAY_NAME_URI_COMPONENT%%')
4
+ import { PromptButton } from '../assets/prompt-button.tsx'
5
+ import { Document } from './document.tsx'
8
6
 
9
7
  const FONT_STACK =
10
8
  "'JetBrains Mono', ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace"
11
9
 
12
10
  export function HomePage() {
13
11
  return () => (
14
- <html lang="en">
15
- <head>
16
- <meta charSet="utf-8" />
17
- <meta name="viewport" content="width=device-width,initial-scale=1" />
18
- <meta name="color-scheme" content="light dark" />
19
- <title>Welcome to {APP_DISPLAY_NAME}</title>
20
- <link rel="preconnect" href="https://fonts.googleapis.com" />
21
- <link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
22
- <link
23
- rel="stylesheet"
24
- href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&display=swap"
25
- />
26
- <script type="module" src={routes.assets.href({ path: 'app/assets/entry.ts' })}></script>
27
- </head>
28
- <body
12
+ <Document head={<HomeHead />}>
13
+ <main
29
14
  mix={css({
30
15
  // Light-mode design tokens (default).
31
16
  '--surface-0': '#dee2e6',
@@ -58,7 +43,7 @@ export function HomePage() {
58
43
  justifyContent: 'center',
59
44
  })}
60
45
  >
61
- <main
46
+ <div
62
47
  mix={css({
63
48
  width: '100%',
64
49
  maxWidth: '820px',
@@ -71,9 +56,23 @@ export function HomePage() {
71
56
  <Masthead />
72
57
  <Columns />
73
58
  <Footer />
74
- </main>
75
- </body>
76
- </html>
59
+ </div>
60
+ </main>
61
+ </Document>
62
+ )
63
+ }
64
+
65
+ function HomeHead() {
66
+ return () => (
67
+ <>
68
+ <meta name="color-scheme" content="light dark" />
69
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
70
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
71
+ <link
72
+ rel="stylesheet"
73
+ href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&display=swap"
74
+ />
75
+ </>
77
76
  )
78
77
  }
79
78
 
@@ -133,8 +132,8 @@ function Columns() {
133
132
 
134
133
  function GetStartedCard() {
135
134
  return () => (
136
- <div mix={css({ ...CARD_STYLES, flex: '0 0 auto' })}>
137
- <h2 mix={css(CARD_HEADER_STYLES)}>Get started</h2>
135
+ <div mix={[cardStyle, css({ flex: '0 0 auto' })]}>
136
+ <h2 mix={cardHeaderStyle}>Get started</h2>
138
137
  <ul
139
138
  mix={css({
140
139
  listStyle: 'none',
@@ -147,7 +146,7 @@ function GetStartedCard() {
147
146
  })}
148
147
  >
149
148
  <li>
150
- <CardLink href="https://remix.run/docs" icon={<AtomIcon />} label="Remix Docs" />
149
+ <CardLink href="https://api.remix.run" icon={<AtomIcon />} label="Remix API" />
151
150
  </li>
152
151
  <li>
153
152
  <CardLink
@@ -164,14 +163,16 @@ function GetStartedCard() {
164
163
  function CodingWithAiCard() {
165
164
  return () => (
166
165
  <div
167
- mix={css({
168
- ...CARD_STYLES,
169
- width: '540px',
170
- justifyContent: 'center',
171
- '@media (max-width: 720px)': { width: '100%' },
172
- })}
166
+ mix={[
167
+ cardStyle,
168
+ css({
169
+ width: '540px',
170
+ justifyContent: 'center',
171
+ '@media (max-width: 720px)': { width: '100%' },
172
+ }),
173
+ ]}
173
174
  >
174
- <h2 mix={css(CARD_HEADER_STYLES)}>Coding with AI?</h2>
175
+ <h2 mix={cardHeaderStyle}>Coding with AI?</h2>
175
176
  <div
176
177
  mix={css({
177
178
  width: '100%',
@@ -332,7 +333,7 @@ function Footer() {
332
333
  )
333
334
  }
334
335
 
335
- const CARD_STYLES = {
336
+ const cardStyle = css({
336
337
  background: 'var(--surface-3)',
337
338
  borderRadius: '20px',
338
339
  padding: '32px 16px 16px',
@@ -340,9 +341,9 @@ const CARD_STYLES = {
340
341
  flexDirection: 'column',
341
342
  alignItems: 'center',
342
343
  gap: '32px',
343
- } as const
344
+ })
344
345
 
345
- const CARD_HEADER_STYLES = {
346
+ const cardHeaderStyle = css({
346
347
  margin: 0,
347
348
  width: '100%',
348
349
  padding: '0 16px',
@@ -354,7 +355,7 @@ const CARD_HEADER_STYLES = {
354
355
  textTransform: 'uppercase',
355
356
  letterSpacing: '0.1em',
356
357
  color: 'var(--text-primary)',
357
- } as const
358
+ })
358
359
 
359
360
  // ----- SVG icons -----
360
361
  // Inline so the page is fully self-contained with no external icon assets.
@@ -0,0 +1,4 @@
1
+ node_modules/
2
+ db/*.sqlite
3
+ tmp/
4
+ .DS_Store
@@ -1,19 +1,18 @@
1
1
  {
2
- "name": "remix-bootstrap-template",
2
+ "name": "remix-template",
3
3
  "private": true,
4
4
  "type": "module",
5
5
  "scripts": {
6
- "dev": "tsx watch server.ts",
7
- "start": "tsx server.ts",
8
- "test": "tsx --test",
6
+ "dev": "node --watch --import remix/node-tsx server.ts",
7
+ "start": "node --import remix/node-tsx server.ts",
8
+ "test": "node --import remix/node-tsx --test",
9
9
  "typecheck": "tsc --noEmit"
10
10
  },
11
11
  "engines": {
12
12
  "node": ">=24.3.0"
13
13
  },
14
14
  "dependencies": {
15
- "remix": "workspace:^",
16
- "tsx": "catalog:"
15
+ "remix": "workspace:^"
17
16
  },
18
17
  "devDependencies": {
19
18
  "@types/node": "catalog:",
@@ -0,0 +1,11 @@
1
+ <svg width="144" height="144" viewBox="0 0 144 144" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <rect width="144" height="144" rx="72" fill="black"/>
3
+ <g clip-path="url(#clip0_2008_2428)">
4
+ <path d="M102.763 51.2382L102.762 51.2391V51.2401C113.767 51.2402 121.369 56.1787 119.744 62.2714L118.643 66.3973C117.017 72.4901 106.778 77.4286 95.7734 77.4286H94.6475L117.765 92.5868H80.6504L61.9629 78.163C61.2148 77.6833 60.3465 77.4286 59.459 77.4286H28.2197L31.1631 66.3954H85.8799C87.9367 66.3954 89.8519 65.4721 90.1562 64.3329H90.1572C90.4613 63.1935 89.0394 62.2694 86.9814 62.2694H32.2646L35.207 51.2382H102.763ZM54.1865 81.2362C55.2231 81.2363 55.9785 82.2245 55.71 83.2303L53.2139 92.5858H24.1768L27.2041 81.2362H54.1865Z" fill="white"/>
5
+ </g>
6
+ <defs>
7
+ <clipPath id="clip0_2008_2428">
8
+ <rect width="96" height="41.5862" fill="white" transform="translate(24 51.2069)"/>
9
+ </clipPath>
10
+ </defs>
11
+ </svg>
@@ -1,25 +1,24 @@
1
- import { serve } from 'remix/node-serve'
1
+ import * as http from 'node:http'
2
+ import { createRequestListener } from 'remix/node-fetch-server'
2
3
 
3
4
  import { router } from './app/router.ts'
4
5
 
5
6
  const port = process.env.PORT ? Number.parseInt(process.env.PORT, 10) : 44100
6
7
 
7
- const server = serve(
8
- async (request) => {
8
+ const server = http.createServer(
9
+ createRequestListener(async (request) => {
9
10
  try {
10
11
  return await router.fetch(request)
11
12
  } catch (error) {
12
13
  console.error(error)
13
14
  return new Response('Internal Server Error', { status: 500 })
14
15
  }
15
- },
16
- {
17
- port,
18
- },
16
+ }),
19
17
  )
20
18
 
21
- await server.ready
22
- console.log(`Server listening on http://localhost:${server.port}`)
19
+ server.listen(port, () => {
20
+ console.log(`Server listening on http://localhost:${port}`)
21
+ })
23
22
 
24
23
  let shuttingDown = false
25
24
 
@@ -29,8 +28,8 @@ function shutdown() {
29
28
  }
30
29
 
31
30
  shuttingDown = true
32
- server.close()
33
- process.exit(0)
31
+ server.close(() => process.exit(0))
32
+ server.closeAllConnections()
34
33
  }
35
34
 
36
35
  process.on('SIGINT', shutdown)
@@ -3,12 +3,13 @@
3
3
  "strict": true,
4
4
  "lib": ["ES2024", "DOM", "DOM.Iterable"],
5
5
  "types": ["node"],
6
- "module": "ES2022",
7
- "moduleResolution": "Bundler",
6
+ "module": "NodeNext",
7
+ "moduleResolution": "NodeNext",
8
8
  "target": "ESNext",
9
9
  "allowImportingTsExtensions": true,
10
10
  "rewriteRelativeImportExtensions": true,
11
11
  "verbatimModuleSyntax": true,
12
+ "isolatedModules": true,
12
13
  "skipLibCheck": true,
13
14
  "jsx": "react-jsx",
14
15
  "jsxImportSource": "remix/ui",
@@ -1,27 +0,0 @@
1
- # %%RMX_APP_DISPLAY_NAME%%
2
-
3
- A minimal Remix application starter with a home page and an auth page.
4
-
5
- ## Starter Shape
6
-
7
- - `app/controllers/home.tsx` owns the home page.
8
- - `app/controllers/auth.tsx` owns the auth page.
9
- - `app/routes.ts` defines the route contract.
10
- - `app/router.ts` wires routes to handlers.
11
- - `app/ui/` holds the shared document and layout wrappers.
12
- - `app/utils/render.tsx` centralizes HTML response rendering.
13
-
14
- ## Growing The App
15
-
16
- - Start with flat route files and only introduce route folders when a route needs multiple actions or route-owned modules.
17
- - Add directories like `app/data/`, `app/middleware/`, `public/`, or `test/` when the app actually needs them.
18
- - Move shared UI into `app/ui/` once more than one route needs it.
19
-
20
- ## Commands
21
-
22
- ```sh
23
- npm i
24
- npm run start
25
- npm test
26
- npm run typecheck
27
- ```
@@ -1,19 +0,0 @@
1
- import { run } from 'remix/ui'
2
-
3
- run({
4
- async loadModule(moduleUrl, exportName) {
5
- let mod = await import(moduleUrl)
6
- return mod[exportName]
7
- },
8
- async resolveFrame(src, signal, target) {
9
- let headers = new Headers({ accept: 'text/html' })
10
- if (target) headers.set('x-remix-target', target)
11
-
12
- let response = await fetch(src, {
13
- credentials: 'same-origin',
14
- headers,
15
- signal,
16
- })
17
- return response.body ?? response.text()
18
- },
19
- })
@@ -1,21 +0,0 @@
1
- import type { BuildAction } from 'remix/fetch-router'
2
-
3
- import type { routes } from '../routes.ts'
4
- import { Layout } from '../ui/layout.tsx'
5
- import { render } from '../utils/render.tsx'
6
-
7
- export const auth: BuildAction<'GET', typeof routes.auth> = {
8
- handler({ request }) {
9
- return render(<AuthPage />, request)
10
- },
11
- }
12
-
13
- function AuthPage() {
14
- return () => (
15
- <Layout title="Auth">
16
- <h1>Auth</h1>
17
- <p>Use this route to start building sign-in, sign-up, and session flows.</p>
18
- <p>Keep it as a flat file until the route needs multiple actions or route-owned modules.</p>
19
- </Layout>
20
- )
21
- }
@@ -1,11 +0,0 @@
1
- import type { BuildAction } from 'remix/fetch-router'
2
-
3
- import type { routes } from '../routes.ts'
4
- import { HomePage } from '../ui/scaffold-home-page.tsx'
5
- import { render } from '../utils/render.tsx'
6
-
7
- export const home: BuildAction<'GET', typeof routes.home> = {
8
- handler({ request }) {
9
- return render(<HomePage />, request)
10
- },
11
- }
@@ -1,16 +0,0 @@
1
- import { createRouter } from 'remix/fetch-router'
2
-
3
- import { assets } from './assets.ts'
4
- import { auth } from './controllers/auth.tsx'
5
- import { home } from './controllers/home.tsx'
6
- import { routes } from './routes.ts'
7
-
8
- export const router = createRouter()
9
-
10
- router.get(routes.assets, async ({ request }) => {
11
- let response = await assets.fetch(request)
12
- return response ?? new Response('Not Found', { status: 404 })
13
- })
14
-
15
- router.map(routes.home, home)
16
- router.map(routes.auth, auth)
@@ -1,22 +0,0 @@
1
- import type { RemixNode } from 'remix/ui'
2
-
3
- import { routes } from '../routes.ts'
4
- import { Document } from './document.tsx'
5
-
6
- export interface LayoutProps {
7
- children?: RemixNode
8
- title?: string
9
- }
10
-
11
- export function Layout() {
12
- return ({ title, children }: LayoutProps) => (
13
- <Document title={title}>
14
- <header>
15
- <nav>
16
- <a href={routes.home.href()}>Home</a> <a href={routes.auth.href()}>Auth</a>
17
- </nav>
18
- </header>
19
- <main>{children}</main>
20
- </Document>
21
- )
22
- }
@@ -1,26 +0,0 @@
1
- import type { RemixNode } from 'remix/ui'
2
- import { renderToStream } from 'remix/ui/server'
3
-
4
- import { router } from '../router.ts'
5
-
6
- export function render(node: RemixNode, request: Request, init?: ResponseInit) {
7
- let stream = renderToStream(node, {
8
- frameSrc: request.url,
9
- async resolveFrame(src, target) {
10
- let headers = new Headers({ accept: 'text/html' })
11
- let cookie = request.headers.get('cookie')
12
- if (cookie) headers.set('cookie', cookie)
13
- if (target) headers.set('x-remix-target', target)
14
-
15
- let response = await router.fetch(new Request(new URL(src, request.url), { headers }))
16
- return response.body ?? response.text()
17
- },
18
- })
19
-
20
- let headers = new Headers(init?.headers)
21
- if (!headers.has('Content-Type')) {
22
- headers.set('Content-Type', 'text/html; charset=utf-8')
23
- }
24
-
25
- return new Response(stream, { ...init, headers })
26
- }