106 lines
2.6 KiB
Markdown
106 lines
2.6 KiB
Markdown
|
|
||
|
up:: [[TypeScript]]
|
||
|
X:: [[JavaScript]]
|
||
|
tags::
|
||
|
|
||
|
# Create SSR Vite Preact App
|
||
|
|
||
|
## Initialization
|
||
|
To create the scaffolding of a preact vite ssr app you run the command:
|
||
|
```
|
||
|
npm create vite@latest
|
||
|
```
|
||
|
Which will start the CLI process.
|
||
|
|
||
|
You will be asked to choose a boilerplate startup, you should go to "other".
|
||
|
This will prompt you to install an "extras" package; select yes.
|
||
|
Choose the srr project for `Preact`
|
||
|
|
||
|
## Server file
|
||
|
In the server file we have some setup to do
|
||
|
|
||
|
### Constants
|
||
|
```TypeScript
|
||
|
const isProduction = process.env.NODE_ENV === 'production'
|
||
|
const port = process.env.PORT || 5173
|
||
|
const base = process.env.BASE || '/'
|
||
|
```
|
||
|
|
||
|
### Cached production assets
|
||
|
```typescript
|
||
|
const templateHtml = isProduction ? await fs.readFile('./dist/client/index.html', 'utf-8') : ''
|
||
|
const ssrManifest = isProduction ? await fs.readFile('./dist/client/ssr-manifest.json', 'utf-8') : undefined
|
||
|
|
||
|
```
|
||
|
|
||
|
### Create HTTP Server
|
||
|
```typescript
|
||
|
const app = express()
|
||
|
```
|
||
|
|
||
|
### Add vite or respective production middlewares
|
||
|
```typescript
|
||
|
let vite
|
||
|
if (!isProduction) {
|
||
|
const { createServer } = await import('vite')
|
||
|
vite = await createServer({
|
||
|
server: { middlewareMode: true },
|
||
|
appType: 'custom',
|
||
|
base
|
||
|
})
|
||
|
app.use(vite.middlewares)
|
||
|
} else {
|
||
|
const compression = (await import('compression')).default
|
||
|
const sirv = (await import('sirv')).default
|
||
|
app.use(compression())
|
||
|
app.use(base, sirv('./dist/client', { extensions: [] }))
|
||
|
}
|
||
|
```
|
||
|
|
||
|
### Serve HTML
|
||
|
```typescript
|
||
|
app.use('*', async (req, res) => {
|
||
|
try {
|
||
|
const url = req.originalUrl.replace(base, '')
|
||
|
|
||
|
let template
|
||
|
let render
|
||
|
if (!isProduction) {
|
||
|
// Always read fresh template in development
|
||
|
template = await fs.readFile('./index.html', 'utf-8')
|
||
|
template = await vite.transformIndexHtml(url, template)
|
||
|
render = (await vite.ssrLoadModule('/src/entry-server.tsx')).render
|
||
|
} else {
|
||
|
template = templateHtml
|
||
|
render = (await import('./dist/server/entry-server.js')).render
|
||
|
}
|
||
|
|
||
|
const rendered = await render(url, ssrManifest)
|
||
|
|
||
|
const html = template
|
||
|
.replace(`<!--app-head-->`, rendered.head ?? '')
|
||
|
.replace(`<!--app-html-->`, rendered.html ?? '')
|
||
|
|
||
|
res.status(200).set({ 'Content-Type': 'text/html' }).end(html)
|
||
|
} catch (e) {
|
||
|
vite?.ssrFixStacktrace(e)
|
||
|
console.log(e.stack)
|
||
|
res.status(500).end(e.stack)
|
||
|
}
|
||
|
})
|
||
|
```
|
||
|
|
||
|
### Start HTTP Server
|
||
|
```typescript
|
||
|
app.listen(port, () => {
|
||
|
console.log(`Server started at http://localhost:${port}`)
|
||
|
})
|
||
|
|
||
|
```
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
# Add API support
|
||
|
[[Add api support to vite ssr app]]
|