35 lines
55 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en-US" dir="ltr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>服务端渲染(SSR) | ZiuChen</title>
<meta name="description" content="Unlimited Progress.">
<link rel="preload stylesheet" href="/assets/style.60c127af.css" as="style">
<link rel="modulepreload" href="/assets/chunks/VPAlgoliaSearchBox.7b810437.js">
<link rel="modulepreload" href="/assets/app.6cf9e426.js">
<link rel="modulepreload" href="/assets/note_SSR.md.5e6cefdd.lean.js">
<link rel="icon" href="/logo.png">
<script id="check-dark-light">(()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})();</script>
</head>
<body>
<div id="app"><div class="Layout" data-v-3af881ed><!--[--><!--]--><!--[--><span tabindex="-1" data-v-00bddfc0></span><a href="#VPContent" class="VPSkipLink visually-hidden" data-v-00bddfc0> Skip to content </a><!--]--><!----><header class="VPNav" data-v-3af881ed data-v-3796071a><div class="VPNavBar has-sidebar" data-v-3796071a data-v-fe00b0e5><div class="container" data-v-fe00b0e5><div class="title" data-v-fe00b0e5><div class="VPNavBarTitle has-sidebar" data-v-fe00b0e5 data-v-a7f91dcc><a class="title" href="/" data-v-a7f91dcc><!--[--><!--]--><!--[--><img class="VPImage logo" src="/logo.png" alt data-v-dca92699><!--]--><!--[-->ZiuChen<!--]--><!--[--><!--]--></a></div></div><div class="content" data-v-fe00b0e5><div class="curtain" data-v-fe00b0e5></div><div class="content-body" data-v-fe00b0e5><!--[--><!--]--><div class="VPNavBarSearch search" data-v-fe00b0e5 style="--6dc8a562:&#39;Meta&#39;;"><div id="docsearch"><button type="button" class="DocSearch DocSearch-Button" aria-label="Search"><span class="DocSearch-Button-Container"><svg class="DocSearch-Search-Icon" width="20" height="20" viewBox="0 0 20 20"><path d="M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z" stroke="currentColor" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"></path></svg><span class="DocSearch-Button-Placeholder">Search</span></span><span class="DocSearch-Button-Keys"><kbd class="DocSearch-Button-Key"></kbd><kbd class="DocSearch-Button-Key">K</kbd></span></button></div></div><nav aria-labelledby="main-nav-aria-label" class="VPNavBarMenu menu" data-v-fe00b0e5 data-v-a4f7fa5c><span id="main-nav-aria-label" class="visually-hidden" data-v-a4f7fa5c>Main Navigation</span><!--[--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/" data-v-a4f7fa5c data-v-1a106a35 data-v-8dd200cc><!--[-->首页<!--]--><!----></a><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-a4f7fa5c data-v-e76b733c><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-e76b733c><span class="text" data-v-e76b733c><!----> 我的项目 <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-e76b733c><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-e76b733c><div class="VPMenu" data-v-e76b733c data-v-faf23071><div class="items" data-v-faf23071><!--[--><!--[--><div class="VPMenuLink" data-v-faf23071 data-v-c0d2d58e><a class="VPLink link" href="/project/ClipboardManager/" data-v-c0d2d58e data-v-8dd200cc><!--[-->超级剪贴板<!--]--><!----></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-faf23071 data-v-c0d2d58e><a class="VPLink link" href="/project/SmartWordBreak/" data-v-c0d2d58e data-v-8dd200cc><!--[-->超级分词<!--]--><!----></a></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-a4f7fa5c data-v-e76b733c><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-e76b733c><span class="text" data-v-e76b733c><!----> 开源作品 <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-e76b733c><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-e76b733c><div class="VPMenu" data-v-e76b733c data-v-faf23071><div class="items" data-v-faf23071><!--[--><!--[--><div class="VPMenuLink" data-v-faf23071 data-v-c0d2d58e><a class="VPLink link" href="/works/opensource.html" data-v-c0d2d58e data-v-8dd200cc><!--[-->个人作品<!--]--><!----></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-faf23071 data-v-c0d2d58e><a class="VPLink link" href="/works/contribution.html" data-v-c0d2d58e data-v-8dd200cc><!--[-->社区贡献<!--]--><!----></a></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-a4f7fa5c data-v-e76b733c><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-e76b733c><span class="text" data-v-e76b733c><!----> 学习笔记 <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-e76b733c><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-e76b733c><div class="VPMenu" data-v-e76b733c data-v-faf23071><div class="items" data-v-faf23071><!--[--><!--[--><div class="VPMenuLink" data-v-faf23071 data-v-c0d2d58e><a class="VPLink link" href="/note/JavaScript.html" data-v-c0d2d58e data-v-8dd200cc><!--[-->JavaScript基础<!--]--><!----></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-faf23071 data-v-c0d2d58e><a class="VPLink link" href="/note/CSS.html" data-v-c0d2d58e data-v-8dd200cc><!--[-->CSS基础<!--]--><!----></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-faf23071 data-v-c0d2d58e><a class="VPLink link" href="/note/JavaScriptEnhanced.html" data-v-c0d2d58e data-v-8dd200cc><!--[-->JavaScript进阶<!--]--><!----></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-faf23071 data-v-c0d2d58e><a class="VPLink link" href="/note/Front-end%20Engineering.html" data-v-c0d2d58e data-v-8dd200cc><!--[-->前端工程化<!--]--><!----></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-faf23071 data-v-c0d2d58e><a class="VPLink link active" href="/note/SSR.html" data-v-c0d2d58e data-v-8dd200cc><!--[-->服务端渲染<!--]--><!----></a></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/self/" data-v-a4f7fa5c data-v-1a106a35 data-v-8dd200cc><!--[-->个人介绍<!--]--><!----></a><!--]--><!--]--></nav><!----><div class="VPNavBarAppearance appearance" data-v-fe00b0e5 data-v-2d4753dd><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" aria-label="toggle dark mode" aria-checked="false" data-v-2d4753dd data-v-867372a0 data-v-dc009bc3><span class="check" data-v-dc009bc3><span class="icon" data-v-dc009bc3><!--[--><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="sun" data-v-867372a0><path d="M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z"></path><path d="M12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z"></path><path d="M12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z"></path><path d="M5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z"></path><path d="M19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z"></path><path d="M3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z"></path><path d="M23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z"></path><path d="M4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z"></path><path d="M18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="moon" data-v-867372a0><path d="M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z"></path></svg><!--]--></span></span></button></div><div class="VPSocialLinks VPNavBarSocialLinks social-links" data-v-fe00b0e5 data-v-f0005c73 data-v-819d8281><!--[--><a class="VPSocialLink" href="https://ziuchen.github.io/" target="_blank" rel="noopener" data-v-819d8281 data-v-ba84061a><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></a><a class="VPSocialLink" href="https://juejin.cn/user/1887205216238477" target="_blank" rel="noopener" data-v-819d8281 data-v-ba84061a><svg width="36" height="28" viewBox="0 0 36 28" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M17.5875 6.77268L21.8232 3.40505L17.5875 0.00748237L17.5837 0L13.3555 3.39757L17.5837 6.76894L17.5875 6.77268ZM17.5863 17.3955H17.59L28.5161 8.77432L25.5526 6.39453L17.59 12.6808H17.5863L17.5825 12.6845L9.61993 6.40201L6.66016 8.78181L17.5825 17.3992L17.5863 17.3955ZM17.5828 23.2891L17.5865 23.2854L32.2133 11.7456L35.1768 14.1254L28.5238 19.3752L17.5865 28L0.284376 14.3574L0 14.1291L2.95977 11.7531L17.5828 23.2891Z" fill="#1E80FF"/></svg></a><!--]--></div><div class="VPFlyout VPNavBarExtra extra" data-v-fe00b0e5 data-v-0467f0ad data-v-e76b733c><button type="button" class="button" aria-haspopup="true" aria-expanded="false" aria-label="extra navigation" data-v-e76b733c><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="icon" data-v-e76b733c><circle cx="12" cy="12" r="2"></circle><circle cx="19" cy="12" r="2"></circle><circle cx="5" cy="12" r="2"></circle></svg></button><div class="menu" data-v-e76b733c><div class="VPMenu" data-v-e76b733c data-v-faf23071><!----><!--[--><!--[--><!----><div class="group" data-v-0467f0ad><div class="item appearance" data-v-0467f0ad><p class="label" data-v-0467f0ad>Appearance</p><div class="appearance-action" data-v-0467f0ad><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" aria-label="toggle dark mode" aria-checked="false" data-v-0467f0ad data-v-867372a0 data-v-dc009bc3><span class="check" data-v-dc009bc3><span class="icon" data-v-dc009bc3><!--[--><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="sun" data-v-867372a0><path d="M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z"></path><path d="M12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z"></path><path d="M12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z"></path><path d="M5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z"></path><path d="M19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z"></path><path d="M3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z"></path><path d="M23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z"></path><path d="M4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z"></path><path d="M18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="moon" data-v-867372a0><path d="M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z"></path></svg><!--]--></span></span></button></div></div></div><div class="group" data-v-0467f0ad><div class="item social-links" data-v-0467f0ad><div class="VPSocialLinks social-links-list" data-v-0467f0ad data-v-819d8281><!--[--><a class="VPSocialLink" href="https://ziuchen.github.io/" target="_blank" rel="noopener" data-v-819d8281 data-v-ba84061a><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></a><a class="VPSocialLink" href="https://juejin.cn/user/1887205216238477" target="_blank" rel="noopener" data-v-819d8281 data-v-ba84061a><svg width="36" height="28" viewBox="0 0 36 28" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M17.5875 6.77268L21.8232 3.40505L17.5875 0.00748237L17.5837 0L13.3555 3.39757L17.5837 6.76894L17.5875 6.77268ZM17.5863 17.3955H17.59L28.5161 8.77432L25.5526 6.39453L17.59 12.6808H17.5863L17.5825 12.6845L9.61993 6.40201L6.66016 8.78181L17.5825 17.3992L17.5863 17.3955ZM17.5828 23.2891L17.5865 23.2854L32.2133 11.7456L35.1768 14.1254L28.5238 19.3752L17.5865 28L0.284376 14.3574L0 14.1291L2.95977 11.7531L17.5828 23.2891Z" fill="#1E80FF"/></svg></a><!--]--></div></div></div><!--]--><!--]--></div></div></div><!--[--><!--]--><button type="button" class="VPNavBarHamburger hamburger" aria-label="mobile navigation" aria-expanded="false" aria-controls="VPNavScreen" data-v-fe00b0e5 data-v-f1813d69><span class="container" data-v-f1813d69><span class="top" data-v-f1813d69></span><span class="middle" data-v-f1813d69></span><span class="bottom" data-v-f1813d69></span></span></button></div></div></div></div><!----></header><div class="VPLocalNav" data-v-3af881ed data-v-07d63927><button class="menu" aria-expanded="false" aria-controls="VPSidebarNav" data-v-07d63927><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="menu-icon" data-v-07d63927><path d="M17,11H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,11,17,11z"></path><path d="M21,7H3C2.4,7,2,6.6,2,6s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,7,21,7z"></path><path d="M21,15H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,15,21,15z"></path><path d="M17,19H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,19,17,19z"></path></svg><span class="menu-text" data-v-07d63927>Menu</span></button><a class="top-link" href="#" data-v-07d63927>Return to top</a></div><aside class="VPSidebar" data-v-3af881ed data-v-eec6a639><div class="curtain" data-v-eec6a639></div><nav class="nav" id="VPSidebarNav" aria-labelledby="sidebar-aria-label" tabindex="-1" data-v-eec6a639><span class="visually-hidden" id="sidebar-aria-label" data-v-eec6a639> Sidebar Navigation </span><!--[--><!--]--><!--[--><div class="group" data-v-eec6a639><section class="VPSidebarItem level-0 collapsible" data-v-eec6a639 data-v-66b47b62><div class="item" role="button" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link" data-v-66b47b62 data-v-8dd200cc><!--[--><h2 class="text" data-v-66b47b62>我的项目</h2><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-66b47b62><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-66b47b62><!--[--><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/project/ClipboardManager/" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>超级剪贴板</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/project/SmartWordBreak/" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>超级分词</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><!--]--></div></section></div><div class="group" data-v-eec6a639><section class="VPSidebarItem level-0 collapsible" data-v-eec6a639 data-v-66b47b62><div class="item" role="button" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link" data-v-66b47b62 data-v-8dd200cc><!--[--><h2 class="text" data-v-66b47b62>开源作品</h2><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-66b47b62><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-66b47b62><!--[--><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/works/opensource.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>个人作品</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/works/contribution.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>社区贡献</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><!--]--></div></section></div><div class="group" data-v-eec6a639><section class="VPSidebarItem level-0 collapsible" data-v-eec6a639 data-v-66b47b62><div class="item" role="button" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link" data-v-66b47b62 data-v-8dd200cc><!--[--><h2 class="text" data-v-66b47b62>文章归档</h2><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-66b47b62><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-66b47b62><!--[--><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/article/%E3%80%902023%E3%80%91%E9%9D%92%E8%AE%AD%E8%90%A5%20-%20%E5%89%8D%E7%AB%AF%E7%BB%83%E4%B9%A0%E9%A2%98%E6%B1%87%E6%80%BB%E8%A7%A3%E6%9E%90.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>【2023】青训营 - 前端练习题汇总解析</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/article/%E4%B8%80%E6%96%87%E8%AF%BB%E6%87%82%E4%BA%8B%E4%BB%B6%E5%86%92%E6%B3%A1%E4%B8%8E%E4%BA%8B%E4%BB%B6%E6%8D%95%E8%8E%B7.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>一文读懂事件冒泡与事件捕获</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/article/%E4%B8%80%E6%96%87%E8%AF%BB%E6%87%82%E4%BC%AA%E7%B1%BB%E4%B8%8E%E4%BC%AA%E5%85%83%E7%B4%A0.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>一文读懂伪类与伪元素</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/article/%E4%B8%80%E6%96%87%E8%AF%BB%E6%87%82%E5%87%BD%E6%95%B0%E4%B8%ADthis%E6%8C%87%E5%90%91%E9%97%AE%E9%A2%98.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>一文读懂函数中this指向问题</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/article/%E4%BB%8E0%E5%AE%9E%E7%8E%B0%E4%B8%80%E4%B8%AA%E5%B9%B4%E5%BA%A6%E6%8A%A5%E5%91%8A.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>从0实现一个年度报告</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/article/%E5%BD%BB%E5%BA%95%E6%90%9E%E6%87%82%E5%AF%B9%E8%B1%A1%E7%9A%84%E6%95%B0%E6%8D%AE%E5%B1%9E%E6%80%A7%E6%8F%8F%E8%BF%B0%E7%AC%A6%E3%80%81%E5%AD%98%E5%82%A8%E5%B1%9E%E6%80%A7%E6%8F%8F%E8%BF%B0%E7%AC%A6.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>彻底搞懂对象的数据属性描述符、存储属性描述符</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/article/%E6%B7%B1%E5%85%A5Vue3%E6%BA%90%E7%A0%81%EF%BC%8C%E7%9C%8B%E7%9C%8BVue.use%E5%90%8E%E7%A9%B6%E7%AB%9F%E5%8F%91%E7%94%9F%E4%BA%86%E4%BB%80%E4%B9%88%EF%BC%9F.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>深入Vue3源码看看Vue.use后究竟发生了什么</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/article/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3Proxy%E4%B8%8EReflect.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>深入理解Proxy与Reflect</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/article/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3%E6%B5%8F%E8%A7%88%E5%99%A8%E7%BC%93%E5%AD%98%E6%9C%BA%E5%88%B6.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>深入理解浏览器缓存机制</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/article/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3%E6%B5%8F%E8%A7%88%E5%99%A8%E8%BF%90%E8%A1%8C%E5%8E%9F%E7%90%86.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>深入理解浏览器运行原理</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><!--]--></div></section></div><div class="group" data-v-eec6a639><section class="VPSidebarItem level-0 collapsible has-active" data-v-eec6a639 data-v-66b47b62><div class="item" role="button" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link" data-v-66b47b62 data-v-8dd200cc><!--[--><h2 class="text" data-v-66b47b62>学习笔记</h2><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-66b47b62><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-66b47b62><!--[--><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/note/JavaScript.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>JavaScript基础</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/note/CSS.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>CSS基础</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/note/JavaScriptEnhanced.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>JavaScript进阶</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/note/Front-end%20Engineering.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>前端工程化</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><div class="VPSidebarItem level-1 is-link is-active has-active" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/note/SSR.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>服务端渲染</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><!--]--></div></section></div><!--]--><!--[--><!--]--></nav></aside><div class="VPContent has-sidebar" id="VPContent" data-v-3af881ed data-v-e31feb0e><div class="VPDoc has-sidebar has-aside" data-v-e31feb0e data-v-30dabfe4><div class="container" data-v-30dabfe4><div class="aside" data-v-30dabfe4><div class="aside-curtain" data-v-30dabfe4></div><div class="aside-container" data-v-30dabfe4><div class="aside-content" data-v-30dabfe4><div class="VPDocAside" data-v-30dabfe4 data-v-7110f5c9><!--[--><!--]--><!--[--><!--]--><div class="VPDocAsideOutline" data-v-7110f5c9 data-v-9c6f1a55><div class="content" data-v-9c6f1a55><div class="outline-marker" data-v-9c6f1a55></div><div class="outline-title" data-v-9c6f1a55>On this page</div><nav aria-labelledby="doc-outline-aria-label" data-v-9c6f1a55><span class="visually-hidden" id="doc-outline-aria-label" data-v-9c6f1a55> Table of Contents for current page </span><ul class="root" data-v-9c6f1a55 data-v-02afc12d><!--[--><!--]--></ul></nav></div></div><!--[--><!--]--><div class="spacer" data-v-7110f5c9></div><!--[--><!--]--><!----><!--[--><!--]--><!--[--><!--]--></div></div></div></div><div class="content" data-v-30dabfe4><div class="content-container" data-v-30dabfe4><!--[--><!--]--><main class="main" data-v-30dabfe4><div style="position:relative;" class="vp-doc _note_SSR" data-v-30dabfe4><div><h1 id="服务端渲染-ssr" tabindex="-1">服务端渲染(SSR) <a class="header-anchor" href="#服务端渲染-ssr" aria-hidden="true">#</a></h1><ul><li>邂逅SPA和SSR</li><li>Node服务搭建</li><li>Vue3 + SSR搭建</li><li>SSR + Hydration 水合</li><li>Vue SSR + Router</li><li>Vue SSR + Pinia</li></ul><h2 id="邂逅spa和ssr" tabindex="-1">邂逅SPA和SSR <a class="header-anchor" href="#邂逅spa和ssr" aria-hidden="true">#</a></h2><p>我们使用Vue开发的网页一般都是单页面应用程序SPA Single Page Application</p><ul><li>SPA应用是在客户端呈现的我们称这个渲染过程为CSRClient Side Rendering</li><li>常见的B端Web应用开发模式<strong>渲染工作在客户端进行,服务器压力较轻</strong>,服务器直接返回未经加工的<code>.html</code>文件</li><li>所需要的资源HTML CSS JS等在一次请求中就加载完成首屏时间更长需要额外的首屏优化</li></ul><p>与之相对的就是服务端渲染SSR Server Side Rendering</p><ul><li>SSR并不是什么新鲜的概念早期的JSP或PHP就已经体现了服务端渲染的原理</li><li>但是传统开发模式,代码耦合度较高,不容易维护</li></ul><p>于是同构SSR应运而生我们称之为BFFBackend for Frontend 服务于前端的后端)</p><ul><li>前后端一体化一套Vue / React代码在服务器上运行一遍在到达浏览器又运行一遍。</li><li>前后端都参与到渲染中并且首次渲染出的HTML相同</li></ul><p>浏览器请求<code>.html</code>文件 =&gt; 服务端运行Vue / React代码并生成<code>.html</code> =&gt; 发送<code>.html</code>文件给浏览器 =&gt; 浏览器显示网页内容</p><p>=&gt; 浏览器加载JS文件 =&gt; 绑定DOM事件 客户端渲染接管界面 =&gt; 再次跳转路由就是客户端渲染 无需请求后台</p><h3 id="spa的优点与缺点" tabindex="-1">SPA的优点与缺点 <a class="header-anchor" href="#spa的优点与缺点" aria-hidden="true">#</a></h3><ul><li>SPA的优点 <ul><li>只需要加载一次 更好的用户体验 <ul><li>只有一个<code>.html</code>文件页面切换不需要重新加载所以比传统Web应用程序更快</li></ul></li><li>轻松构建功能丰富的Web应用程序</li></ul></li><li>SPA的缺点 <ul><li>SPA应用默认只返回一个空HTML文件不利于SEO</li><li>首屏加载资源过大,影响首屏渲染速度</li><li>不利于复杂项目构建</li></ul></li></ul><h3 id="seo优化" tabindex="-1">SEO优化 <a class="header-anchor" href="#seo优化" aria-hidden="true">#</a></h3><ul><li>语义性HTML标记 <ul><li>标题用 <code>h1</code>,一个页面只应当由一个 <code>h1</code> 标签,副标题用 <code>h2 - h6</code></li><li>不要过度使用 <code>h</code> 标签多次使用不会增加SEO</li><li>段落用 <code>p</code> 标签 列表用 <code>ul</code> 标签,且 <code>li</code> 只放在 <code>ul</code></li></ul></li><li>每个页面都需要包含标题+内部链接 <ul><li>每个页面对应的title同一个网站所有页面都有内链可以指向首页</li></ul></li><li>保证链接可供抓取 <ul><li><code>&lt;a href=&quot;https://www.example.com&quot; /&gt;</code></li><li><code>&lt;a href=&quot;/relative/path/file&quot; /&gt;</code></li></ul></li><li>meta标签优化设置description和keywords等</li><li>文本标记和img <ul><li>比如<code>&lt;b&gt;</code><code>&lt;strong&gt;</code>加粗文本的标签,爬虫会关注到该内容</li><li><code>img</code>标签添加<code>alt</code>属性,图片加载失败时供爬虫读取<code>alt</code>内容</li></ul></li><li>robots.txt 文件,规定爬虫可以访问网址上的哪些页面</li><li>sitemap.xml 站点地图,在站点地图列出所有网页,确保爬虫不会漏掉某些网页</li></ul><h2 id="服务端渲染-ssr-1" tabindex="-1">服务端渲染 SSR <a class="header-anchor" href="#服务端渲染-ssr-1" aria-hidden="true">#</a></h2><p>服务端渲染 SSR Server Side Rendering</p><ul><li>页面是在服务端渲染的用户每请求一个SSR页面都会先在服务端渲染</li><li>服务端渲染完成后返回给浏览器呈现浏览器发现JS脚本解析脚本向服务器发起请求之后网页就可以交互了 <ul><li><code>app = createSSRApp(App)</code> <code>renderToString(app) =&gt; App String Html</code></li><li><code>client_bundle.js</code> 客户端通过脚本激活应用程序 让应用程序可以进行交互,这个过程叫水合( Hydration</li></ul></li><li>Vue Nuxt / React Next.jsSSR应用也称为同构应用server_bundle.js &amp; client_bundle.js</li></ul><h3 id="ssr的优点" tabindex="-1">SSR的优点 <a class="header-anchor" href="#ssr的优点" aria-hidden="true">#</a></h3><ul><li>更快的首屏渲染速度 <ul><li>浏览器显示静态页面的内容要比JavaScript动态生成的内容快得多</li><li>用户访问首页时立刻返回静态页面内容而不需要等待浏览器先加载完整个SPA应用的JS代码</li></ul></li><li>更好的SEO <ul><li>爬虫擅长爬取HTML页面服务端直接返回一个静态的HTML给浏览器</li><li>有利于爬虫快速爬取网页内容并编入索引有利于SEO</li></ul></li><li>SSR 应用程序在 Hydration 之后仍然可以保留Web应用程序的可交互性 <ul><li>前端路由、响应式数据、虚拟DOM等</li></ul></li></ul><h3 id="ssr的缺点" tabindex="-1">SSR的缺点 <a class="header-anchor" href="#ssr的缺点" aria-hidden="true">#</a></h3><ul><li>SSR 通过需要对服务器进行更多的API调用在服务端渲染需要消耗更多的服务器资源成本较高</li><li>100个人访问这个网站服务器就要为每个人渲染100次</li><li>增加了一定的开发成本,开发者需要关心哪些代码是运行在服务端的,哪些则是运行在浏览器的</li><li>SSR配置站点的缓存通常会比SPA站点要更复杂</li></ul><h3 id="ssr-解决方案" tabindex="-1">SSR 解决方案 <a class="header-anchor" href="#ssr-解决方案" aria-hidden="true">#</a></h3><ul><li>传统方案PHP JSP ...</li><li>从0开始搭建SSR项目Node+Webpack+Vue/React</li><li>选用现成的框架 <ul><li>React Next.js</li><li>Vue3 + Nuxt3 || Vue2 + Nuxt.js</li></ul></li></ul><h2 id="静态网站生成-ssg" tabindex="-1">静态网站生成 SSG <a class="header-anchor" href="#静态网站生成-ssg" aria-hidden="true">#</a></h2><p>静态网页生成 SSGStatic Site Generate</p><ul><li>SSG应用在构建阶段就确定了<code>.html</code>页面的内容</li><li>用户访问网站,服务器直接返回<code>.html</code>文件给客户端,相当于一个静态资源</li><li>优点 <ul><li>直接返回静态的<code>html</code>文件有利于SEO</li><li>相比于SSR不需要每次请求都由服务端处理所以可以大幅减轻服务端压力也可以将文件放到CDN上优化访问速度</li><li>保留了SPA应用的特性比如前端路由、响应式数据、虚拟DOM等</li></ul></li><li>缺点 <ul><li>如果网站的内容需要更新,那么需要重新构建与部署</li><li>只能生成偏静态的页面,不利于与用户的交互,所有用户获取到的页面都是相同的</li></ul></li><li>哪些应用场景:文档站、个人博客、新闻站点等</li></ul><h3 id="ssr与ssg的优势" tabindex="-1">SSR与SSG的优势 <a class="header-anchor" href="#ssr与ssg的优势" aria-hidden="true">#</a></h3><ul><li>更短的首屏时间 <ul><li>只需要请求一个HTML文件就能展示出页面</li><li>虽然在服务端仍然需要调取相关接口,但是服务器-服务器之间的通信远比客户端快,有时甚至是同一台服务器的本地接口</li><li>不再需要大量的js文件请求这就使得SSR/SSG可以拥有更短的首屏时间</li></ul></li></ul><h3 id="跨请求状态污染" tabindex="-1">跨请求状态污染 <a class="header-anchor" href="#跨请求状态污染" aria-hidden="true">#</a></h3><ul><li><p>在SPA中整个生命周期只有一个App对象实例/一个Router对象实例/一个Store对象实例</p><ul><li>因为每个用户使用SPA时各自的渲染进程都是在自己的浏览器上独立进行的这是一种<strong>单例模式</strong></li></ul></li><li><p>然而在SSR的环境下App模块通常只在</p><p>服务器启动时</p><p>初始化一次,同一个应用模块会在多个服务器请求之间被复用</p><ul><li>单例状态对象也会在多个请求之间被复用:</li><li>某个用户对共享的单例状态进行修改,那么这个状态可能会意外地泄露给另一位正在请求的用户</li><li>我们将这种情况称为:<strong>跨请求状态污染</strong></li></ul></li><li><p>为了避免这种跨请求状态污染SSR的解决方案是</p><ul><li>在每个请求中,为整个应用创建一个<strong>全新的实例</strong>包括后面的Router和Store等实例</li><li>带来的缺点就是:需要消耗更多的服务器资源</li></ul></li></ul><h2 id="nuxt3-系统学习" tabindex="-1">Nuxt3 系统学习 <a class="header-anchor" href="#nuxt3-系统学习" aria-hidden="true">#</a></h2><ul><li>邂逅Nuxt3</li><li>Nuxt3 初体验</li><li>Nuxt3 全局配置</li><li>Nuxt3 内置组件</li><li>Nuxt3 样式和资源</li><li>Nuxt3 页面和导航</li><li>Nuxt3 动态路由</li></ul><h3 id="认识nuxt3" tabindex="-1">认识Nuxt3 <a class="header-anchor" href="#认识nuxt3" aria-hidden="true">#</a></h3><ul><li>支持数据双向绑定和组件化Vue.js</li><li>处理客户端导航Vue Router</li><li>支持开发中热模块替换、生产环境代码打包Webpack5 Vite</li><li>兼容旧版浏览器支持ES6+语法转译ESBuild</li><li>支持开发环境服务器,支持服务端渲染/API接口转发</li><li>使用<code>h3</code>实现部署<strong>可移植性</strong><code>h3</code>是一个极小的高性能http框架 <ul><li>支持在Serverless、Worker、Node.js环境中运行</li></ul></li></ul><h3 id="搭建nuxt3环境" tabindex="-1">搭建Nuxt3环境 <a class="header-anchor" href="#搭建nuxt3环境" aria-hidden="true">#</a></h3><p>使用命令行工具 <code>Nuxi</code> 初始化Nuxt</p><ul><li><code>npx nuxi init project-name</code></li><li><code>pnpm dlx nuxi init project-name</code></li><li><code>npm install -g nuxi &amp;&amp; nuxi init project-name</code></li></ul><p>解读脚手架创建的初始化项目的<code>package.json</code>中的脚本:</p><div class="language-json line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">json</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C792EA;">private</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">true,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C792EA;">scripts</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#FFCB6B;">build</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">nuxt build</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#FFCB6B;">dev</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">nuxt dev</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#FFCB6B;">generate</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">nuxt generate</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#FFCB6B;">preview</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">nuxt preview</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#FFCB6B;">postinstall</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">nuxt prepare</span><span style="color:#89DDFF;">&quot;</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">},</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C792EA;">devDependencies</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#FFCB6B;">nuxt</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">^3.2.0</span><span style="color:#89DDFF;">&quot;</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br></div></div><ul><li><code>build</code> 构建正式版本,将被输出到<code>.output</code>文件夹</li><li><code>dev</code> 开发环境</li><li><code>generate</code> 打包正式版本项目,但是会预渲染每个路由(<code>nuxt build --prerender</code></li><li><code>preview</code> 对打包项目启动本地预览服务器</li><li><code>postinstall</code> 该脚本为NPM的生命周期函数将在<code>npm install</code>后执行</li></ul><p>针对<code>postinstall</code>中执行的<code>nuxi prepare</code>脚本,官方文档有如下解释:</p><blockquote><p>The <code>prepare</code> command creates a <code>.nuxt</code> directory in your application and generates types. This can be useful in a CI environment or as a <code>postinstall</code> command in your <code>package.json</code>.</p></blockquote><p>执行该脚本后,将在项目根目录创建<code>.nuxt</code>文件夹</p><ul><li>这个文件夹将作为默认构建输出的文件夹</li><li>其中的文件都以<code>.d.ts</code>结尾是Nuxt的TS类型声明</li></ul><h3 id="配置-configuration" tabindex="-1">配置 Configuration <a class="header-anchor" href="#配置-configuration" aria-hidden="true">#</a></h3><ul><li>通过 <code>nuxt.config.ts</code> 文件对Nuxt进行自定义配置</li><li><code>runtimeConfig</code> 运行时配置 即定义<strong>环境变量</strong><ul><li>直接定义在 <code>runtimeConfig</code> 中的值,仅在服务端可以访问到 <ul><li>定义在<code>runtimeConfig.public</code>中的变量,在客户端和服务端中都能读取到</li><li>也可以将环境变量定义在<code>.env</code>文件中,优先级<code>.env &gt; runtimeConfig</code><ul><li><code>NUXT_</code>开头的会作为私有环境变量读取到运行时</li><li><code>NUXT_PUBLIC_</code>开头的会作为公共变量读取到运行时</li></ul></li></ul></li><li><code>appConfig</code> 应用配置,定义在<strong>构建时</strong>确定的公共变量,如 theme <ul><li>配置会和app.config.ts合并优先级<code>app.config.ts &gt; appConfig</code></li></ul></li><li><code>app</code> app的配置</li><li><code>head</code> 给每个页面设置head信息也支持useHead配置和内置组件 <ul><li>在这个配置中定义的标签会注入到所有页面的head标签中</li><li>也可以在某些页面动态插入head标签内容 使用<code>useHead</code>函数</li><li>或者在template中使用Nuxt的内置组件<code>Head</code></li></ul></li><li><code>ssr</code> 指定应用渲染模式 <ul><li>默认值为true 即采用SSR方式渲染应用</li><li>如果指定了<code>ssr: false</code> 则会采用SPA的方式渲染应用即客户端渲染</li></ul></li><li><code>router</code> 配置路由相关的信息比如在客户端渲染可以配置hash路由 <ul><li>需要注意的是SSR并不支持哈希路由</li><li><code>router: { options: { hashMode: false } }</code></li></ul></li><li><code>alias</code> 路径别名 <ul><li>默认已经为我们配置好了一些别名,详情可以参阅文档</li></ul></li><li><code>modules</code> 配置Nuxt扩展的模块比如<code>@pinia/nuxt</code> <code>@nuxt/image</code></li><li><code>routeRules</code> 定义路由规则,可以更改路由的渲染模式或分配基于路由缓存策略</li><li><code>builder</code> 指定使用Vite还是Webpack来构建应用默认是Vite如切换为Webpack还需要安装额外依赖</li></ul></li></ul><h4 id="runtimeconfig-与-appconfig" tabindex="-1">runtimeConfig 与 appConfig <a class="header-anchor" href="#runtimeconfig-与-appconfig" aria-hidden="true">#</a></h4><ul><li><code>runtimeConfig</code>: 定义<strong>环境变量</strong>,比如:<strong>运行时</strong>需要指定的私有/公共的token等</li><li><code>appConfig</code>: 定义<strong>公共变量</strong>,比如:<strong>构建时</strong>确定的公共token、网站配置等</li></ul><p>针对他们的比较,官方文档提供了一个表格可以参阅:</p><table><thead><tr><th>Feature</th><th>runtimeConfig</th><th>app.config</th></tr></thead><tbody><tr><td>Client Side</td><td>Hydrated</td><td>Bundled</td></tr><tr><td>Environment Variables</td><td>✅ Yes</td><td>❌ No</td></tr><tr><td>Reactive</td><td>✅ Yes</td><td>✅ Yes</td></tr><tr><td>Types support</td><td>✅ Partial</td><td>✅ Yes</td></tr><tr><td>Configuration per Request</td><td>❌ No</td><td>✅ Yes</td></tr><tr><td>Hot Module Replacement</td><td>❌ No</td><td>✅ Yes</td></tr><tr><td>Non primitive JS types</td><td>❌ No</td><td>✅ Yes</td></tr></tbody></table><p><a href="https://nuxt.com/docs/getting-started/configuration#runtimeconfig-vs-appconfig" target="_blank" rel="noreferrer">runtimeconfig-vs-appconfig</a></p><h4 id="区分client和server环境" tabindex="-1">区分Client和Server环境 <a class="header-anchor" href="#区分client和server环境" aria-hidden="true">#</a></h4><p>Nuxt为我们扩展了Node的process对象并为我们在浏览器环境提供了process对象</p><ul><li>Nuxt会在服务端的process对象中注入属性<code>dev</code> <code>server</code> <code>client</code>以供使用</li><li>也会在浏览器网页中注入process对象包含上述的三个属性</li><li>也可以手动判断<code>typeof window === &#39;object&#39;</code>检查是服务器环境/浏览器环境</li></ul><h3 id="页面与组件-view-and-component" tabindex="-1">页面与组件 View and Component <a class="header-anchor" href="#页面与组件-view-and-component" aria-hidden="true">#</a></h3><p>Nuxt会自动为我们注册组件、注册页面路由<em>约定&gt;规范</em></p><ul><li>位于<code>pages/</code>下的页面都会被注册路由 <ul><li>路由使用内置组件NuxtPage占位相当于router-view</li><li>相对应的可以使用NuxtLink执行跳转相当于router-link</li><li>因为底层是vue-router所以动态路由、嵌套路由都是支持的</li></ul></li><li>位于<code>components/</code>下的组件都会被自动全局注册</li></ul><h4 id="nuxt3-内置组件" tabindex="-1">Nuxt3 内置组件 <a class="header-anchor" href="#nuxt3-内置组件" aria-hidden="true">#</a></h4><p>Nuxt3 框架提供了一些内置的组件,常用的如下:</p><ul><li>SEO组件Html Body Head Title Meta Style Link NoScript Base <ul><li>这些组件的作用是向页面中不同部分插入标签在SSR的过程中渲染出来并返回给客户端</li><li>这样爬虫就会在同步获取页面数据时获取到这些标签</li></ul></li><li>NuxtPage是Nuxt自带的页面占位组件 <ul><li>需要显示位于目录中的顶级或嵌套页面<code>pages/</code></li><li><strong>是对 router-view 的封装</strong></li></ul></li><li>ClientOnly该组件包裹的内容只会在客户端渲染 <ul><li>其中内容不会出现在服务端返回的<code>.html</code>文件中</li><li>会在客户端通过JS脚本动态渲染出来 <ul><li>类似于Vue3新增的内置组件Suspence</li><li>可以为其传入具名插槽#fallback展示组件被渲染前的加载中状态</li></ul></li></ul></li><li>ServerOnly该组件包裹的内容只会在服务端渲染</li></ul></div></div></main><!--[--><!--]--><footer class="VPDocFooter" data-v-30dabfe4 data-v-cc0f9778><div class="edit-info" data-v-cc0f9778><div class="edit-link" data-v-cc0f9778><a class="VPLink link edit-link-button" href="https://github.com/ZiuChen/ZiuChen.github.io/edit/main/docs/note/SSR.md" target="_blank" rel="noreferrer" data-v-cc0f9778 data-v-8dd200cc><!--[--><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" class="edit-link-icon" data-v-cc0f9778><path d="M18,23H4c-1.7,0-3-1.3-3-3V6c0-1.7,1.3-3,3-3h7c0.6,0,1,0.4,1,1s-0.4,1-1,1H4C3.4,5,3,5.4,3,6v14c0,0.6,0.4,1,1,1h14c0.6,0,1-0.4,1-1v-7c0-0.6,0.4-1,1-1s1,0.4,1,1v7C21,21.7,19.7,23,18,23z"></path><path d="M8,17c-0.3,0-0.5-0.1-0.7-0.3C7,16.5,6.9,16.1,7,15.8l1-4c0-0.2,0.1-0.3,0.3-0.5l9.5-9.5c1.2-1.2,3.2-1.2,4.4,0c1.2,1.2,1.2,3.2,0,4.4l-9.5,9.5c-0.1,0.1-0.3,0.2-0.5,0.3l-4,1C8.2,17,8.1,17,8,17zM9.9,12.5l-0.5,2.1l2.1-0.5l9.3-9.3c0.4-0.4,0.4-1.1,0-1.6c-0.4-0.4-1.2-0.4-1.6,0l0,0L9.9,12.5z M18.5,2.5L18.5,2.5L18.5,2.5z"></path></svg> Edit this page on GitHub<!--]--><!----></a></div><div class="last-updated" data-v-cc0f9778><p class="VPLastUpdated" data-v-cc0f9778 data-v-de6a4e1f>Updated Date: <time datetime="2023-02-15T13:53:37.000Z" data-v-de6a4e1f></time></p></div></div><div class="prev-next" data-v-cc0f9778><div class="pager" data-v-cc0f9778><a class="pager-link prev" href="/note/Front-end%20Engineering.html" data-v-cc0f9778><span class="desc" data-v-cc0f9778>Previous page</span><span class="title" data-v-cc0f9778>前端工程化</span></a></div><div class="has-prev pager" data-v-cc0f9778><!----></div></div></footer><!--[--><!--]--></div></div></div></div></div><footer class="VPFooter has-sidebar" data-v-3af881ed data-v-8b655284><div class="container" data-v-8b655284><p class="message" data-v-8b655284>Released under the MIT License.</p><p class="copyright" data-v-8b655284>Copyright © 2019-present Ziu Chen</p></div></footer><!--[--><!--]--></div></div>
<script>__VP_HASH_MAP__ = JSON.parse("{\"article_深入vue3源码看看vue.use后究竟发生了什么.md\":\"55a883c8\",\"article_一文读懂伪类与伪元素.md\":\"eff1b557\",\"article_彻底搞懂对象的数据属性描述符、存储属性描述符.md\":\"d8143a19\",\"article_从0实现一个年度报告.md\":\"2fe79340\",\"article_一文读懂函数中this指向问题.md\":\"231015d6\",\"article_【2023】青训营 - 前端练习题汇总解析.md\":\"4eb34c9d\",\"article_一文读懂事件冒泡与事件捕获.md\":\"1c409bb8\",\"article_深入理解proxy与reflect.md\":\"ed1492ff\",\"index.md\":\"c9a62842\",\"article_深入理解浏览器运行原理.md\":\"68a5a9e3\",\"article_深入理解浏览器缓存机制.md\":\"ffa7c337\",\"note_javascript.md\":\"c3b70a43\",\"note_front-end engineering.md\":\"9c830697\",\"note_css.md\":\"02e58778\",\"project_smartwordbreak_index.md\":\"3f252c44\",\"project_smartwordbreak_log_index.md\":\"aa668ca0\",\"project_smartwordbreak_statement_index.md\":\"a6c8991d\",\"works_contribution.md\":\"2de3214c\",\"self_index.md\":\"61d9fe32\",\"works_opensource.md\":\"4873ace6\",\"project_clipboardmanager_guide_index.md\":\"5d1aeccd\",\"project_clipboardmanager_statement_index.md\":\"266e3976\",\"project_clipboardmanager_index.md\":\"b1dec137\",\"note_ssr.md\":\"5e6cefdd\",\"project_clipboardmanager_vip_index.md\":\"64066399\",\"project_clipboardmanager_log_index.md\":\"e647084b\",\"note_javascriptenhanced.md\":\"30fbee05\"}")</script>
<script type="module" async src="/assets/app.6cf9e426.js"></script>
</body>
</html>