Skip to content

Commit 297dda8

Browse files
pi0danielroe
andcommitted
initial version
Co-authored-by: Daniel Roe <[email protected]>
0 parents  commit 297dda8

File tree

15 files changed

+244
-0
lines changed

15 files changed

+244
-0
lines changed

.gitignore

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
9+
10+
node_modules
11+
dist
12+
dist-ssr
13+
*.local
14+
15+
# Editor directories and files
16+
.vscode/*
17+
!.vscode/extensions.json
18+
.idea
19+
.DS_Store
20+
*.suo
21+
*.ntvs*
22+
*.njsproj
23+
*.sln
24+
*.sw?

.vscode/extensions.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"recommendations": ["johnsoncodehk.volar"]
3+
}

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Vue 3 + SSR + Vite
2+
3+
This template should help get you started developing with Vue 3 and SSR in Vite.
4+
5+
## Recommended IDE Setup
6+
7+
- [VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar)
8+
9+
## Type Support For `.vue` Imports in TS
10+
11+
Since TypeScript cannot handle type information for `.vue` imports, they are shimmed to be a generic Vue component type by default. In most cases this is fine if you don't really care about component prop types outside of templates. However, if you wish to get actual prop types in `.vue` imports (for example to get props validation when using manual `h(...)` calls), you can enable Volar's `.vue` type support plugin by running `Volar: Switch TS Plugin on/off` from VSCode command palette.

index.html

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
4+
<head>
5+
<meta charset="UTF-8" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>Vite App</title>
8+
</head>
9+
10+
<body>
11+
<div id="app">
12+
<!--app-html-->
13+
</div>
14+
<script type="module" src="/src/entry-client.ts"></script>
15+
</body>
16+
17+
</html>

package.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"private": true,
3+
"scripts": {
4+
"dev": "node ./server.mjs"
5+
},
6+
"dependencies": {
7+
"vue": "^3.2.25",
8+
"vue-router": "^4.0.0"
9+
},
10+
"devDependencies": {
11+
"@vitejs/plugin-vue": "latest",
12+
"@vitejs/plugin-vue-jsx": "latest",
13+
"express": "^4.17.1",
14+
"vite": "latest"
15+
}
16+
}

public/favicon.ico

4.19 KB
Binary file not shown.

server.mjs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import fs from 'fs'
2+
import path from 'path'
3+
import express from 'express'
4+
import { createServer } from 'vite'
5+
6+
const resolve = (p) => path.resolve(p)
7+
8+
const manifest = {}
9+
10+
const app = express()
11+
12+
const vite = await createServer({
13+
root: resolve('.'),
14+
logLevel: 'info',
15+
server: {
16+
middlewareMode: 'ssr',
17+
watch: {
18+
// During tests we edit the files too fast and sometimes chokidar
19+
// misses change events, so enforce polling for consistency
20+
usePolling: true,
21+
interval: 100,
22+
},
23+
},
24+
})
25+
26+
// use vite's connect instance as middleware
27+
app.use(vite.middlewares);
28+
29+
app.use('*', async (req, res) => {
30+
try {
31+
const url = req.originalUrl;
32+
33+
let template, render;
34+
35+
template = fs.readFileSync(resolve('index.html'), 'utf-8');
36+
template = await vite.transformIndexHtml(url, template);
37+
render = (await vite.ssrLoadModule('/src/entry-server.ts')).render;
38+
39+
const appHtml = await render(url, manifest);
40+
41+
const html = template
42+
.replace(`<!--app-html-->`, appHtml);
43+
44+
res.status(200).set({ 'Content-Type': 'text/html' }).end(html);
45+
} catch (e) {
46+
vite && vite.ssrFixStacktrace(e);
47+
console.log(e.stack);
48+
res.status(500).end(e.stack);
49+
}
50+
});
51+
52+
53+
app.listen(3000, () => {
54+
console.log('http://localhost:3000');
55+
})

src/App.vue

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<template>
2+
<div>
3+
<router-link to="/">Home</router-link>
4+
<router-view v-slot="{ Component }">
5+
<Suspense>
6+
<component :is="Component" />
7+
</Suspense>
8+
</router-view>
9+
</div>
10+
</template>
11+
12+
<style>
13+
@font-face {
14+
font-family: 'Inter';
15+
font-style: italic;
16+
font-weight: 400;
17+
font-display: swap;
18+
src: url('./assets/fonts/Inter-Italic.woff2#iefix') format('woff2'),
19+
url('./assets/fonts/Inter-Italic.woff') format('woff');
20+
}
21+
.inter {
22+
font-family: 'Inter';
23+
}
24+
#app {
25+
font-family: Avenir, Helvetica, Arial, sans-serif;
26+
-webkit-font-smoothing: antialiased;
27+
-moz-osx-font-smoothing: grayscale;
28+
text-align: center;
29+
color: #2c3e50;
30+
margin-top: 60px;
31+
}
32+
</style>

src/entry-client.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { createApp } from './main';
2+
3+
const { app, router } = createApp();
4+
5+
router.isReady().then(() => {
6+
app.mount('#app');
7+
});

src/entry-server.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { createApp } from './main';
2+
import { renderToString } from 'vue/server-renderer';
3+
4+
export async function render(url, manifest) {
5+
const { app, router } = createApp();
6+
7+
router.push(url);
8+
await router.isReady();
9+
10+
const ctx = {};
11+
const html = await renderToString(app, ctx);
12+
return { html };
13+
}

0 commit comments

Comments
 (0)