当前位置: 首页 > news >正文

扬中网站推广托管毕设做网站需要发布到浏览器吗

扬中网站推广托管,毕设做网站需要发布到浏览器吗,网站制作与发布,制作网站的知识SSR和CSR 首先#xff0c;我们先要了解什么是SSR和CSR#xff0c;SSR是服务端渲染#xff0c;CSR是客户端渲染#xff0c;服务端渲染是指 HTTP 服务器直接根据用户的请求#xff0c;获取数据#xff0c;生成完整的 HTML 页面返回给客户端#xff08;浏览器#xff09;展…SSR和CSR 首先我们先要了解什么是SSR和CSRSSR是服务端渲染CSR是客户端渲染服务端渲染是指 HTTP 服务器直接根据用户的请求获取数据生成完整的 HTML 页面返回给客户端浏览器展现。相对地HTTP 服务器根据用户请求返回对应的 JSON 数据在 HTML 页面中通过 JavaScript 来生成最终用户看到的页面叫做客户端渲染。比如现在非常流行的 Vue 和 React 框架就是客户端渲染的一个应用。在非常早期的 Web 技术中大家还是使用 JSP这种古老的模板语法来编写前端的页面然后直接将 JSP 文件放到服务端在服务端填入数据并渲染出完整的页面内容可以说那个时代的做法是天然的服务端渲染。但是随着Web2.0的到来。Web应用变得复杂了起来相比于服务端渲染要发送完整页面客户端渲染每次只需要请求页面上需要更新的数据网络传输数据量小能够显著减轻服务器压力。而且客户端渲染真正实现了前后端职责分离后端只需关注数据逻辑由前端的 JS 去完成这种开发模式更加灵活效率也更高。因此客户端渲染渐渐成为了主流。 但客户端渲染也存在着一定的问题例如首屏加载比较慢、对 SEO 不太友好因此 SSR即服务端渲染技术应运而生它在保留 CSR 技术栈的同时也能解决 CSR 的各种问题。在某些特定的情况下采用服务端渲染要比客户端渲染有优势所以服务端渲染又逐渐回归人们的视野成为了特定场景下的一种选择。当然SSR 中只能生成页面的内容和结构并不能完成事件绑定因此需要在浏览器中执行 CSR 的 JS 脚本完成事件绑定让页面拥有交互的能力这个过程被称作hydrate(翻译为注水或者激活)。同时像这样服务端渲染 客户端 hydrate 的应用也被称为同构应用。 这里附上CSR和SSR的简易流程图 看到这里相信大家应该对SSR和CSR的区别有所了解了接下来我们就自己动手搭建React和Vue的SSR环境我们分别使用webpack和vite来搭建。 实战环节 使用vite打造React的SSR环境 搭建项目骨架 首先我们先使用vite初始化一个React的项目,我们这里包管理工具使用pnpm如果没有下载pnpm,先在命令行执行npm install pnpm -g然后我们执行pnpm create vite,输入我们的项目名然后选择React和ts进行开发进入项目根目录执行pnpm i安装依赖。 然后我们进入tsconfig.json里把esModuleInterop的值改为true让我们在项目里可以支持import path from path这种写法’: {compilerOptions: {target: ESNext,useDefineForClassFields: true,lib: [DOM, DOM.Iterable, ESNext],allowJs: false,skipLibCheck: true,// 可以支持import path from path的写法esModuleInterop: true,allowSyntheticDefaultImports: true,strict: true,forceConsistentCasingInFileNames: true,module: ESNext,moduleResolution: Node,resolveJsonModule: true,isolatedModules: true,noEmit: true,jsx: react-jsx},include: [src],references: [{ path: ./tsconfig.node.json }] } 删除项目自带的src/main.ts然后在 src 目录下新建entry-client.tsx和entry-server.tsx两个入口文件: entry-client.ts // 客户端入口文件 import React from react import ReactDOM from react-dom/client import App from ./App import ./index.cssReactDOM.hydrateRoot(document.getElementById(root)!,React.StrictModeApp data{data} //React.StrictMode ) entry-server.ts // 导出 SSR 组件入口 import App from ./App import ./index.cssfunction ServerEntry(props: any) {return App data{props.data} / }export { ServerEntry } 我们以 Express 框架为例来实现 Node 后端服务后续的 SSR 逻辑会接入到这个服务中。当然我们需要安装以下的依赖: pnpm i express -S pnpm i types/express -D 接着新建src/ssr-server/index.ts: // 后端服务 import express from express;async function createServer() {const app express();app.listen(3000, () {console.log(Node 服务器已启动~)console.log(http://localhost:3000);}); }createServer(); SSR运行时的实现 SSR 作为一种特殊的后端服务我们可以将其封装成一个中间件的形式如以下的代码所示: src/ssr-server/index.ts import express, { RequestHandler, Express } from express import { ViteDevServer } from viteconst isProd process.env.NODE_ENV production const cwd process.cwd()async function createSsrMiddleware(app: Express): PromiseRequestHandler {let vite: ViteDevServer | null nullif (!isProd) {vite await (await import(vite)).createServer({root: process.cwd(),server: {middlewareMode: ssr,},})// 注册 Vite Middlewares// 主要用来处理客户端资源app.use(vite.middlewares)}return async (req, res, next) {// SSR 的逻辑// 1. 加载服务端入口模块// 2. 数据预取// 3. 「核心」渲染组件 - 字符串// 4. 拼接 HTML返回客户端} }async function createServer() {const app express()// 加入 Vite SSR 中间件app.use(await createSsrMiddleware(app))app.listen(3000, () {console.log(Node 服务器已启动~)console.log(http://localhost:3000)}) }createServer() Ok,那接下来我们来实现中间件内SSR的逻辑实现首先实现第一步即加载服务端入口模块: 我们将它抽离到src/server/utils.ts里: src/server/utils.ts import { ViteDevServer } from vite import path from pathexport const isProd process.env.NODE_ENV production export const cwd process.cwd()async function loadSsrEntryModule(vite: ViteDevServer | null) {// 生产模式下直接 require 打包后的产物if (isProd) {const entryPath path.join(cwd, dist/server/entry-server.js);return require(entryPath);} // 开发环境下通过 no-bundle 方式加载else {const entryPath path.join(cwd, src/entry-server.tsx);return vite!.ssrLoadModule(entryPath);} } 我们补充一下中间件的逻辑 async function createSsrMiddleware(app: Express): PromiseRequestHandler {// 省略前面的代码return async (req, res, next) {const url req.originalUrl;// 1. 服务端入口加载const { ServerEntry } await loadSsrEntryModule(vite);// ...} } 接下来我们来实现服务端的数据预取操作你可以在entry-server.tsx中添加一个简单的获取数据的函数: export async function fetchData() {return { user: pujie } } 然后在 SSR 中间件中完成数据预取的操作: src/ssr-server/index.ts async function createSsrMiddleware(app: Express): PromiseRequestHandler {// 省略前面的代码return async (req, res, next) {const url req.originalUrl;// 1. 服务端入口加载const { ServerEntry, fetchData } await loadSsrEntryModule(vite);// 2. 预取数据const data await fetchData();} } 接着我们进入到核心的组件渲染阶段: src/ssr-server/index.ts import { renderToString } from react-dom/server; import React from react;async function createSsrMiddleware(app: Express): PromiseRequestHandler {// 省略前面的代码return async (req, res, next) {const url req.originalUrl;// 1. 服务端入口加载const { ServerEntry, fetchData } await loadSsrEntryModule(vite);// 2. 预取数据const data await fetchData();// 3. 组件渲染 - 字符串const appHtml renderToString(React.createElement(ServerEntry, { data }));} } 我们在第一步之后我们拿到了入口组件现在可以调用React的renderToStringAPI 将组件渲染为字符串组件的具体内容便就此生成了。 OK目前我们已经拿到了组件的 HTML 以及预取的数据接下来我们在根目录下的 HTML 中提供相应的插槽方便内容的替换: index.html !DOCTYPE html html langenheadmeta charsetUTF-8 /link relicon typeimage/svgxml href/src/favicon.svg /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleVite App/title/headbodydiv idroot!-- SSR_APP --/divscript typemodule src/src/entry-client.tsx/script!-- SSR_DATA --/body /html OK然后我们拿到html文件后我们要将插槽占位的内容换成对应的内容,然后将html返回给客户端: src/ssr-server/index.ts async function createSsrMiddleware(app: Express): PromiseRequestHandler {// 省略之前的代码return async (req, res, next) {const url req.originalUrl;// 省略前面的步骤// 4. 拼接完整 HTML 字符串返回客户端const templatePath resolveTemplatePath();let template await fs.readFileSync(templatePath, utf-8);// 开发模式下需要注入 HMR、环境变量相关的代码因此需要调用 vite.transformIndexHtmlif (!isProd vite) {template await vite.transformIndexHtml(url, template);}const html template.replace(!-- SSR_APP --, appHtml)// 注入数据标签用于客户端 客户端进行注水接管浏览器事件.replace(!-- SSR_DATA --,scriptwindow.__SSR_DATA__${JSON.stringify(data)}/script);res.status(200).setHeader(Content-Type, text/html).end(html);} } 补充工具函数: src/ssr-server/utils.ts export function resolveTemplatePath() {return isProd? path.join(cwd, dist/client/index.html): path.join(cwd, index.html) } 在拼接 HTML 的逻辑中除了添加页面的具体内容同时我们也注入了一个挂载全局数据的script标签这是用来干什么的呢 在 SSR 的基本概念中我们就提到过为了激活页面的交互功能我们需要执行 CSR 的 JavaScript 代码来进行 hydrate 操作而客户端 hydrate 的时候需要和服务端同步预取后的数据保证页面渲染的结果和服务端渲染一致因此我们刚刚注入的数据 script 标签便派上用场了。由于全局的 window 上挂载服务端预取的数据我们可以在entry-client.tsx也就是客户端渲染入口中拿到这份数据并进行 hydrate如果我们要做全局状态管理也是这个思路。 entry-client.tsx import React from react import ReactDOM from react-dom/client import App from ./App import { fetchData } from ./entry-server import ./index.css// 跳过ts类型检测 // ts-ignore const data window.__SSR_DATA__ ?? fetchData() // 如果服务端获取数据失败我们要做客户端降级在客户端获取数据ReactDOM.hydrateRoot(document.getElementById(root)!,React.StrictModeApp data{data} //React.StrictMode ) 我们在这里还需要处理生产环境下静态资源的处理这里我们可以通过serve-static中间件来完成这个服务 async function createSsrMiddleware(app: Express): PromiseRequestHandler {return async (req, res, next) {try {const url req.originalUrl;if (!matchPageUrl(url)) {// 走静态资源的处理return await next();}// SSR 的逻辑省略} catch(e: any) {vite?.ssrFixStacktrace(e);console.error(e);res.status(500).end(e.message);}} }async function createServer() {const app express();// 加入 Vite SSR 中间件app.use(await createSsrMiddleware(app));// 注册中间件生产环境端处理客户端资源if (isProd) {app.use(serve(path.join(cwd, dist/client)))}// 省略其它代码 } 我们还需要补充matchPageUrl这个工具函数 src/ssr-server/utils.ts export function matchPageUrl(url: string) {if (url /) {return true} } 这样一来我们就解决了生产环境下静态资源失效的问题。不过一般情况下我们会将静态资源部上传到 CDN 上并且将 Vite 的 base 配置为域名前缀这样我们可以通过 CDN 直接访问到静态资源而不需要加上服务端的处理。 自定义head 在 SSR 的过程中我们虽然可以在决定组件的内容即div idroot/div这个容器 div 中的内容但对于 HTML 中head的内容我们无法根据组件的内部状态来决定比如对于一个直播间的页面我们需要在服务端渲染出 title 标签title 的内容是不同主播的直播间名称不能在代码中写死这种情况怎么办React其实有一个库叫react-helmet可以帮我们完成这个需求,我们下载这个库 Ok,我们编写一下App.tsx的内容 import logo from ./assets/react.svg import ./App.css import { Helmet } from react-helmetexport interface AppProps {data: any }function App(props: AppProps) {const { data } props// ts-ignorereturn (div classNameAppHelmettitle{data.user}的页面/titlelink relcanonical hrefhttp://mysite.com/example //Helmetheader classNameApp-headerimg src{logo} classNameApp-logo altlogo /pHello Vite Reactimg srchttps://reactjs.orgtarget_blankrelnoopener noreferrerLearn React/a{ | }aclassNameApp-linkhrefhttps://vitejs.dev/guide/features.htmltarget_blankrelnoopener noreferrerVite Docs/a/p/header/div stylemargin: auto / }export default App OK,最后我们在package.json里添加一些脚本 scripts: {// 开发阶段启动 SSR 的后端服务dev: nodemon --watch src/ssr-server/index.ts --exec esno src/ssr-server/index.ts,// 打包客户端产物和 SSR 产物build: npm run build:client npm run build:server,build:client: vite build --outDir dist/client --ssrManifest --manifest,build:server: vite build --ssr src/entry-server.tsx --outDir dist/server,// 生产环境预览 SSR 效果preview: set NODE_ENVproduction esno src/ssr-server/index.ts}, nodemon大家应该比较熟悉esno是用来执行ts文件的,类似ts-node,OK,我们安装一下依赖 pnpm i esno nodemon -D 然后我们试一下开发环境怎么样执行pnpm dev,可以看到如下页面 OK我们再试一下生产环境执行pnpm build然后执行pnpm preview,看到的页面应该和开发环境一样的那我们React简易的SSR环境就搭建完成了 使用webpack打造Vue的SSR环境 其实Vue的SSR环境搭建的过程是和React差不多的只是将资源换成webpack处理而已首先我们先搭建项目环境 搭建项目骨架 pnpm init -y pnpm install webpack webpack-cli -D 建立文件目录如下: ├─ package.json ├─ pnpm-lock.yaml ├─ server.js ├─ src │├─ App.vue │├─ entry-client.js │├─ entry-server.js ├─ webpack.base.js ├─ webpack.client.js └─ webpack.server.js 由于Vue的SSR搭建和React的思路差不多所以不把步骤拆的那么细了不过我会给代码添加注释 我们需要分别为服务端和客户端准备入口文件 entry-server.js import { createSSRApp } from vueimport App from ./App.vueexport default () {return createSSRApp(App) } entry-client.js import { createSSRApp } from vueimport App from ./App.vuecreateSSRApp(App).mount(#app) 两者区别在于客户端版本会立即调用 mount 将组件挂载到页面上而服务端版本只是 export 一个创建应用的工厂函数。 编写不同环境的webpack配置文件 我们需要分别为客户端、服务端版本编写 Webpack 配置文件和一个基础的配置文件也就是服务端和客户端都会用到的配置即上述目录中的三个**webpack.*.js 文件**。 webpack.base.js用于客户端和服务端的公共配置 const path require(path) const { VueLoaderPlugin } require(vue-loader)module.exports {mode: process.env.NODE_ENV production ? production : development,output: {filename: [name].[contenthash].js,path: path.join(__dirname, dist),},resolve: {extensions: [.vue, .js],},module: {rules: [{ test: /.vue$/, use: vue-loader }],},plugins: [new VueLoaderPlugin()], } webpack.client.js 用于定义构建客户端资源的配置 // 合并webpack配置的插件 const Merge require(webpack-merge) const path require(path) const HtmlWebpackPlugin require(html-webpack-plugin) const { WebpackManifestPlugin } require(webpack-manifest-plugin) const base require(./webpack.base)module.exports Merge.merge(base, {entry: {// 入口指向 entry-client.js 文件client: path.join(__dirname, ./src/entry-client),},output: {publicPath: /,},module: {rules: [{ test: /\.css$/, use: [style-loader, css-loader] }],},plugins: [// 这里使用 webpack-manifest-plugin 记录产物分布情况// 方面后续在 server.js 中使用new WebpackManifestPlugin({ fileName: manifest-client.json }),// 自动生成 HTML 文件内容new HtmlWebpackPlugin({templateContent: !DOCTYPE html html headmeta charsetutf-8titleWebpack App/title /head bodydiv idapp / /body /html,}),], }) webpack.server.js 用于定义构建服务端资源的配置 const Merge require(webpack-merge) const path require(path) const { WebpackManifestPlugin } require(webpack-manifest-plugin) const base require(./webpack.base)module.exports Merge.merge(base, {entry: {server: path.join(__dirname, src/entry-server),},target: node,output: {// 打包后的结果会在 node 环境使用// 因此此处将模块化语句转译为 commonjs 形式libraryTarget: commonjs2,},module: {rules: [{test: /\.css$/,use: [// 注意这里用 vue-style-loader 而不是 style-loader// 因为 vue-style-loader 对 SSR 模式更友好vue-style-loader,{loader: css-loader,options: {esModule: false,},},],},],},plugins: [// 这里使用 webpack-manifest-plugin 记录产物分布情况// 方面后续在 server.js 中使用new WebpackManifestPlugin({ fileName: manifest-server.json }),], }) 然后我们只需要调用适当命令即可分别生成客户端、服务端版本代码 # 客户端版本 npx webpack --config ./webpack.client.js # 服务端版本 npx webpack --config ./webpack.server.js 编写SSR的服务端的服务 server.js const express require(express) const path require(path) const { renderToString } require(vue/server-renderer)// 通过 manifest 文件找到正确的产物路径 const clientManifest require(./dist/manifest-client.json) const serverManifest require(./dist/manifest-server.json)const serverBundle path.join(__dirname, ./dist, serverManifest[server.js]) // 这里就对标到 entry-server.js 导出的工厂函数 const createApp require(serverBundle).defaultconst server express()server.get(/, async (req, res) {const app createApp()const html await renderToString(app)const clientBundle clientManifest[client.js]res.send(!DOCTYPE htmlhtmlheadtitleVue SSR /title/headbody!-- 注入组件运行结果 --div idapp${html}/div!-- 注入客户端代码产物路径 --!-- 实现 Hydrate 效果 --script src${clientBundle}/script/body/html) })server.use(express.static(./dist))server.listen(3000, () {console.log(服务在3000端口运行) }) OK我们编写App.vue文件 templatediv :class[main, cls]h3{{ message }}/h3button clickhandleClickToggle/button/div /templatescript import { ref, computed } from vue/reactivity export default {setup() {const isActivity ref(false)const cls computed(() (isActivity.value ? activate : deactivate))const handleClick () {isActivity.value !isActivity.value}return {isActivity,message: Hello World,cls,handleClick,}}, } /scriptstyle h3 {color: #42b983; } .main {position: fixed;top: 0;left: 0;bottom: 0;right: 0;padding: 20px 12px;transition: background 0.3s linear; } .activate {background: #000; } .deactivate {background: #fff; } /style 然后我们在package.json里添加脚本如下: scripts: {build:client: webpack --config ./webpack.client.js,build:server: webpack --config ./webpack.server.js,start: nodemon server.js}, Ok,然后我们执行pnpm build:client和pnpm build:server,然后执行pnpm start,项目就跑起来了我们可以看到如下页面点击Toggle可以切换背景 OK相信读了文章的同学们应该对SSR应该有了新的认识有问题可以一起讨论哇咱们下回再见咯。 React的SSR环境搭建代码地址 Vue的SSR环境搭建代码地址 最后 整理了一套《前端大厂面试宝典》包含了HTML、CSS、JavaScript、HTTP、TCP协议、浏览器、VUE、React、数据结构和算法一共201道面试题并对每个问题作出了回答和解析。 有需要的小伙伴可以点击文末卡片领取这份文档无偿分享 部分文档展示 文章篇幅有限后面的内容就不一一展示了 有需要的小伙伴可以点下方卡片免费领取
http://www.w-s-a.com/news/292962/

