From 809e33297215ccaff548fc02ed05feb07000ade7 Mon Sep 17 00:00:00 2001 From: dash <1549469775@qq.com> Date: Mon, 29 Sep 2025 23:43:39 +0800 Subject: [PATCH] =?UTF-8?q?=E9=9B=8F=E5=BD=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 10 +++++ bun.lockb | Bin 198834 -> 215533 bytes client/App.vue | 31 +++++++++++++++ client/assets/vue.svg | 1 + client/components/HelloWorld.vue | 38 ++++++++++++++++++ client/entry-client.ts | 6 +++ client/entry-server.ts | 15 +++++++ client/main.ts | 10 +++++ client/style.css | 79 +++++++++++++++++++++++++++++++++++++ client/vite-env.d.ts | 7 ++++ index.html | 14 +++++++ package.json | 24 ++++++----- public/vite.svg | 1 + server.js | 66 +++++++++++++++++++++++++++++++ server.ts | 71 +++++++++++++++++++++++++++++++++ vite.config copy.ts | 82 ++++++++++++++++++++++++++++++++++++++ vite.config.ts | 83 ++------------------------------------- 17 files changed, 446 insertions(+), 92 deletions(-) create mode 100644 client/App.vue create mode 100644 client/assets/vue.svg create mode 100644 client/components/HelloWorld.vue create mode 100644 client/entry-client.ts create mode 100644 client/entry-server.ts create mode 100644 client/main.ts create mode 100644 client/style.css create mode 100644 client/vite-env.d.ts create mode 100644 index.html create mode 100644 public/vite.svg create mode 100644 server.js create mode 100644 server.ts create mode 100644 vite.config copy.ts diff --git a/README.md b/README.md index 5764c61..7918d2f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,13 @@ +## ssr + +https://stackblitz.com/edit/bluwy-create-vite-extra-fuc1kcnj?file=index.html,server.js,src%2FApp.vue,src%2Fcomponents%2FHelloWorld.vue,src%2Fassets%2Fvue.svg + +bun run server.ts + +bunx tsc .\server.ts --module NodeNext --target esnext --moduleResolution nodenext + + + ## koa3-demo diff --git a/bun.lockb b/bun.lockb index 8f97feb0893745cc0616da2938663e60f96eea7a..daa08b11a1dc565e1ff0b5d2d437b8ff62159569 100644 GIT binary patch delta 42296 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 K{M5ze;r{|AdrMIO diff --git a/client/App.vue b/client/App.vue new file mode 100644 index 0000000..5cc7b23 --- /dev/null +++ b/client/App.vue @@ -0,0 +1,31 @@ + + + + + diff --git a/client/assets/vue.svg b/client/assets/vue.svg new file mode 100644 index 0000000..770e9d3 --- /dev/null +++ b/client/assets/vue.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/components/HelloWorld.vue b/client/components/HelloWorld.vue new file mode 100644 index 0000000..63f7e72 --- /dev/null +++ b/client/components/HelloWorld.vue @@ -0,0 +1,38 @@ + + + + + diff --git a/client/entry-client.ts b/client/entry-client.ts new file mode 100644 index 0000000..ae68fdd --- /dev/null +++ b/client/entry-client.ts @@ -0,0 +1,6 @@ +import './style.css' +import { createApp } from "./main" + +const { app } = createApp() + +app.mount('#app') diff --git a/client/entry-server.ts b/client/entry-server.ts new file mode 100644 index 0000000..bbafdd3 --- /dev/null +++ b/client/entry-server.ts @@ -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 } +} diff --git a/client/main.ts b/client/main.ts new file mode 100644 index 0000000..ff091f8 --- /dev/null +++ b/client/main.ts @@ -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 } +} diff --git a/client/style.css b/client/style.css new file mode 100644 index 0000000..f691315 --- /dev/null +++ b/client/style.css @@ -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; + } +} diff --git a/client/vite-env.d.ts b/client/vite-env.d.ts new file mode 100644 index 0000000..323c78a --- /dev/null +++ b/client/vite-env.d.ts @@ -0,0 +1,7 @@ +/// + +declare module '*.vue' { + import type { DefineComponent } from 'vue' + const component: DefineComponent<{}, {}, any> + export default component +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..70c1f19 --- /dev/null +++ b/index.html @@ -0,0 +1,14 @@ + + + + + + + Vite + Vue + TS + + + +
+ + + diff --git a/package.json b/package.json index 199afea..7545092 100644 --- a/package.json +++ b/package.json @@ -4,23 +4,19 @@ "version": "0.0.1-alpha", "type": "module", "scripts": { - "dev": "bun --hot src/main.js", - "start": "cross-env NODE_ENV=production bun run src/main.js", - "build": "vite build", - "migrate:make": "npx knex migrate:make ", - "migrate": "npx knex migrate:latest", - "seed:make": "npx knex seed:make ", - "seed": "npx knex seed:run ", - "dev:init": "bun run scripts/init.js", - "init": "cross-env NODE_ENV=production bun run scripts/init.js", - "test": "bun test", - "test:db:run": "bun run scripts/run-db-tests.js", - "test:db:benchmark": "bun run scripts/db-benchmark.js" + "dev": "bun run server.ts", + "build": "npm run build:client && npm run build:server", + "build:client": "vite build --outDir dist/client", + "build:server": "vite build --ssr client/entry-server.ts --outDir dist/server", + "preview": "cross-env NODE_ENV=production node server", + "check": "vue-tsc" }, "devDependencies": { "@types/bun": "latest", + "@types/koa": "^3.0.0", "@types/node": "^24.0.1", "cross-env": "^10.0.0", + "koa-send": "^5.0.1", "module-alias": "^2.2.3", "node-gyp": "^11.4.2", "vite": "^7.0.0", @@ -28,6 +24,7 @@ }, "dependencies": { "@koa/etag": "^5.0.1", + "@vitejs/plugin-vue": "^6.0.1", "bcryptjs": "^3.0.2", "consolidate": "^1.0.4", "extend-shallow": "^3.0.2", @@ -39,6 +36,7 @@ "knex": "^3.1.0", "koa": "^3.0.0", "koa-bodyparser": "^4.4.1", + "koa-connect": "^2.1.0", "koa-helmet": "^8.0.1", "koa-ratelimit": "^6.0.0", "koa-session": "^7.0.2", @@ -62,6 +60,6 @@ "services": "./src/services" }, "peerDependencies": { - "typescript": "^5.0.0" + "typescript": "^5.9.2" } } \ No newline at end of file diff --git a/public/vite.svg b/public/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/server.js b/server.js new file mode 100644 index 0000000..76512b4 --- /dev/null +++ b/server.js @@ -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(``, rendered.head ?? '') + .replace(``, 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}`); +}); diff --git a/server.ts b/server.ts new file mode 100644 index 0000000..21162b0 --- /dev/null +++ b/server.ts @@ -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(``, rendered.head ?? '') + .replace(``, 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}`) +}) diff --git a/vite.config copy.ts b/vite.config copy.ts new file mode 100644 index 0000000..ef21700 --- /dev/null +++ b/vite.config copy.ts @@ -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: "", + }, + ], + }), + ], +}) diff --git a/vite.config.ts b/vite.config.ts index ef21700..bbcf80c 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,82 +1,7 @@ -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] -} +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +// https://vite.dev/config/ 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: "", - }, - ], - }), - ], + plugins: [vue()], })