17 changed files with 446 additions and 92 deletions
Binary file not shown.
@ -0,0 +1,31 @@ |
|||||
|
<script setup lang="ts"> |
||||
|
// This starter template is using Vue 3 <script setup> SFCs |
||||
|
// Check out https://vuejs.org/api/sfc-script-setup.html#script-setup |
||||
|
import HelloWorld from './components/HelloWorld.vue'; |
||||
|
</script> |
||||
|
|
||||
|
<template> |
||||
|
<div> |
||||
|
<a href="https://vite.dev" target="_blank"> |
||||
|
<img src="/vite.svg" class="logo" alt="Vite logo" />AAA |
||||
|
</a> |
||||
|
<a href="https://vuejs.org/" target="_blank"> |
||||
|
<img src="./assets/vue.svg" class="logo vue" alt="Vue logo" /> |
||||
|
</a> |
||||
|
</div> |
||||
|
<HelloWorld msg="Vite + Vue" /> |
||||
|
</template> |
||||
|
|
||||
|
<style scoped> |
||||
|
.logo { |
||||
|
height: 6em; |
||||
|
padding: 1.5em; |
||||
|
will-change: filter; |
||||
|
} |
||||
|
.logo:hover { |
||||
|
filter: drop-shadow(0 0 2em #646cffaa); |
||||
|
} |
||||
|
.logo.vue:hover { |
||||
|
filter: drop-shadow(0 0 2em #42b883aa); |
||||
|
} |
||||
|
</style> |
||||
|
After Width: | Height: | Size: 496 B |
@ -0,0 +1,38 @@ |
|||||
|
<script setup lang="ts"> |
||||
|
import { ref } from 'vue'; |
||||
|
|
||||
|
defineProps<{ msg: string }>(); |
||||
|
|
||||
|
const count = ref(0); |
||||
|
</script> |
||||
|
|
||||
|
<template> |
||||
|
<h1>{{ msg }}</h1> |
||||
|
|
||||
|
<div class="card"> |
||||
|
<button type="button" @click="count++">count 啊啊撒打算 {{ count }}</button> |
||||
|
<p> |
||||
|
Edit |
||||
|
<code>components/HelloWorld.vue</code> to test HMR |
||||
|
</p> |
||||
|
</div> |
||||
|
|
||||
|
<p> |
||||
|
Check out |
||||
|
<a href="https://vuejs.org/guide/quick-start.html#local" target="_blank" |
||||
|
>create-vue</a |
||||
|
>, the official Vue + Vite starter |
||||
|
</p> |
||||
|
<p> |
||||
|
Install |
||||
|
<a href="https://github.com/johnsoncodehk/volar" target="_blank">Volar</a> |
||||
|
in your IDE for a better DX |
||||
|
</p> |
||||
|
<p class="read-the-docs">Click on the Vite and Vue logos to learn more</p> |
||||
|
</template> |
||||
|
|
||||
|
<style scoped> |
||||
|
.read-the-docs { |
||||
|
color: #888; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,6 @@ |
|||||
|
import './style.css' |
||||
|
import { createApp } from "./main" |
||||
|
|
||||
|
const { app } = createApp() |
||||
|
|
||||
|
app.mount('#app') |
||||
@ -0,0 +1,15 @@ |
|||||
|
import { renderToString } from 'vue/server-renderer' |
||||
|
import { createApp } from './main' |
||||
|
|
||||
|
export async function render(_url: string) { |
||||
|
const { app } = createApp() |
||||
|
|
||||
|
// passing SSR context object which will be available via useSSRContext()
|
||||
|
// @vitejs/plugin-vue injects code into a component's setup() that registers
|
||||
|
// itself on ctx.modules. After the render, ctx.modules would contain all the
|
||||
|
// components that have been instantiated during this render call.
|
||||
|
const ctx = {} |
||||
|
const html = await renderToString(app, ctx) |
||||
|
|
||||
|
return { html } |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
import { createSSRApp } from 'vue' |
||||
|
import App from './App.vue' |
||||
|
|
||||
|
// SSR requires a fresh app instance per request, therefore we export a function
|
||||
|
// that creates a fresh app instance. If using Vuex, we'd also be creating a
|
||||
|
// fresh store here.
|
||||
|
export function createApp() { |
||||
|
const app = createSSRApp(App) |
||||
|
return { app } |
||||
|
} |
||||
@ -0,0 +1,79 @@ |
|||||
|
:root { |
||||
|
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; |
||||
|
line-height: 1.5; |
||||
|
font-weight: 400; |
||||
|
|
||||
|
color-scheme: light dark; |
||||
|
color: rgba(255, 255, 255, 0.87); |
||||
|
background-color: #242424; |
||||
|
|
||||
|
font-synthesis: none; |
||||
|
text-rendering: optimizeLegibility; |
||||
|
-webkit-font-smoothing: antialiased; |
||||
|
-moz-osx-font-smoothing: grayscale; |
||||
|
} |
||||
|
|
||||
|
a { |
||||
|
font-weight: 500; |
||||
|
color: #646cff; |
||||
|
text-decoration: inherit; |
||||
|
} |
||||
|
a:hover { |
||||
|
color: #535bf2; |
||||
|
} |
||||
|
|
||||
|
body { |
||||
|
margin: 0; |
||||
|
display: flex; |
||||
|
place-items: center; |
||||
|
min-width: 320px; |
||||
|
min-height: 100vh; |
||||
|
} |
||||
|
|
||||
|
h1 { |
||||
|
font-size: 3.2em; |
||||
|
line-height: 1.1; |
||||
|
} |
||||
|
|
||||
|
button { |
||||
|
border-radius: 8px; |
||||
|
border: 1px solid transparent; |
||||
|
padding: 0.6em 1.2em; |
||||
|
font-size: 1em; |
||||
|
font-weight: 500; |
||||
|
font-family: inherit; |
||||
|
background-color: #1a1a1a; |
||||
|
cursor: pointer; |
||||
|
transition: border-color 0.25s; |
||||
|
} |
||||
|
button:hover { |
||||
|
border-color: #646cff; |
||||
|
} |
||||
|
button:focus, |
||||
|
button:focus-visible { |
||||
|
outline: 4px auto -webkit-focus-ring-color; |
||||
|
} |
||||
|
|
||||
|
.card { |
||||
|
padding: 2em; |
||||
|
} |
||||
|
|
||||
|
#app { |
||||
|
max-width: 1280px; |
||||
|
margin: 0 auto; |
||||
|
padding: 2rem; |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
@media (prefers-color-scheme: light) { |
||||
|
:root { |
||||
|
color: #213547; |
||||
|
background-color: #ffffff; |
||||
|
} |
||||
|
a:hover { |
||||
|
color: #747bff; |
||||
|
} |
||||
|
button { |
||||
|
background-color: #f9f9f9; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
/// <reference types="vite/client" />
|
||||
|
|
||||
|
declare module '*.vue' { |
||||
|
import type { DefineComponent } from 'vue' |
||||
|
const component: DefineComponent<{}, {}, any> |
||||
|
export default component |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html lang="en"> |
||||
|
<head> |
||||
|
<meta charset="UTF-8" /> |
||||
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" /> |
||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
||||
|
<title>Vite + Vue + TS</title> |
||||
|
<!--app-head--> |
||||
|
</head> |
||||
|
<body> |
||||
|
<div id="app"><!--app-html--></div> |
||||
|
<script type="module" src="/client/entry-client.ts"></script> |
||||
|
</body> |
||||
|
</html> |
||||
|
After Width: | Height: | Size: 1.5 KiB |
@ -0,0 +1,66 @@ |
|||||
|
import fs from 'node:fs/promises'; |
||||
|
import Koa from "koa"; |
||||
|
import c2k from 'koa-connect'; |
||||
|
import Send from 'koa-send'; |
||||
|
// Constants
|
||||
|
const isProduction = process.env.NODE_ENV === 'production'; |
||||
|
const port = process.env.PORT || 5173; |
||||
|
const base = process.env.BASE || '/'; |
||||
|
// Cached production assets
|
||||
|
const templateHtml = isProduction |
||||
|
? await fs.readFile('./dist/client/index.html', 'utf-8') |
||||
|
: ''; |
||||
|
const app = new Koa(); |
||||
|
// Add Vite or respective production middlewares
|
||||
|
/** @type {import('vite').ViteDevServer | undefined} */ |
||||
|
let vite; |
||||
|
if (!isProduction) { |
||||
|
const { createServer } = await import('vite'); |
||||
|
vite = await createServer({ |
||||
|
server: { middlewareMode: true }, |
||||
|
appType: 'custom', |
||||
|
base, |
||||
|
}); |
||||
|
app.use(c2k(vite.middlewares)); |
||||
|
} |
||||
|
else { |
||||
|
app.use(Send({ root: 'dist/client', index: false })); |
||||
|
} |
||||
|
app.use(async (ctx, next) => { |
||||
|
try { |
||||
|
const url = ctx.path.replace(base, ''); |
||||
|
/** @type {string} */ |
||||
|
let template; |
||||
|
/** @type {import('./client/entry-server.ts').render} */ |
||||
|
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('/client/entry-server.ts')).render; |
||||
|
} |
||||
|
else { |
||||
|
template = templateHtml; |
||||
|
// @ts-ignore
|
||||
|
render = (await import('./dist/server/entry-server.js')).render; |
||||
|
} |
||||
|
const rendered = await render(url); |
||||
|
const html = template |
||||
|
.replace(`<!--app-head-->`, rendered.head ?? '') |
||||
|
.replace(`<!--app-html-->`, rendered.html ?? ''); |
||||
|
ctx.status = 200; |
||||
|
ctx.set({ 'Content-Type': 'text/html' }); |
||||
|
ctx.body = html; |
||||
|
} |
||||
|
catch (e) { |
||||
|
vite?.ssrFixStacktrace(e); |
||||
|
console.log(e.stack); |
||||
|
ctx.status = 500; |
||||
|
ctx.body = e.stack; |
||||
|
} |
||||
|
await next(); |
||||
|
}); |
||||
|
// Start http server
|
||||
|
app.listen(port, () => { |
||||
|
console.log(`Server started at http://localhost:${port}`); |
||||
|
}); |
||||
@ -0,0 +1,71 @@ |
|||||
|
import fs from 'node:fs/promises' |
||||
|
import Koa from "koa" |
||||
|
import c2k from 'koa-connect' |
||||
|
import { ViteDevServer } from 'vite' |
||||
|
import Send from 'koa-send' |
||||
|
|
||||
|
// Constants
|
||||
|
const isProduction = process.env.NODE_ENV === 'production' |
||||
|
const port = process.env.PORT || 5173 |
||||
|
const base = process.env.BASE || '/' |
||||
|
|
||||
|
// Cached production assets
|
||||
|
const templateHtml = isProduction |
||||
|
? await fs.readFile('./dist/client/index.html', 'utf-8') |
||||
|
: '' |
||||
|
|
||||
|
const app = new Koa() |
||||
|
|
||||
|
// Add Vite or respective production middlewares
|
||||
|
/** @type {import('vite').ViteDevServer | undefined} */ |
||||
|
let vite: ViteDevServer |
||||
|
if (!isProduction) { |
||||
|
const { createServer } = await import('vite') |
||||
|
vite = await createServer({ |
||||
|
server: { middlewareMode: true }, |
||||
|
appType: 'custom', |
||||
|
base, |
||||
|
}) |
||||
|
app.use(c2k(vite.middlewares)) |
||||
|
} else { |
||||
|
app.use(Send({ root: 'dist/client', index: false })) |
||||
|
} |
||||
|
app.use(async (ctx, next) => { |
||||
|
try { |
||||
|
const url = ctx.path.replace(base, '') |
||||
|
/** @type {string} */ |
||||
|
let template |
||||
|
/** @type {import('./client/entry-server.ts').render} */ |
||||
|
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('/client/entry-server.ts')).render |
||||
|
} else { |
||||
|
template = templateHtml |
||||
|
// @ts-ignore
|
||||
|
render = (await import('./dist/server/entry-server.js')).render |
||||
|
} |
||||
|
|
||||
|
const rendered = await render(url) |
||||
|
|
||||
|
const html = template |
||||
|
.replace(`<!--app-head-->`, rendered.head ?? '') |
||||
|
.replace(`<!--app-html-->`, rendered.html ?? '') |
||||
|
ctx.status = 200 |
||||
|
ctx.set({ 'Content-Type': 'text/html' }) |
||||
|
ctx.body = html |
||||
|
} catch (e: Error | any) { |
||||
|
vite?.ssrFixStacktrace(e) |
||||
|
console.log(e.stack) |
||||
|
ctx.status = 500 |
||||
|
ctx.body = e.stack |
||||
|
} |
||||
|
await next() |
||||
|
}) |
||||
|
|
||||
|
// Start http server
|
||||
|
app.listen(port, () => { |
||||
|
console.log(`Server started at http://localhost:${port}`) |
||||
|
}) |
||||
@ -0,0 +1,82 @@ |
|||||
|
import { dirname, resolve } from "node:path" |
||||
|
import { fileURLToPath } from "node:url" |
||||
|
import module from "node:module" |
||||
|
import { defineConfig } from "vite" |
||||
|
import pkg from "./package.json" |
||||
|
import { viteStaticCopy } from "vite-plugin-static-copy" |
||||
|
|
||||
|
const __dirname = dirname(fileURLToPath(import.meta.url)) |
||||
|
|
||||
|
function getExternal(): string[] { |
||||
|
return [...Object.keys(pkg.dependencies || {}), ...module.builtinModules] |
||||
|
} |
||||
|
|
||||
|
export default defineConfig({ |
||||
|
publicDir: false, |
||||
|
resolve: { |
||||
|
alias: { |
||||
|
"@": resolve(__dirname, "src"), |
||||
|
db: resolve(__dirname, "src/db"), |
||||
|
config: resolve(__dirname, "src/config"), |
||||
|
utils: resolve(__dirname, "src/utils"), |
||||
|
}, |
||||
|
}, |
||||
|
build: { |
||||
|
lib: { |
||||
|
entry: resolve(__dirname, "src/main.js"), |
||||
|
formats: ["es"], |
||||
|
fileName: () => `[name].js`, |
||||
|
}, |
||||
|
outDir: resolve(__dirname, "dist"), |
||||
|
rollupOptions: { |
||||
|
external: getExternal(), |
||||
|
// watch: {
|
||||
|
// include: "src/**",
|
||||
|
// exclude: "node_modules/**",
|
||||
|
// },
|
||||
|
output: { |
||||
|
preserveModules: true, |
||||
|
preserveModulesRoot: "src", |
||||
|
inlineDynamicImports: false, |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
plugins: [ |
||||
|
viteStaticCopy({ |
||||
|
targets: [ |
||||
|
{ |
||||
|
src: "public", |
||||
|
dest: "", |
||||
|
}, |
||||
|
{ |
||||
|
src: "src/views", |
||||
|
dest: "", |
||||
|
}, |
||||
|
{ |
||||
|
src: "src/db/migrations", |
||||
|
dest: "db", |
||||
|
}, |
||||
|
{ |
||||
|
src: "src/db/seeds", |
||||
|
dest: "db", |
||||
|
}, |
||||
|
{ |
||||
|
src: "entrypoint.sh", |
||||
|
dest: "", |
||||
|
}, |
||||
|
{ |
||||
|
src: "package.json", |
||||
|
dest: "", |
||||
|
}, |
||||
|
{ |
||||
|
src: "knexfile.mjs", |
||||
|
dest: "", |
||||
|
}, |
||||
|
{ |
||||
|
src: "bun.lockb", |
||||
|
dest: "", |
||||
|
}, |
||||
|
], |
||||
|
}), |
||||
|
], |
||||
|
}) |
||||
@ -1,82 +1,7 @@ |
|||||
import { dirname, resolve } from "node:path" |
import { defineConfig } from 'vite' |
||||
import { fileURLToPath } from "node:url" |
import vue from '@vitejs/plugin-vue' |
||||
import module from "node:module" |
|
||||
import { defineConfig } from "vite" |
|
||||
import pkg from "./package.json" |
|
||||
import { viteStaticCopy } from "vite-plugin-static-copy" |
|
||||
|
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url)) |
|
||||
|
|
||||
function getExternal(): string[] { |
|
||||
return [...Object.keys(pkg.dependencies || {}), ...module.builtinModules] |
|
||||
} |
|
||||
|
|
||||
|
// https://vite.dev/config/
|
||||
export default defineConfig({ |
export default defineConfig({ |
||||
publicDir: false, |
plugins: [vue()], |
||||
resolve: { |
|
||||
alias: { |
|
||||
"@": resolve(__dirname, "src"), |
|
||||
db: resolve(__dirname, "src/db"), |
|
||||
config: resolve(__dirname, "src/config"), |
|
||||
utils: resolve(__dirname, "src/utils"), |
|
||||
}, |
|
||||
}, |
|
||||
build: { |
|
||||
lib: { |
|
||||
entry: resolve(__dirname, "src/main.js"), |
|
||||
formats: ["es"], |
|
||||
fileName: () => `[name].js`, |
|
||||
}, |
|
||||
outDir: resolve(__dirname, "dist"), |
|
||||
rollupOptions: { |
|
||||
external: getExternal(), |
|
||||
// watch: {
|
|
||||
// include: "src/**",
|
|
||||
// exclude: "node_modules/**",
|
|
||||
// },
|
|
||||
output: { |
|
||||
preserveModules: true, |
|
||||
preserveModulesRoot: "src", |
|
||||
inlineDynamicImports: false, |
|
||||
}, |
|
||||
}, |
|
||||
}, |
|
||||
plugins: [ |
|
||||
viteStaticCopy({ |
|
||||
targets: [ |
|
||||
{ |
|
||||
src: "public", |
|
||||
dest: "", |
|
||||
}, |
|
||||
{ |
|
||||
src: "src/views", |
|
||||
dest: "", |
|
||||
}, |
|
||||
{ |
|
||||
src: "src/db/migrations", |
|
||||
dest: "db", |
|
||||
}, |
|
||||
{ |
|
||||
src: "src/db/seeds", |
|
||||
dest: "db", |
|
||||
}, |
|
||||
{ |
|
||||
src: "entrypoint.sh", |
|
||||
dest: "", |
|
||||
}, |
|
||||
{ |
|
||||
src: "package.json", |
|
||||
dest: "", |
|
||||
}, |
|
||||
{ |
|
||||
src: "knexfile.mjs", |
|
||||
dest: "", |
|
||||
}, |
|
||||
{ |
|
||||
src: "bun.lockb", |
|
||||
dest: "", |
|
||||
}, |
|
||||
], |
|
||||
}), |
|
||||
], |
|
||||
}) |
}) |
||||
|
|||||
Loading…
Reference in new issue