Let my path choose you 
HOMEPAGE 
TYPESCRIPT 
性能优化 
CSR 

步骤1: 浏览器请求 HTML
↓
步骤2: 服务器返回空壳 HTML
↓
步骤3: 浏览器加载 Vue.js
↓
步骤4: 浏览器执行 JS,请求数据
↓
步骤5: 浏览器渲染页面内容<!-- CSR模式下的初始HTML -->
<!DOCTYPE html>
<html>
  <body>
    <div id="app">
      <!-- 这里初始是空的 -->
    </div>
    <script src="vue.js"></script>
    <script>
      const app = Vue.createApp({
        data() {
          return { products: [] };
        },
        mounted() {
          // 在客户端请求数据
          fetch("/api/products")
            .then((res) => res.json())
            .then((data) => (this.products = data));
        },
      }).mount("#app");
    </script>
  </body>
</html>SSR 

步骤1: 浏览器请求 HTML
↓
步骤2: 服务器执行 Vue 代码
↓
步骤3: 服务器获取数据
↓
步骤4: 服务器生成完整 HTML
↓
步骤5: 浏览器接收并显示完整内容
↓
步骤6: 加载 JS 后激活交互功能// SSR服务器端代码
import { createSSRApp } from "vue";
import { renderToString } from "vue/server-renderer";
async function render(url) {
  const app = createSSRApp({
    data() {
      return {
        products: [],
      };
    },
  });
  // 在服务器端获取数据
  const products = await fetch("http://api/products").then((res) => res.json());
  app.data().products = products;
  // 生成HTML字符串
  const html = await renderToString(app);
  // 返回完整的HTML
  return `
        <!DOCTYPE html>
        <html>
        <body>
            <div id="app">${html}</div>
            <script>
                // 注入初始状态
                window.__INITIAL_STATE__ = ${JSON.stringify(products)}
            </script>
            <script src="vue.js"></script>
            <script src="app.js"></script>
        </body>
        </html>
    `;
}all in all 

简而言之,做一个常规的企业官网,复杂度相对而言是比较低的,难点在于视觉、动画,并且截至 2022 年 9 月 8 日浏览器的SEO(Search Engine Optimization)对SPA(Single Page Application)应用-CSR(Client Side Render 客户端渲染) 还不友好,为了SEO需要上Multi Page Application-SSR(Server Side Render),,是否需要使用SSG(Static Site Generation) 不适合动态获取数据的场景Nuxt.js Next.js这样的服务端渲染框架要考虑实际情况,切勿舍近求远。
区别的可视化展示 
CSR 初始 HTML 
<!-- 浏览器收到的初始HTML -->
<div id="app">
  <!-- 空的 -->
</div>SSR 初始 HTML 
<!-- 浏览器收到的初始HTML -->
<div id="app">
  <div class="product-list">
    <div class="product">
      <h2>商品1</h2>
      <p>价格: ¥99</p>
    </div>
    <div class="product">
      <h2>商品2</h2>
      <p>价格: ¥199</p>
    </div>
  </div>
</div>SSR 的主要优势 
- 更快的首屏加载
 
- 用户立即看到完整内容
 - 不需要等待 JS 执行完毕
 
- 更好的 SEO
 
- 搜索引擎可以直接爬取完整内容
 - 对内容网站特别重要
 
- 更好的用户体验
 
- 无需等待空白页面
 - 特别适合网速较慢的场景
 
SSR 的主要劣势 
- 服务器压力 SSR 需要服务器执行 Vue 代码和数据获取,需要合理控制服务器负载
 - 开发复杂度
 
Question 
即使我用 Nuxt,我的数据也是请求的单独的后端服务,就是在 nuxt 中也只是调用数据接口,这样仍然算是服务端渲染吗
以下内容来自 claude-3.5-sonnet
这仍然是服务端渲染!让我解释原因:
1. Nuxt 的渲染流程 
浏览器请求页面
↓
Nuxt服务器接收请求
↓
执行页面组件的asyncData/fetch
↓
调用后端API获取数据
↓
Nuxt服务器用数据渲染完整HTML
↓
返回完整HTML给浏览器
↓
浏览器展示内容并激活(hydration)2. 代码示例对比 
传统客户端渲染:
<template>
  <div class="products">
    <!-- 初始加载时这里是空的 -->
    <div v-for="product in products" :key="product.id">
      {{ product.name }}
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      products: [],
    };
  },
  mounted() {
    // 在浏览器端请求数据
    fetch("http://api.example.com/products")
      .then((res) => res.json())
      .then((data) => (this.products = data));
  },
};
</script>Nuxt 服务端渲染:
<template>
  <div class="products">
    <!-- 服务器端已经填充好数据 -->
    <div v-for="product in products" :key="product.id">
      {{ product.name }}
    </div>
  </div>
</template>
<script>
export default {
  async asyncData({ $axios }) {
    // 在服务器端执行!
    const products = await $axios.$get("http://api.example.com/products");
    return { products };
  },
};
</script>3. 关键区别 
浏览器收到的 HTML 内容: 
客户端渲染:
<div class="products">
  <!-- 空的 -->
