mirror of
https://github.com/IT4Change/boilerplate-frontend.git
synced 2025-12-13 07:35:53 +00:00
vike basic setup
This commit is contained in:
parent
b3931f8ea8
commit
592f5c74d4
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
node_modules/
|
||||||
|
dist/
|
||||||
2459
package-lock.json
generated
Normal file
2459
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
35
package.json
35
package.json
@ -3,20 +3,45 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "The IT4C Boilerplate for frontends",
|
"description": "The IT4C Boilerplate for frontends",
|
||||||
"main": "build/index.js",
|
"main": "build/index.js",
|
||||||
"scripts": {
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
|
||||||
},
|
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/IT4Change/boilerplate-frontend.git"
|
"url": "git+https://github.com/IT4Change/boilerplate-frontend.git"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"npm"
|
"npm",
|
||||||
|
"vike"
|
||||||
],
|
],
|
||||||
"author": "Ulf Gebhardt",
|
"author": "Ulf Gebhardt",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/IT4Change/boilerplate-frontend/issues"
|
"url": "https://github.com/IT4Change/boilerplate-frontend/issues"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/IT4Change/boilerplate-frontend#readme"
|
"homepage": "https://github.com/IT4Change/boilerplate-frontend#readme",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "npm run server:dev",
|
||||||
|
"prod": "npm run build && npm run server:prod",
|
||||||
|
"build": "vite build",
|
||||||
|
"server": "node --loader ts-node/esm ./server/index.ts",
|
||||||
|
"server:dev": "npm run server",
|
||||||
|
"server:prod": "cross-env NODE_ENV=production npm run server",
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@types/compression": "^1.7.2",
|
||||||
|
"@types/express": "^4.17.17",
|
||||||
|
"@types/node": "^20.4.10",
|
||||||
|
"@vitejs/plugin-vue": "^4.2.3",
|
||||||
|
"@vue/compiler-sfc": "^3.3.4",
|
||||||
|
"@vue/server-renderer": "^3.3.4",
|
||||||
|
"compression": "^1.7.4",
|
||||||
|
"cross-env": "^7.0.3",
|
||||||
|
"express": "^4.18.2",
|
||||||
|
"sirv": "^2.0.3",
|
||||||
|
"ts-node": "^10.9.1",
|
||||||
|
"typescript": "^5.1.6",
|
||||||
|
"vite": "^4.4.9",
|
||||||
|
"vike": "^0.4.145",
|
||||||
|
"vue": "^3.3.4"
|
||||||
|
},
|
||||||
|
"type": "module"
|
||||||
}
|
}
|
||||||
|
|||||||
17
renderer/Link.vue
Normal file
17
renderer/Link.vue
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<template>
|
||||||
|
<a :class="{ active: pageContext.urlPathname === $attrs.href }">
|
||||||
|
<slot />
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
<style scoped>
|
||||||
|
a {
|
||||||
|
padding: 3px 10px;
|
||||||
|
}
|
||||||
|
a.active {
|
||||||
|
background-color: #eee;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { usePageContext } from './usePageContext'
|
||||||
|
const pageContext = usePageContext()
|
||||||
|
</script>
|
||||||
55
renderer/PageShell.vue
Normal file
55
renderer/PageShell.vue
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<template>
|
||||||
|
<div class="layout">
|
||||||
|
<div class="navigation">
|
||||||
|
<a href="/" class="logo">
|
||||||
|
<img src="./logo.svg" height="64" width="64" alt="logo" />
|
||||||
|
</a>
|
||||||
|
<Link href="/">Home</Link>
|
||||||
|
<Link href="/about">About</Link>
|
||||||
|
</div>
|
||||||
|
<div class="content"><slot /></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import Link from './Link.vue'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.layout {
|
||||||
|
display: flex;
|
||||||
|
max-width: 900px;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
padding: 20px;
|
||||||
|
border-left: 2px solid #eee;
|
||||||
|
padding-bottom: 50px;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
.navigation {
|
||||||
|
padding: 20px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
line-height: 1.8em;
|
||||||
|
}
|
||||||
|
.logo {
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
16
renderer/_default.page.client.ts
Normal file
16
renderer/_default.page.client.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
export { render }
|
||||||
|
|
||||||
|
import { createApp } from './app'
|
||||||
|
import type { PageContextClient } from './types'
|
||||||
|
|
||||||
|
// This render() hook only supports SSR, see https://vike.dev/render-modes for how to modify render() to support SPA
|
||||||
|
async function render(pageContext: PageContextClient) {
|
||||||
|
const { Page, pageProps } = pageContext
|
||||||
|
if (!Page) throw new Error('Client-side render() hook expects pageContext.Page to be defined')
|
||||||
|
const app = createApp(Page, pageProps, pageContext)
|
||||||
|
app.mount('#app')
|
||||||
|
}
|
||||||
|
|
||||||
|
/* To enable Client-side Routing:
|
||||||
|
export const clientRouting = true
|
||||||
|
// !! WARNING !! Before doing so, read https://vike.dev/clientRouting */
|
||||||
56
renderer/_default.page.server.ts
Normal file
56
renderer/_default.page.server.ts
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
export { render }
|
||||||
|
// See https://vike.dev/data-fetching
|
||||||
|
export const passToClient = ['pageProps', 'urlPathname']
|
||||||
|
|
||||||
|
import { renderToString as renderToString_ } from '@vue/server-renderer'
|
||||||
|
import type { App } from 'vue'
|
||||||
|
import { escapeInject, dangerouslySkipEscape } from 'vike/server'
|
||||||
|
import { createApp } from './app'
|
||||||
|
import logoUrl from './logo.svg'
|
||||||
|
import type { PageContextServer } from './types'
|
||||||
|
|
||||||
|
async function render(pageContext: PageContextServer) {
|
||||||
|
const { Page, pageProps } = pageContext
|
||||||
|
// This render() hook only supports SSR, see https://vike.dev/render-modes for how to modify render() to support SPA
|
||||||
|
if (!Page) throw new Error('My render() hook expects pageContext.Page to be defined')
|
||||||
|
const app = createApp(Page, pageProps, pageContext)
|
||||||
|
|
||||||
|
const appHtml = await renderToString(app)
|
||||||
|
|
||||||
|
// See https://vike.dev/head
|
||||||
|
const { documentProps } = pageContext.exports
|
||||||
|
const title = (documentProps && documentProps.title) || 'Vite SSR app'
|
||||||
|
const desc = (documentProps && documentProps.description) || 'App using Vite + Vike'
|
||||||
|
|
||||||
|
const documentHtml = escapeInject`<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" href="${logoUrl}" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<meta name="description" content="${desc}" />
|
||||||
|
<title>${title}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app">${dangerouslySkipEscape(appHtml)}</div>
|
||||||
|
</body>
|
||||||
|
</html>`
|
||||||
|
|
||||||
|
return {
|
||||||
|
documentHtml,
|
||||||
|
pageContext: {
|
||||||
|
// We can add some `pageContext` here, which is useful if we want to do page redirection https://vike.dev/page-redirection
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function renderToString(app: App) {
|
||||||
|
let err: unknown
|
||||||
|
// Workaround: renderToString_() swallows errors in production, see https://github.com/vuejs/core/issues/7876
|
||||||
|
app.config.errorHandler = (err_) => {
|
||||||
|
err = err_
|
||||||
|
}
|
||||||
|
const appHtml = await renderToString_(app)
|
||||||
|
if (err) throw err
|
||||||
|
return appHtml
|
||||||
|
}
|
||||||
14
renderer/_error.page.vue
Normal file
14
renderer/_error.page.vue
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<template>
|
||||||
|
<div v-if="is404">
|
||||||
|
<h1>404 Page Not Found</h1>
|
||||||
|
<p>This page could not be found.</p>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<h1>500 Internal Error</h1>
|
||||||
|
<p>Something went wrong.</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
defineProps(['is404'])
|
||||||
|
</script>
|
||||||
29
renderer/app.ts
Normal file
29
renderer/app.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { createSSRApp, defineComponent, h } from 'vue'
|
||||||
|
import PageShell from './PageShell.vue'
|
||||||
|
import { setPageContext } from './usePageContext'
|
||||||
|
import type { Component, PageContext, PageProps } from './types'
|
||||||
|
|
||||||
|
export { createApp }
|
||||||
|
|
||||||
|
function createApp(Page: Component, pageProps: PageProps | undefined, pageContext: PageContext) {
|
||||||
|
const PageWithLayout = defineComponent({
|
||||||
|
render() {
|
||||||
|
return h(
|
||||||
|
PageShell,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
default() {
|
||||||
|
return h(Page, pageProps || {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const app = createSSRApp(PageWithLayout)
|
||||||
|
|
||||||
|
// Make pageContext available from any Vue component
|
||||||
|
setPageContext(app, pageContext)
|
||||||
|
|
||||||
|
return app
|
||||||
|
}
|
||||||
36
renderer/logo.svg
Normal file
36
renderer/logo.svg
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="175" height="175" fill="none" version="1.1" viewBox="0 0 175 175" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||||
|
<metadata>
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
||||||
|
<dc:title/>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="linearGradient880" x1="108.64" x2="115.51" y1="88.726" y2="136.2" gradientTransform="matrix(1.0498 0 0 1.0498 -2.9171 -2.9658)" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#ffea83" offset="0"/>
|
||||||
|
<stop stop-color="#FFDD35" offset=".083333"/>
|
||||||
|
<stop stop-color="#FFA800" offset="1"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint2_linear" x1="48.975" x2="61.299" y1="3.9232" y2="158.04" gradientTransform="translate(-2.832e-5)" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#FFEA83" offset="0"/>
|
||||||
|
<stop stop-color="#FFDD35" offset=".083333"/>
|
||||||
|
<stop stop-color="#FFA800" offset="1"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint0_linear-6" x1="-1.4492" x2="116.62" y1="-5.8123" y2="137.08" gradientTransform="translate(-2.832e-5)" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#41D1FF" offset="0"/>
|
||||||
|
<stop stop-color="#BD34FE" offset="1"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<circle cx="87.5" cy="87.5" r="87.5" fill="#c4c4c4"/>
|
||||||
|
<circle cx="87.5" cy="87.5" r="87.5" fill="url(#paint0_linear-6)"/>
|
||||||
|
<g transform="translate(632.92 54.355)" fill="#d38787" stroke-width="1.0614">
|
||||||
|
<path d="m-549.75 68.457c-5.7533-3.1217-6.1166-5.2295-6.1166-35.489 0-30.458 0.35464-32.448 6.3339-35.54 3.9943-2.0655 24.279-2.2805 26.735-0.28333 0.89718 0.72974 6.7203 6.6637 12.94 13.187l11.309 11.86v19.575c0 18.473-0.12956 19.74-2.3011 22.5-4.0223 5.1136-7.558 5.8565-27.65 5.8099-14.15-0.03287-19.008-0.40294-21.25-1.6191zm42.473-6.3594c2.27-1.59 2.359-2.2909 2.359-18.575v-16.923h-6.9521c-12.443 0-16.4-4.0845-16.4-16.93v-7.4828h-8.9464c-6.7178 0-9.3619 0.41549-10.614 1.668-2.5031 2.5031-2.5031 55.724 0 58.228 2.4502 2.4502 37.058 2.4636 40.553 0.01609zm-1.8867-42.165c0-0.16422-2.8659-3.1346-6.3686-6.6008l-6.3686-6.3022v4.9328c0 6.3185 1.8955 8.2687 8.0366 8.2687 2.5854 0 4.7007-0.13434 4.7007-0.29859zm-57.57 44.279c-5.6185-3.0486-6.1166-5.593-6.1166-31.243 0-18.891 0.31331-24.063 1.6101-26.571 1.809-3.4981 6.5048-6.3339 10.489-6.3339 2.4847 0 2.5814 0.19984 1.541 3.1843-0.61054 1.7514-1.7457 3.1843-2.5226 3.1843-0.77686 0-2.1631 0.75059-3.0805 1.668-2.4923 2.4923-2.4923 47.244 0 49.736 0.91739 0.9174 2.3036 1.668 3.0805 1.668 0.77688 0 1.912 1.4329 2.5226 3.1843 1.0562 3.0298 0.97108 3.1822-1.7537 3.1418-1.575-0.02331-4.1713-0.75194-5.7694-1.6191zm-16.983-4.2458c-5.4392-2.9512-6.1166-5.9415-6.1166-26.997 0-15.096 0.345-19.878 1.6101-22.325 1.7476-3.3796 6.4758-6.3339 10.137-6.3339 1.8666 0 2.1789 0.44955 1.6594 2.3882-0.35184 1.3135-0.64655 2.7465-0.65453 3.1843-8e-3 0.43784-0.69682 0.79608-1.5308 0.79608-0.83399 0-2.2669 0.75059-3.1843 1.668-2.4767 2.4767-2.4767 38.768 0 41.244 0.91741 0.91739 2.2946 1.668 3.0605 1.668 1.196 0 2.6402 2.995 2.6871 5.5726 0.0241 1.3294-4.5804 0.80962-7.6676-0.8655z" style="mix-blend-mode:lighten"/>
|
||||||
|
<path d="m-552.2 68.911c-5.7533-3.1217-6.1166-5.2295-6.1166-35.489 0-30.458 0.35463-32.448 6.3339-35.54 3.9943-2.0655 24.279-2.2805 26.735-0.28333 0.89718 0.72974 6.7203 6.6637 12.94 13.187l11.309 11.86v19.575c0 18.473-0.12957 19.74-2.3011 22.5-4.0223 5.1136-7.558 5.8565-27.65 5.8099-14.15-0.03287-19.008-0.40294-21.25-1.6191zm42.473-6.3594c2.27-1.59 2.359-2.2909 2.359-18.575v-16.923h-6.952c-12.443 0-16.4-4.0845-16.4-16.93v-7.4828h-8.9464c-6.7179 0-9.3619 0.41549-10.614 1.668-2.5031 2.5031-2.5031 55.724 0 58.228 2.4502 2.4502 37.058 2.4636 40.553 0.01609zm-1.8867-42.165c0-0.16422-2.8659-3.1346-6.3686-6.6008l-6.3686-6.3022v4.9328c0 6.3185 1.8955 8.2688 8.0366 8.2688 2.5854 0 4.7007-0.13434 4.7007-0.29859zm-57.57 44.279c-5.6185-3.0486-6.1166-5.593-6.1166-31.243 0-18.891 0.31331-24.063 1.6101-26.571 1.809-3.4981 6.5048-6.3339 10.489-6.3339 2.4847 0 2.5814 0.19984 1.541 3.1843-0.61054 1.7514-1.7457 3.1843-2.5226 3.1843-0.77687 0-2.1631 0.75059-3.0805 1.668-2.4923 2.4923-2.4923 47.244 0 49.736 0.91741 0.91739 2.3036 1.668 3.0805 1.668 0.77686 0 1.912 1.4329 2.5226 3.1843 1.0562 3.0298 0.97107 3.1822-1.7537 3.1418-1.575-0.02331-4.1713-0.75194-5.7694-1.6191zm-16.983-4.2458c-5.4392-2.9512-6.1166-5.9415-6.1166-26.997 0-15.096 0.34502-19.878 1.6101-22.325 1.7476-3.3796 6.4758-6.3339 10.137-6.3339 1.8666 0 2.1789 0.44955 1.6594 2.3882-0.35182 1.3135-0.64653 2.7465-0.65452 3.1843-8e-3 0.43784-0.69683 0.79608-1.5308 0.79608-0.83397 0-2.2669 0.75059-3.1843 1.668-2.4767 2.4767-2.4767 38.768 0 41.245 0.9174 0.91739 2.2946 1.668 3.0605 1.668 1.196 0 2.6402 2.995 2.6871 5.5726 0.0241 1.3294-4.5804 0.80962-7.6676-0.8655z" fill-opacity=".47466" style="mix-blend-mode:lighten"/>
|
||||||
|
</g>
|
||||||
|
<path d="m128.48 88.913-24.027 4.6784c-0.39475 0.07685-0.68766 0.40944-0.71076 0.80849l-1.4782 24.805c-0.0347 0.58371 0.50497 1.0372 1.0792 0.90602l6.6886-1.5338c0.62676-0.14383 1.1916 0.40419 1.0635 1.0299l-1.9874 9.6702c-0.13438 0.65091 0.48084 1.2073 1.1202 1.0142l4.1322-1.2472c0.64041-0.19317 1.2556 0.36535 1.1202 1.0162l-3.158 15.191c-0.19842 0.95011 1.074 1.4677 1.6042 0.653l0.35485-0.54382 19.578-38.827c0.32755-0.64985-0.23727-1.391-0.95641-1.2535l-6.8849 1.3207c-0.6467 0.12389-1.1979-0.47453-1.0152-1.1034l4.4944-15.482c0.18266-0.63012-0.36955-1.2295-1.0173-1.1034z" fill="url(#linearGradient880)" stroke-width="1.0498"/>
|
||||||
|
<rect x="3" y="3" width="169" height="169" rx="84.5" stroke="url(#paint2_linear)" stroke-width="6" style="mix-blend-mode:soft-light"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 5.7 KiB |
37
renderer/types.ts
Normal file
37
renderer/types.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
export type {
|
||||||
|
PageContextServer,
|
||||||
|
/*
|
||||||
|
// When using Client Routing https://vike.dev/clientRouting
|
||||||
|
PageContextClient,
|
||||||
|
PageContext,
|
||||||
|
/*/
|
||||||
|
// When using Server Routing
|
||||||
|
PageContextClientWithServerRouting as PageContextClient,
|
||||||
|
PageContextWithServerRouting as PageContext
|
||||||
|
//*/
|
||||||
|
} from 'vike/types'
|
||||||
|
export type { PageProps }
|
||||||
|
export type { Component }
|
||||||
|
|
||||||
|
// https://vike.dev/pageContext#typescript
|
||||||
|
declare global {
|
||||||
|
namespace Vike {
|
||||||
|
interface PageContext {
|
||||||
|
Page: Page
|
||||||
|
pageProps?: PageProps
|
||||||
|
urlPathname: string
|
||||||
|
exports: {
|
||||||
|
documentProps?: {
|
||||||
|
title?: string
|
||||||
|
description?: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
import type { ComponentPublicInstance } from 'vue'
|
||||||
|
|
||||||
|
type Component = ComponentPublicInstance // https://stackoverflow.com/questions/63985658/how-to-type-vue-instance-out-of-definecomponent-in-vue-3/63986086#63986086
|
||||||
|
type Page = Component
|
||||||
|
type PageProps = {}
|
||||||
21
renderer/usePageContext.ts
Normal file
21
renderer/usePageContext.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// `usePageContext` allows us to access `pageContext` in any Vue component.
|
||||||
|
// See https://vike.dev/pageContext-anywhere
|
||||||
|
|
||||||
|
import { inject } from 'vue'
|
||||||
|
import type { App, InjectionKey } from 'vue'
|
||||||
|
import { PageContext } from './types'
|
||||||
|
|
||||||
|
export { usePageContext }
|
||||||
|
export { setPageContext }
|
||||||
|
|
||||||
|
const key: InjectionKey<PageContext> = Symbol()
|
||||||
|
|
||||||
|
function usePageContext() {
|
||||||
|
const pageContext = inject(key)
|
||||||
|
if (!pageContext) throw new Error('setPageContext() not called in parent')
|
||||||
|
return pageContext
|
||||||
|
}
|
||||||
|
|
||||||
|
function setPageContext(app: App, pageContext: PageContext) {
|
||||||
|
app.provide(key, pageContext)
|
||||||
|
}
|
||||||
74
server/index.ts
Normal file
74
server/index.ts
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
// This file isn't processed by Vite, see https://github.com/vikejs/vike/issues/562
|
||||||
|
// Consequently:
|
||||||
|
// - When changing this file, you needed to manually restart your server for your changes to take effect.
|
||||||
|
// - To use your environment variables defined in your .env files, you need to install dotenv, see https://vike.dev/env
|
||||||
|
// - To use your path aliases defined in your vite.config.js, you need to tell Node.js about them, see https://vike.dev/path-aliases
|
||||||
|
|
||||||
|
// If you want Vite to process your server code then use one of these:
|
||||||
|
// - vavite (https://github.com/cyco130/vavite)
|
||||||
|
// - See vavite + Vike examples at https://github.com/cyco130/vavite/tree/main/examples
|
||||||
|
// - vite-node (https://github.com/antfu/vite-node)
|
||||||
|
// - HatTip (https://github.com/hattipjs/hattip)
|
||||||
|
// - You can use Bati (https://batijs.github.io/) to scaffold a Vike + HatTip app. Note that Bati generates apps that use the V1 design (https://vike.dev/migration/v1-design) and Vike packages (https://vike.dev/vike-packages)
|
||||||
|
|
||||||
|
import express from 'express'
|
||||||
|
import compression from 'compression'
|
||||||
|
import { renderPage } from 'vike/server'
|
||||||
|
import { root } from './root.js'
|
||||||
|
const isProduction = process.env.NODE_ENV === 'production'
|
||||||
|
|
||||||
|
startServer()
|
||||||
|
|
||||||
|
async function startServer() {
|
||||||
|
const app = express()
|
||||||
|
|
||||||
|
app.use(compression())
|
||||||
|
|
||||||
|
// Vite integration
|
||||||
|
if (isProduction) {
|
||||||
|
// In production, we need to serve our static assets ourselves.
|
||||||
|
// (In dev, Vite's middleware serves our static assets.)
|
||||||
|
const sirv = (await import('sirv')).default
|
||||||
|
app.use(sirv(`${root}/dist/client`))
|
||||||
|
} else {
|
||||||
|
// We instantiate Vite's development server and integrate its middleware to our server.
|
||||||
|
// ⚠️ We instantiate it only in development. (It isn't needed in production and it
|
||||||
|
// would unnecessarily bloat our production server.)
|
||||||
|
const vite = await import('vite')
|
||||||
|
const viteDevMiddleware = (
|
||||||
|
await vite.createServer({
|
||||||
|
root,
|
||||||
|
server: { middlewareMode: true }
|
||||||
|
})
|
||||||
|
).middlewares
|
||||||
|
app.use(viteDevMiddleware)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ...
|
||||||
|
// Other middlewares (e.g. some RPC middleware such as Telefunc)
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// Vike middleware. It should always be our last middleware (because it's a
|
||||||
|
// catch-all middleware superseding any middleware placed after it).
|
||||||
|
app.get('*', async (req, res, next) => {
|
||||||
|
const pageContextInit = {
|
||||||
|
urlOriginal: req.originalUrl
|
||||||
|
}
|
||||||
|
const pageContext = await renderPage(pageContextInit)
|
||||||
|
const { httpResponse } = pageContext
|
||||||
|
if (!httpResponse) {
|
||||||
|
return next()
|
||||||
|
} else {
|
||||||
|
const { body, statusCode, headers, earlyHints } = httpResponse
|
||||||
|
if (res.writeEarlyHints) res.writeEarlyHints({ link: earlyHints.map((e) => e.earlyHintLink) })
|
||||||
|
headers.forEach(([name, value]) => res.setHeader(name, value))
|
||||||
|
res.status(statusCode)
|
||||||
|
// For HTTP streams use httpResponse.pipe() instead, see https://vike.dev/stream
|
||||||
|
res.send(body)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const port = process.env.PORT || 3000
|
||||||
|
app.listen(port)
|
||||||
|
console.log(`Server running at http://localhost:${port}`)
|
||||||
|
}
|
||||||
8
server/root.ts
Normal file
8
server/root.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export { root }
|
||||||
|
|
||||||
|
// https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-when-using-the-experimental-modules-flag/50052194#50052194
|
||||||
|
|
||||||
|
import { dirname } from 'path'
|
||||||
|
import { fileURLToPath } from 'url'
|
||||||
|
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||||
|
const root = `${__dirname}/..`
|
||||||
9
server/tsconfig.json
Normal file
9
server/tsconfig.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"extends": "../tsconfig.json",
|
||||||
|
// Make IDEs complain about missing file extension .js in import paths.
|
||||||
|
// Alternatively, we could always set "module" to "Node16" and add the file extension .js to import paths everywhere.
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "Node16",
|
||||||
|
"moduleResolution": "Node16"
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/pages/about/index.page.vue
Normal file
13
src/pages/about/index.page.vue
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<template>
|
||||||
|
<h1>About</h1>
|
||||||
|
<p>Example of app using Vike.</p>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
code {
|
||||||
|
font-family: monospace;
|
||||||
|
background-color: #eaeaea;
|
||||||
|
padding: 3px 5px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
8
src/pages/index/Counter.vue
Normal file
8
src/pages/index/Counter.vue
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<template>
|
||||||
|
<button type="button" @click="state.count++">Counter {{ state.count }}</button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { reactive } from 'vue'
|
||||||
|
const state = reactive({ count: 0 })
|
||||||
|
</script>
|
||||||
12
src/pages/index/index.page.vue
Normal file
12
src/pages/index/index.page.vue
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<template>
|
||||||
|
<h1>Welcome</h1>
|
||||||
|
This page is:
|
||||||
|
<ul>
|
||||||
|
<li>Rendered to HTML.</li>
|
||||||
|
<li>Interactive. <Counter /></li>
|
||||||
|
</ul>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import Counter from './Counter.vue'
|
||||||
|
</script>
|
||||||
4
src/vue.d.ts
vendored
Normal file
4
src/vue.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
declare module '*.vue' {
|
||||||
|
const Component: any
|
||||||
|
export default Component
|
||||||
|
}
|
||||||
21
tsconfig.json
Normal file
21
tsconfig.json
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"strict": true,
|
||||||
|
"module": "ES2020",
|
||||||
|
"target": "ES2020",
|
||||||
|
// Doesn't apply to server/, see ts-node config down below and server/tsconfig.json
|
||||||
|
"moduleResolution": "Bundler",
|
||||||
|
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
||||||
|
"types": ["vite/client"],
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"esModuleInterop": true
|
||||||
|
},
|
||||||
|
"ts-node": {
|
||||||
|
"transpileOnly": true,
|
||||||
|
"esm": true,
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "Node16",
|
||||||
|
"moduleResolution": "Node16"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user