Skip to content

Commit

Permalink
feat: add Link component for external (built) css (#181)
Browse files Browse the repository at this point in the history
* feat: add `Link` component for external (built) css

* fix: prod as optional
  • Loading branch information
mika-f authored Jun 4, 2024
1 parent 3b34165 commit d41cef5
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 0 deletions.
23 changes: 23 additions & 0 deletions mocks/app-link/routes/_renderer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { jsxRenderer } from 'hono/jsx-renderer'
import { Link } from '../../../src/server'

export default jsxRenderer(
({ children }) => {
return (
<html>
<head>
<Link
href='/app/globals.css'
rel='stylesheet'
prod={true}
manifest={{ 'app/globals.css': { file: 'static/globals-abc.css' } }}
/>
</head>
<body>{children}</body>
</html>
)
},
{
docType: false,
}
)
13 changes: 13 additions & 0 deletions mocks/app-link/routes/classic/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Hono } from 'hono'

const app = new Hono()

app.get('/', (c) => {
return c.render(
<main>
<div />
</main>
)
})

export default app
7 changes: 7 additions & 0 deletions mocks/app-link/routes/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function Hello() {
return (
<main>
<div />
</main>
)
}
Empty file added mocks/app/globals.css
Empty file.
1 change: 1 addition & 0 deletions src/server/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { HasIslands } from './has-islands.js'
export { Script } from './script.js'
export { Link } from './link.js'
38 changes: 38 additions & 0 deletions src/server/components/link.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import type { FC } from 'hono/jsx'
import type { Manifest } from 'vite'

type Options = { manifest?: Manifest; prod?: boolean } & JSX.IntrinsicElements['link']

export const Link: FC<Options> = async (options) => {
let { href, prod, manifest, ...rest } = options
if (href) {
if (prod ?? import.meta.env.PROD) {
if (!manifest) {
const MANIFEST = import.meta.glob<{ default: Manifest }>('/dist/.vite/manifest.json', {
eager: true,
})
for (const [, manifestFile] of Object.entries(MANIFEST)) {
if (manifestFile['default']) {
manifest = manifestFile['default']
break
}
}
}
if (manifest) {
const assetInManifest = manifest[href.replace(/^\//, '')]
if (assetInManifest) {
if (href.startsWith('/')) {
return <link href={`/${assetInManifest.file}`} {...rest}></link>
}

return <link href={assetInManifest.file} {...rest}></link>
}
}
return <></>
} else {
return <link href={href} {...rest}></link>
}
}

return <link {...rest} />
}
26 changes: 26 additions & 0 deletions test-integration/apps.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,32 @@ describe('<Script /> component', () => {
})
})

describe('<Link /> component', () => {
const ROUTES = import.meta.glob('../mocks/app-link/routes/**/index.tsx', {
eager: true,
})

describe('default (rel=stylesheet, absolute path)', () => {
const RENDERER = import.meta.glob('../mocks/app-link/routes/**/_renderer.tsx', {
eager: true,
})

const app = createApp({
root: '../mocks/app-link/routes',
ROUTES: ROUTES as any,
RENDERER: RENDERER as any,
})

it('Should convert the link path correctly', async () => {
const res = await app.request('/')
expect(res.status).toBe(200)
expect(await res.text()).toBe(
'<html><head><link href="/static/globals-abc.css" rel="stylesheet"></link></head><body><main><div></div></main></body></html>'
)
})
})
})

describe('<HasIslands /> Component with path aliases', () => {
const ROUES = import.meta.glob('../mocks/app-alias/routes/**/[a-z[-][a-z-_[]*.(tsx|ts)', {
eager: true,
Expand Down

0 comments on commit d41cef5

Please sign in to comment.