</div>Nuxt SSR:
<div class="products">
  <div>iPhone 13</div>
  <div>MacBook Pro</div>
  <div>iPad Air</div>
  <!-- 数据已经填充 -->
</div>4. 为什么这仍然是 SSR? 
- 数据获取时机
 
// Nuxt在服务器端完成这些步骤:
async function serverRender() {
  // 1. 执行asyncData/fetch
  const data = await fetchData();
  // 2. 使用数据渲染HTML
  const html = await renderComponent(data);
  // 3. 返回完整HTML
  return html;
}- HTML 生成位置
 
虽然数据来自外部 API,但 HTML 的生成是在 Nuxt 服务器上完成的,而不是在浏览器中完成的
5. Nuxt 中的数据获取方式 
- asyncData 方法
 
export default {
  async asyncData({ $axios }) {
    // 服务器端执行
    const data = await $axios.$get("/api/data");
    return { data };
  },
};- fetch 钩子
 
export default {
  async fetch() {
    // 服务器端执行
    this.items = await this.$axios.$get("/api/items");
  },
};6. 验证是否 SSR 的方法 
export default {
  mounted() {
    // 查看HTML源代码是否包含数据
    console.log(document.documentElement.outerHTML);
    // 或使用Vue开发者工具查看
    console.log("是否为SSR:", this.$nuxt?.$ssrContext != null);
  },
};7. SSR 的优化建议 
- 使用缓存
 
// nuxt.config.js
export default {
  render: {
    http2: {
      push: true,
    },
    static: {
      maxAge: 1000 * 60 * 60 * 24 * 7, // 7天缓存
    },
  },
};- 数据预取优化
 
export default {
  async asyncData({ $axios, store }) {
    try {
      // 并行请求多个API
      const [products, categories] = await Promise.all([
        $axios.$get("/api/products"),
        $axios.$get("/api/categories"),
      ]);
      return { products, categories };
    } catch (error) {
      console.error(error);
      return { error: "Failed to load data" };
    }
  },
};记住:SSR 的关键不在于数据从哪里来,而在于HTML 的生成位置和时机。只要 HTML 是在服务器端生成的,并且包含了完整的内容,就是 SSR。
references: 
服务端渲染(SSR)和预渲染(Prerendering)有什么区别?
官网网站用什么技术栈比较合理? - 知乎 (zhihu.com)
2022 年,企业官网开发,前端需要用到那些技术? - 知乎 (zhihu.com)
nuxt 框架 Universal 和 Spa 两种 render mode 的区别_daruanzai3165 的博客-CSDN 博客
SSG 和 SSR 有什么区别? - 知乎 (zhihu.com)
https://zhuanlan.zhihu.com/p/431930680
chrisvfritz/prerender-spa-plugin: Prerenders static HTML in a single-page application. (github.com)
Next.js 的三种渲染方式(BSR、SSG、SSR) - 知乎 (zhihu.com)
vue 单页面(SPA)和多页面(MPA)的区别(详细答案) - 掘金 (juejin.cn)
浅谈 SPA、CSR、SSR、MPA、SSG 专有名词 | 是 Ray 不是 Array (israynotarray.com)
vue 服务端渲染和客户端渲染的区别是什么-前端问答-PHP 中文网
为什么客户端渲染首屏渲染慢和 SEO 问题_Coder 小何的博客-CSDN 博客
Render 
js 在任何时候都会阻塞 dom,所以通常会将 js 放在 body 结束之后,这样页面渲染完成再执行 js,有利于用户体验
css 的加载会阻塞后面 js 的执行;css 加载不会阻塞 DOM 树的解析,但会阻塞 Render 树的渲染
重排一定会触发重绘,重绘不一定会触发重排

触发重排 
- 页面首次渲染
 - 浏览器窗口大小变化
 - 元素尺寸、位置、内容、字体大小发生变化
 - 添加或删除可见的元素
 - 激活伪类时
 
触发重绘 
- 改变元素颜色、背景、visibility、outline 等属性
 
referrences 
*浏览器已原生支持 ES 模块,这对前端开发来说意味着什么?
客户端渲染路线:
- 请求一个 html
 - 服务端返回一个 html
 - 浏览器下载 html 中的 js/css 文件
 - 等待 js 文件下载完成,加载并初始化完成,可以运行,由 js 代码向后端请求数据(ajax/fetch)
 - 等待后端数据返回
 - 客户端从无到完整地,把数据渲染为响应页面 
服务端渲染路线:
 - 请求一个 html
 - 服务端请求数据(内网请求快)
 - 服务器初始渲染(服务端性能好,较快),可以理解为组装数据和模板
 - 服务端返回已经有正确内容的页面
 - 客户端请求 js/css 文件
 - 等待 js 文件下载完成,加载并初始化完成
 - 客户端把剩下一部分渲染完成(内容小,渲染快)
 
Deploy 
# ubuntu install nginx
sudo apt install -y nginx
直接在浏览器访问服务器公网ip,如果出现nginx欢迎页面,说明安装成功