Package Exports
- ssr-tools
- ssr-tools/file-router
- ssr-tools/islands
- ssr-tools/islands/preact
- ssr-tools/islands/preact/client
- ssr-tools/islands/preact/ssr
Readme
Note: This library is a work in progress
ssr-tools
Some tools to use in SSR-rendered apps, designed primarily around islands, vite, and a next-style file router.
Using vite:
import preact from '@preact/preset-vite'
import { islands, fileRouter, client } from 'ssr-tools'
defineConfig({
plugins: [
preact(),
islands(),
fileRouter(),
client(),
],
build: {
ssr: true
}
})Plugins
islands()
Import components as islands with a simple import:
import { ComplexComponent } from './button.ts?island'
// basic props are automatically serialised and a client-side bundle is
// added to the manifest, with only the used island components
<ComplexComponent name={'my-component'} />By default this works with Preact only, but the provider interface is simple enough that you can build one yourself for other frameworks (see Preact example). Just pass in your provider in vite.config.ts:
islands({
provider: {
ssr: {
name: 'name-of-export',
importFrom: 'path/that/resolves/to/ssr/wrapper',
importNamed: true || false
},
bundle: ({ imports, variables, code }) => `
// client bundle content goes here
`
}
})client()
Import anything directly into the client bundle:
import './client.ts?client'fileRouter()
A Next-style file router. To start, add the plugin and define a route:
vite.config.ts
defineConfig({
plugins: [
fileRouter({
// default options
dir: 'src/pages',
glob: '**/*.{ts,tsx,js,jsx}',
removeTrailingSlash: true
}),
],
build: {
ssr: true
}
})
src/pages/[slug].tsx
export default function page(ctx) {
return `<html>
<body>
<h1>${ctx.params.slug}</h1>
</body>
</html>`
}Then add the file router middleware to your server:
import http from 'node:http'
import { fileRouterMiddleware } from 'ssr-tools'
const fileRouter = await fileRouterMiddleware()
const app = http.createServer((req, res) => {
fileRouter(req, res, () => res.end())
})
app.listen(port)
Supported filename patterns:
| File name | Route pattern | Matching paths |
|---|---|---|
/index.ts |
/ |
/ |
/about.ts |
/about |
/about |
/books/[slug].ts |
/books/:slug |
/books/foo/books/bar |
/books/[slug]/reviews |
/blog/:slug/reviews |
/blog/foo/reviews |
/api/[...all].ts |
/api/*all |
/api/search/api/docs/foo/api/docs/bar |
ctx
Context is an object passed to each route handler, with the following properties:
| Property | Description | Example/usage |
|---|---|---|
params |
Any route params from request | { slug: 'hello-world' } |
path |
The relative path to the requested page | /blog/hello-world |
query |
URLSearchParams object |
query.get('category') |
Static rendering
To render static pages, Export a build object to your route:
src/pages/[slug].tsx
export default build = {
// return an iterable, and a page will be generated for each entry
from: () => await getPages()
// specify your url params
// (`props` is each entry from the `from` function)
url: props => ({
slug: slugify(props.title)
})
}
// render the content from `ctx.props`
export default function page(ctx) {
return `<html>
<body>
<h1>${ctx.props.title}</h1>
</body>
</html>`
}Still to complete
- Custom handlers for
GET/HEAD/POST/PUT/DELETE/OPTIONS/PATCH - Web-standard
Request/Responsearguments in all middleware and route handlers FormDatahandling- Set props for single pages in
build.props - Route path override for custom routes
- Render statically-generated pages from middleware
- Ability to render routes outside of Vite
- Multi-platform support
- And more…
Contributing
Contributions welcome!
Acknowledgements
islands plugin adapted from vite-plugin-voie, and barelyhuman's preact-island-plugins.