相关文章:

  • 怎么做网约车seo自动优化软件下载
  • 遵义市住房和城乡建设局官方网站网站备案 自己的服务器
  • 分销系统价格多少北京网站优化平台
  • 怎样做旅游公司的网站泉州网站建设方案优化
  • 手机网站页面范例个人网站做淘宝客违规
  • 做一套网站开发多少钱SEO做得最好的网站
  • 咸宁做网站的公司那家便宜福建建设注册管理中心网站
  • 网站建设工作汇报黑科技广告推广神器
  • 淘宝做首页热点的什么网站徐州建设安全监督网站
  • 正规的镇江网站建设广州有什么好玩的东西
  • 丹阳网站设计公司网站开发 0755
  • 百度网页版浏览器网址找文网优化的技术团队
  • 信息网站怎么做做儿童网站赚钱吗
  • 帝国cms 网站迁移个人网站备案备注
  • 青岛做网站推广怎样做网站才不能被攻破
  • 使用网站模板快速建站教案杂志wordpress主题 无限加载
  • 南宁南宁做网站南安网络推广
  • 旌阳移动网站建设微网站 杭州
  • 合肥网站开发如何用VS2017做网站
  • 网站 制作公司福州企业建站软件
  • 网站推广主要方法一流的盘锦网站建设
  • 给个网站好人有好报2021东莞专业网站营销
  • 中国网站优化哪家好制作网站页面
  • 网站站内优化度娘网站灯笼要咋做呢
  • 怎么制作一个简单的网站七牛云做网站
  • 厦门建网站哪家好求网站建设合伙人
  • 营销型网站制作步骤五个宁波依众网络科技有限公司
  • 外贸响应式网站建设临清建设局网站
  • 手机怎样使用域名访问网站个人做旅游网站的意义
  • 西部数码域名网站模板网站建设怎么管理业务员