使用 Koa2 + Vite + TypeScript + Vue 3 + Pinia 构建 SSR 项目,能让你获得服务端渲染的 SEO 和首屏加载优势,同时享受现代前端开发工具链的流畅体验。这个组合在构建企业级应用时非常强大。

下面这个流程图梳理了项目搭建的核心流程和关键步骤,可以帮助你建立整体认识。

🛠️ 项目搭建与SSR配置

以下是实现SSR的核心配置步骤:

  1. 初始化项目与基础配置
    使用以下命令创建项目骨架,并选择合适的配置:

    bash

    pnpm create vite koa2-ssr-vue3-ts-pinia -- --template vue-ts

    之后,按照企业级标准集成 ESLint、Prettier 以统一代码风格,并配置 tsconfig.json 和 vite.config.ts

  2. 修改客户端入口
    为了适配 SSR,需要将普通的客户端创建模式改为使用 createSSRApp,并拆分入口文件。

    在 src/main.ts 中导出工厂函数:

    typescript

    import { createSSRApp } from "vue";
    import App from "./App.vue";
    
    export const createApp = () => {
      const app = createSSRApp(App);
      return { app };
    }

    创建新的客户端入口文件 src/entry-client.ts

    typescript

    import { createApp } from "./main"
    
    const { app } = createApp();
    app.mount("#app");

    同时,记得在 index.html 中将引入的脚本改为 src/entry-client.ts

  3. 创建Koa2服务器与SSR中间件
    这是实现服务端渲染的核心。你需要创建一个 Koa2 服务器,并在其中集成 Vite 和 SSR 能力。

    安装依赖:pnpm i koa koa-connect @vue/server-renderer --save

    创建服务器文件(例如 server.js 或 server-dev.ts),核心代码如下:

    javascript

    const Koa = require('koa');
    const koaConnect = require('koa-connect');
    const vite = require('vite');
    
    (async () => {
      const app = new Koa();
      const viteServer = await vite.createServer({
        root: process.cwd(),
        server: { middlewareMode: true },
      });
      
      app.use(koaConnect(viteServer.middlewares));
      
      app.use(async (ctx) => {
        try {
          const template = await fs.readFileSync(path.resolve(__dirname, 'index.html'), 'utf-8');
          const transformedTemplate = await viteServer.transformIndexHtml(ctx.path, template);
          
          const { render } = await viteServer.ssrLoadModule('/src/entry-server.ts');
          const { renderedHtml } = await render(ctx, {});
          
          const html = transformedTemplate.replace('<!--app-html-->', renderedHtml);
          ctx.body = html;
        } catch (e) {
          console.log(e.stack);
          ctx.throw(500, e.stack);
        }
      });
      
      app.listen(9000, () => { console.log('Server is listening on 9000'); });
    })();
  4. 创建服务端入口文件
    服务端入口文件使用 renderToString 将 Vue 应用渲染成 HTML 字符串。

    创建 src/entry-server.ts

    typescript

    import { renderToString } from '@vue/server-renderer';
    import { createApp } from './main';
    
    export const render = async (ctx: any) => {
      const { app } = createApp();
      const renderedHtml = await renderToString(app);
      return { renderedHtml };
    }
  5. 修改HTML模板
    在 index.html 中提供一个占位符,以便服务器渲染的内容可以插入其中。

    html

    <!DOCTYPE html>
    <html>
      <head> ... </head>
      <body>
        <div id="app"><!--app-html--></div>
        <script type="module" src="/src/entry-client.ts"></script>
      </body>
    </html>

💡 企业级项目优化建议

要让这个项目达到企业级标准,你还需要关注以下几点:

  • 类型安全与架构:为企业级项目设计清晰的目录结构(如 api/components/composables/stores/),并严格定义 TypeScript 接口和类型,这能显著提升代码的可维护性和团队协作效率。

  • 状态管理 (Pinia):在 SSR 环境中使用 Pinia 时,关键在于状态序列化与激活,以避免客户端和服务器状态不一致导致的问题。

    1. 在服务端渲染时,将 Store 状态序列化到 HTML 中:

      html

      <script>
        window.__INITIAL_STATE__ = <!-- 序列化的Pinia状态 -->;
      </script>
    2. 在客户端入口处,在挂载应用之前反序列化并激活状态:

      typescript

      // entry-client.ts
      if (window.__INITIAL_STATE__) {
        pinia.state.value = window.__INITIAL_STATE__;
      }
  • 性能与代码规范

    • 构建优化:利用 Vite 的构建功能,对代码进行压缩(如 drop_console: true)和分割。

    • 代码规范:集成 ESLint 和 Prettier,并可以使用 commitizen 和 husky 来规范 Git 提交信息,这对于团队协作至关重要。

⚠️ 常见问题与解决方案

  • ** hydration 不匹配:这是一个常见的 SSR 问题。确保服务器和客户端生成的 DOM 结构完全一致**。请特别检查是否在 Vue 组件中使用了浏览器特有的 API(如 document),这些操作应放在 onMounted 生命周期钩子中。

  • 开发环境配置:确保你的开发服务器 (server-dev.ts) 正确配置了 Vite 中间件,以便利用其热更新 (HMR) 能力。

  • 生产环境构建:生产环境需要分别构建客户端和服务端资源。你可能需要调整 Vite 配置来生成 SSR 专用的构建文件,并确保服务器能正确提供这些静态资源。

Logo

一站式 AI 云服务平台

更多推荐