SSR+前端框架 项目工程核心

前言

关于SSR的概念和其优缺点在之前的博客Node服务器端渲染(SSR概念篇)也做过总结,目前学习了如何在实际的代码中实现SSR的前端项目搭建,写此博客也是对 SSR+前端框架 项目工程搭建的一个总结,加上个人的理解。

注意

旨在讲个大概的 代码 结构,基本的结构和代码是用来干什么的,不能做到从 0 基础 到 完全完成项目的初始化。

没有用到 Nuxt.js 或者 Next.js 这种SSR框架,原生 node+vue 讲解

核心技术栈

Node.js + Express + Vue3

运行环境

node环境

项目介绍

核心实现原理

SSR的实现重点是在 服务端 生成页面的元素 DOM等返回给 浏览器

这里我们嵌入前端框架实现SSR,大概分下面几个步骤:

  1. 用前端框架编写app.js脚本,引入框架的组件
  2. 编写服务器端返回静态html页面的接口
  3. 在静态html中,加入前端框架 的组件
  4. 在静态html中,加入前端框架的客户端脚本,使静态页面加入前端框架,实现交互功能。

项目结构

项目目录

build是打包文件,本项目使用webpack打包工具进行的项目打包

核心模块介绍

咱们按照"核心实现原理"步骤中的几步中,来进行项目结构,功能的介绍src下的项目核心SSR配置:

1.app.js(框架引入主组件脚本)

用前端框架编写app.js,引入框架的组件

代码
javascript 复制代码
import { createSSRApp } from "vue";
import App from "./App.vue";
export default function createApp() {
  // 创建app
  const app = createSSRApp(App);
  return app;
}
// createApp(App).mount("#app");
vue 复制代码
<template>
  <div class="app" style="border: 1px solid red">
    <h1>App</h1>
    <div>count: {{ count }}</div>
    <button @click="addNumber">+1</button>
  </div>
</template>

<script setup>
  import { ref } from "vue";
  const count = ref(100);
  function addNumber() {
    count.value += 1;
  }
</script>

2.server(服务端)

功能:
  • 编写服务器端返回静态html页面的接口
  • 开启服务器
  • 配置资源路径
  • 在静态html中,加入前端框架 的组件
  • ...
代码
javascript 复制代码
import express from "express";
import createApp from "../app";
import { renderToString } from "@vue/server-renderer";

let app = express();
let App = createApp();

// 部署 静态资源
app.use(express.static("build"));

// 和注册的顺序有关系,优先匹配第一个符合的路径
app.get("/*", async (req, res) => {
  const AppContent = await renderToString(App);
  console.log(AppContent);
  res.send(`
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <link rel="icon" href="data:;base64,=">
        <title>Document</title>
      </head>
      <body>
        <h1> Vue + Server Side Render</h1>
        <div id="app">${AppContent}</div>
        <script src="/client/client_bundle.js"></script>
      </body>
    </html>
  `);
});
app.listen(3000, () => {
  console.log("Node Server Start On 3000");
});

3.client(客户端)

功能:
  • 在静态html中,加入前端框架的客户端脚本
  • 使静态页面加入前端框架,实现交互功能。
  • ...
代码
javascript 复制代码
import { createApp } from "vue";
import App from "../App.vue";
let app = createApp(App);
app.mount("#app"); // 需要在body添加id=app标签

配置模块

config(项目打包配置)

javascript 复制代码
let path = require("path");
let nodeExternals = require("webpack-node-externals");
let { DefinePlugin } = require("webpack");
let { VueLoaderPlugin } = require("vue-loader/dist/index");
module.exports = {
  mode: "development",
  module: {
    rules: [
      {
        test: /\.js$/,
        use: [
          {
            loader: "babel-loader",
          },
        ],
      },
      {
        test: /\.vue$/,
        loader: "vue-loader",
      },
    ],
  },
  plugins: [
    new VueLoaderPlugin(),
    // 定义两个环境变量,关闭option api 和 pro 调试的提示
    new DefinePlugin({
      __VUE_OPTIONS_API__: false,
      __VUE_PROD_DEVTOOLS__: false,
    }),
  ],
  resolve: {
    extensions: [".js", ".json", ".wasm", ".jsx", ".jsx", "vue"],
  },
};
javascript 复制代码
let path = require("path");
let baseConfig = require("./base.config");
let { merge } = require("webpack-merge");
module.exports = merge(baseConfig, {
  target: "web", // 构建目标环境
  entry: "./src/client/index.js",
  output: {
    filename: "client_bundle.js",
    path: path.resolve(__dirname, "../build/client"),
  },
});
javascript 复制代码
let path = require("path");
let nodeExternals = require("webpack-node-externals");
let baseConfig = require("./base.config");
let { merge } = require("webpack-merge");
module.exports = merge(baseConfig, {
  target: "node",
  entry: "./src/server/index.js",
  output: {
    filename: "server_bundle.js",
    path: path.resolve(__dirname, "../build/server"),
  },
  externals: [nodeExternals()],
});

package.json

json 复制代码
{
  "name": "01-node-server",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build:server": "webpack --config ./config/server.config.js --watch",
    "build:client": "webpack --config ./config/client.config.js --watch",
    "start:server": "nodemon ./build/server/server_bundle.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "axios": "^1.2.1",
    "express": "^4.18.2",
    "nodemon": "^2.0.20",
    "pinia": "^2.0.26",
    "vue": "^3.2.45",
    "vue-loader": "^17.0.1",
    "vue-router": "^4.1.6",
    "webpack-node-externals": "^3.0.0"
  },
  "devDependencies": {
    "@babel/preset-env": "^7.20.2",
    "babel-loader": "^9.1.0",
    "webpack": "^5.75.0",
    "webpack-cli": "^5.0.0",
    "webpack-merge": "^5.8.0"
  }
}
相关推荐
天天进步20154 小时前
前端工程化:Webpack从入门到精通
前端·webpack·node.js
知识分享小能手5 小时前
Vue3 学习教程,从入门到精通,使用 VSCode 开发 Vue3 的详细指南(3)
前端·javascript·vue.js·学习·前端框架·vue·vue3
前端小趴菜057 小时前
react状态管理库 - zustand
前端·react.js·前端框架
实习生小黄13 小时前
express 连接在线数据库踩坑
node.js·express
Thomas游戏开发14 小时前
Unity3D Boehm GC原理解析
前端框架·unity3d·游戏开发
Thomas游戏开发15 小时前
Unity3D 文件夹注释工具
前端框架·unity3d·游戏开发
liangshanbo121515 小时前
微前端框架对比
前端框架
NetX行者16 小时前
基于Vue 3的AI前端框架汇总及工具对比表
前端·vue.js·人工智能·前端框架·开源
伍哥的传说16 小时前
H3初识——入门介绍之常用中间件
前端·javascript·react.js·中间件·前端框架·node.js·ecmascript
超级土豆粉17 小时前
npm 包 scheduler 介绍
前端·npm·node.js