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

陕西省高速集团建设网站公司网址备案能用多少网站

陕西省高速集团建设网站,公司网址备案能用多少网站,网站主色调简介怎么说,百度个人网站建设什么是基于同构代码的 SSR 服务(Server-side rendering based on isomorphic code)首先#xff0c;我们需要先明白什么是 spa (single page application)#xff0c;以及基于 vue 的 spa 是如何工作的#xff0c;这里不展开#xff0c;请参考#xff1a;单页应用:https://… 什么是基于同构代码的 SSR 服务(Server-side rendering based on isomorphic code)首先我们需要先明白什么是 spa (single page application)以及基于 vue 的 spa 是如何工作的这里不展开请参考单页应用:https://zh.wikipedia.org/wiki/%E5%8D%95%E9%A1%B5%E5%BA%94%E7%94%A8vue 实例:https://cn.vuejs.org/v2/guide/instance.html#%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA-Vue-%E5%AE%9E%E4%BE%8B基于同构代码的 SSR 指的是同一份代码(spa代码)既能在客户端运行并渲染出页面也可以在服务器端渲染为 html 字符串并响应给客户端。它与传统的服务器直出不同传统的服务器直出指的是路由系统只存在于服务器端在服务器端任何一个页面都需要服务器响应内容。SSR 有什么好处相比 spa 应用ssr 应用对搜索引擎更友好理论上TTI 更短(TTI time to interactive指用户从第一个请求发出到能够与页面交互这之间的时间差)下图是一个实际项目中在弱网环境(3g)中接入 ssr 服务之前和之后的请求耗时对比工程背景实际项目在微信环境内提供h5页面为提高用户体验我们将其接入 ssr 服务并代理微信 OAuth 的部分过程测量范围新客户从第一个http请求发出到入口页面的内容下载完毕为止接入 ssr 服务前此测量范围内会经历客户端下载入口文件、js、css等资源客户端跳转微信授权服务获取授权 code客户端跳回源地址进行授权登录(客户可看到页面)接入 ssr 服务后此测量范围内会经历服务器跳转微信授权服务获取授权 code客户端下载入口文件、js、css等资源(客户可看到页面)客户端授权登录我们可以看到接入 ssr 服务后客户理论上能更早得看到页面了根据上图可以看到在接入 ssr 服务后客户能更早得看到页面内容客户感知到的性能提高了。SSR 有什么风险加重服务器负载通常用于 SSR 的服务都是基于 NodeJS 环境需要额外的研发成本(例如日志、监控、追踪)SSR 的服务通常都由前端工程师研发和维护增加了更多的心智负担基于同构代码的 SSR 应用是同一份代码既在浏览器运行也在服务器运行代码层面的问题造成的影响更大今天我们使用新版的 cli 工具(v3.x)搭建一个基于 vue 同构代码的 ssr 工程项目。我们的目标使用 vue/cli v3.x 与 koa v2.x 创建一个 ssr 工程我们的步骤如下安装 vue/cli使用 vue/cli 创建 spa 工程将 spa 工程逐步改造成 ssr 工程我们需要的工具如下vue/cli v3.xkoa v2.xkoa-send v5.xvue-server-renderer v2.xmemory-fs v0.xlodash.get v4.xlodash.merge v4.xaxios v0.xejs v2.x第一步安装 vue/cli v3.xyarn global add vue/cli笔者安装的 vue/cli 的版本为: v3.6.2第二步使用 vue/cli 创建一个 spa 应用vue create ssr-demo创建完毕之后 ssr-demo 的目录结构如下./ssr-demo├── README.md├── babel.config.js├── package.json├── public│ ├── favicon.ico│ └── index.html├── src│ ├── App.vue│ ├── assets│ │ └── logo.png│ ├── components│ │ └── HelloWorld.vue│ ├── main.js│ ├── router.js│ ├── store.js│ └── views│ ├── About.vue│ └── Home.vue└── yarn.lock进入 srr-demo 安装 vue-server-rendereryarn add vue-server-renderer笔者创建的 ssr-demo 中各主要工具库的版本如下vue v2.6.10vue-router v3.0.3vuex v3.0.1vue-template-compiler v2.5.21vue-server-renderer v2.6.10执行 yarn serve 在浏览器上看一下效果。至此spa 工程就创建完毕了接下来我们在此基础上将此 spa 工程逐步转换为 ssr 工程模式。第三步单例模式改造在 spa 工程中每个客户端都会拥有一个新的 vue 实例。因此在 ssr 工程中我们也需要为每个客户端请求分配一个新的 vue 实例(包括 router 和 store)。我们的步骤如下改造状态存储 src/store.js改造路由 src/router.js改造应用入口 src/main.js改造步骤一改造状态存储改造前我们看下 src/store.js 的内容import Vue from vueimport Vuex from vuexVue.use(Vuex)export default new Vuex.Store({ state: { }, mutations: { }, actions: { }})src/store.js 的内部只返回了一个 store 实例。如果这份代码在服务器端运行那么这个 store 实例会在服务进程的整个生命周期中存在。这会导致所有的客户端请求都共享了一个 store 实例这显然不是我们的目的因此我们需要将状态存储文件改造成工厂函数代码如下import Vue from vueimport Vuex from vuexVue.use(Vuex)export function createStore () { return new Vuex.Store({ state: { }, mutations: { }, actions: { } })}目录结构同样有变化# 改造前./src├── ...├── store.js├── ...# 改造后./src├── ...├── store│ └── index.js├── ...改造步骤二改造路由改造前我们看下 src/router.js 的内容import Vue from vueimport Router from vue-routerimport Home from ./views/Home.vueVue.use(Router)export default new Router({ mode: history, base: process.env.BASE_URL, routes: [ { path: /, name: home, component: Home }, { path: /about, name: about, // route level code-splitting // this generates a separate chunk (about.[hash].js) for this route // which is lazy-loaded when the route is visited. component: () import(/* webpackChunkName: about */ ./views/About.vue) } ]})类似 src/store.js, 路由文件src/router.js 的内部也只是返回了一个 router 实例。如果这份代码在服务器端运行那么这个 router 实例会在服务进程的整个生命周期中存在。这会导致所有的客户端请求都共享了一个 router 实例这显然不是我们的目的因此我们需要将路由改造成工厂函数代码如下import Vue from vueimport Router from vue-routerimport Home from ../views/Home.vueVue.use(Router)export function createRouter () { return new Router({ mode: history, base: process.env.BASE_URL, routes: [ { path: /, name: home, component: Home }, { path: /about, name: about, // route level code-splitting // this generates a separate chunk (about.[hash].js) for this route // which is lazy-loaded when the route is visited. component: () import(/* webpackChunkName: about */ ../views/About.vue) } ] })}目录结构也有变化# 改造前./src├── ...├── router.js├── ...# 改造后./src├── ...├── router│ └── index.js├── ...改造步骤三改造应用入口因为我们需要在服务器端运行与客户端相同的代码所以免不了需要让服务器端也依赖 webpack 的构建过程。借用官方文档的示意图我们看到源代码分别为客户端和服务器提供了独立的入口文件server entry 和 client entry通过 webpack 的构建过程构建完成后也对应得输出了两份 bundle 文件分别为客户端和服务器提供了chunk 文件映射路径源代码定位源代码打包(服务器端的 bundle 文件包含了所有打包后的客户端代码)等功能。因此我们接下来先改造 src/main.js然后再创建 entry-client.js 和 entry-server.js改造 src/main.js 前我们先来看看 src/main.js 的内容import Vue from vueimport App from ./App.vueimport router from ./routerimport store from ./storeVue.config.productionTip falsenew Vue({ router, store, render: h h(App)}).$mount(#app)与 src/store.js 和 src/router.js 类似src/main.js 同样也是单例模式因此我们将它改造为工厂函数import Vue from vueimport App from ./Appimport { createRouter } from ./routerimport { createStore } from ./storeexport function createApp () { const router createRouter() const store createStore() const app new Vue({ router, store, render: h h(App) }) return { app, router, store }}将 src/main.js 改造完毕后我们来分别创建 entry-client.js 和 entry-server.js我们先来看 entry-client.jsimport { createApp } from ./main.jsconst { app, router, store } createApp()if (window.__INITIAL_STATE__) { store.replaceState(window.__INITIAL_STATE__)}router.onReady(() { app.$mount(#app)})在服务器端渲染路由组件树所产生的 context.state 将作为脱水数据挂载到 window.__INITIAL_STATE__在客户端只需要将 window.__INITIAL_STATE__ 重新注入到 store 中即可(通过 store.replaceState 函数)最后我们需要将 mount 的逻辑放到客户端入口文件内。创建完毕客户端入口文件后让我们来看服务端的入口文件 entry-server.jsimport { createApp } from ./main.jsexport default context { return new Promise((resolve, reject) { const { app, router, store } createApp() router.push(context.url) router.onReady(() { context.rendered () { context.state store.state } resolve(app) }, reject) })}上面的 context.rendered 函数会在应用完成渲染的时候调用在服务器端应用渲染完毕后此时 store 可能已经从路由组件树中填充进来一些数据。当我们将 state 挂载到 context 并在使用 renderer 的时候传递了 template 选项那么 state 会自动序列化并注入到 HTML 中作为 window.__INITIAL_STATE__ 存在。接下来我们来给 store 添加获取数据的逻辑并在首页调用其逻辑方便后面观察服务器端渲染后的 window.__INITIAL_STATE__改造 store: 添加获取数据逻辑改造后的目录结构src/store├── index.js└── modules └── book.jssrc/store/index.jsimport Vue from vueimport Vuex from vueximport { Book } from ./modules/book.jsVue.use(Vuex)export function createStore () { return new Vuex.Store({ modules: { book: Book }, state: { }, mutations: { }, actions: { } })}src/store/modules/book.jsimport Vue from vueconst getBookFromBackendApi id new Promise((resolve, reject) { setTimeout(() { resolve({ name: 《地球往事》, price: 100 }) }, 300)})export const Book { namespaced: true, state: { items: {} }, actions: { fetchItem ({ commit }, id) { return getBookFromBackendApi(id).then(item { commit(setItem, { id, item }) }) } }, mutations: { setItem (state, { id, item }) { Vue.set(state.items, id, item) } }}改造首页预取数据改造前我们先看一下 src/views/Home.vue 的代码template div classhome img altVue logo src../assets/logo.png HelloWorld msgWelcome to Your Vue.js App/ divtemplatescript// is an alias to /srcimport HelloWorld from /components/HelloWorld.vueexport default { name: home, components: { HelloWorld }}script改造后的代码如下template div classhome img altVue logo src../assets/logo.png HelloWorld msgWelcome to Your Vue.js App/ div v-ifbook{{ book.name }}div div v-elsenothingdiv divtemplatescript// is an alias to /srcimport HelloWorld from /components/HelloWorld.vueexport default { name: home, computed: { book () { return this.$store.state.book.items[this.$route.params.id || 1] } }, // 此函数只会在服务器端调用注意只有 vue v2.6.0 才支持此函数 serverPrefetch () { return this.fetchBookItem() }, // 此生命周期函数只会在客户端调用 // 客户端需要判断在 item 不存在的场景再去调用 fetchBookItem 方法获取数据 mounted () { if (!this.item) { this.fetchBookItem() } }, methods: { fetchBookItem () { // 这里要求 book 的 fetchItem 返回一个 Promise return this.$store.dispatch(book/fetchItem, this.$route.params.id || 1) } }, components: { HelloWorld }}script至此客户端源代码的改造告一段落我们接下来配置构建过程配置 vue.config.js基于 vue/cli v3.x 创建的客户端工程项目中不再有 webpack.xxx.conf.js 这类文件了。取而代之的是 vue.config.js 文件它是一个可选的配置文件默认在工程的根目录下由 vue/cli-service 自动加载并解析。我们对于 webpack 的所有配置都通过 vue.config.js 来实现。关于 vue.config.js 内部配置的详细信息请参考官方文档https://cli.vuejs.org/zh/config/#vue-config-jsconst VueSSRServerPlugin require(vue-server-renderer/server-plugin)const VueSSRClientPlugin require(vue-server-renderer/client-plugin)const nodeExternals require(webpack-node-externals)const merge require(lodash.merge)const TARGET_NODE process.env.TARGET_NODE nodeconst DEV_MODE process.env.NODE_ENV developmentconst config { publicPath: process.env.NODE_ENV production // 在这里定义产品环境和其它环境的 publicPath // 关于 publicPath 请参考: // https://webpack.docschina.org/configuration/output/#output-publicpath ? / : /, chainWebpack: config { if (DEV_MODE) { config.devServer.headers({ Access-Control-Allow-Origin: * }) } config .entry(app) .clear() .add(./src/entry-client.js) .end() // 为了让服务器端和客户端能够共享同一份入口模板文件 // 需要让入口模板文件支持动态模板语法(这里选了 ejs) .plugin(html) .tap(args { return [{ template: ./public/index.ejs, minify: { collapseWhitespace: true }, templateParameters: { title: spa, mode: client } }] }) .end() // webpack 的 copy 插件默认会将 public 文件夹中所有的文件拷贝到输出目录 dist 中 // 这里我们需要将 index.ejs 文件排除 .when(config.plugins.has(copy), config { config.plugin(copy).tap(([[config]]) [ [ { ...config, ignore: [...config.ignore, index.ejs] } ] ]) }) .end() // 默认值: 当 webpack 配置中包含 target: node 且 vue-template-compiler 版本号大于等于 2.4.0 时为 true。 // 开启 Vue 2.4 服务端渲染的编译优化之后渲染函数将会把返回的 vdom 树的一部分编译为字符串以提升服务端渲染的性能。 // 在一些情况下你可能想要明确的将其关掉因为该渲染函数只能用于服务端渲染而不能用于客户端渲染或测试环境。 config.module .rule(vue) .use(vue-loader) .tap(options { merge(options, { optimizeSSR: false }) }) config.plugins // Delete plugins that are unnecessary/broken in SSR add Vue SSR plugin .delete(pwa) .end() .plugin(vue-ssr) .use(TARGET_NODE // 这是将服务器的整个输出构建为单个 JSON 文件的插件。 // 默认文件名为 vue-ssr-server-bundle.json ? VueSSRServerPlugin // 此插件在输出目录中生成 vue-ssr-client-manifest.json : VueSSRClientPlugin) .end() if (!TARGET_NODE) return config .entry(app) .clear() .add(./src/entry-server.js) .end() .target(node) .devtool(source-map) .externals(nodeExternals({ whitelist: /\.css$/ })) .output.filename(server-bundle.js) .libraryTarget(commonjs2) .end() .optimization.splitChunks({}) .end() .plugins.delete(named-chunks) .delete(hmr) .delete(workbox) }}module.exports config至此客户端部分的改造告一段落当前 ssr-demo 的目录如下./ssr-demo├── README.md├── babel.config.js├── package.json├── public│ ├── favicon.ico│ └── index.ejs├── src│ ├── App.vue│ ├── assets│ │ └── logo.png│ ├── components│ │ └── HelloWorld.vue│ ├── entry-client.js│ ├── entry-server.js│ ├── main.js│ ├── router│ │ └── index.js│ ├── store│ │ ├── index.js│ │ └── modules│ │ └── book.js│ └── views│ ├── About.vue│ └── Home.vue├── vue.config.js└── yarn.lock接下来让我们来搭建 NodeJS 服务端部分。第四步NodeJS 服务端搭建在搭建服务端之前我们先安装服务端需要的依赖yarn add koa koa-send memory-fs lodash.get axios ejs安装完毕后对应的版本如下koa v2.7.0koa-send v5.0.0memory-fs v0.4.1lodash.get v4.4.2axios v0.18.0ejs v2.6.1生产环境服务搭建在 ssr-demo 跟目录下创建文件夹 app然后创建文件 server.js内容如下const Koa require(koa)const app new Koa()const host 127.0.0.1const port process.env.PORTconst productionEnv [production, test]const isProd productionEnv.includes(process.env.NODE_ENV)const fs require(fs)const PWD process.env.PWD// 产品环境我们在服务端进程启动时将客户端入口文件读取到内存中当 发生异常 或 需要返回客户端入口文件时响应给客户端。const getClientEntryFile isProd isProd ? fs.readFileSync(PWD /dist/index.html) : const clientEntryFile getClientEntryFile(isProd)app.use(async (ctx, next) { if (ctx.method ! GET) return try { await next() } catch (err) { ctx.set(content-type, text/html) if (err.code 404) { ctx.body clientEntryFile return } console.error( [SERVER ERROR] , err.toString()) ctx.body clientEntryFile }})app.use(require(./middlewares/prod.ssr.js))app.listen(port, host, () { console.log([${process.pid}]server started at ${host}:${port})})其中需要注意的是应该捕获服务端抛出的任何异常并将客户端入口文件响应给客户端。在 app 内创建文件夹 middlewares并创建文件 prod.ssr.js:const path require(path)const fs require(fs)const ejs require(ejs)const get require(lodash.get)const resolve file path.resolve(__dirname, file)const PWD process.env.PWDconst enableStream process.env.ENABLESTREAMconst { createBundleRenderer } require(vue-server-renderer)const bundle require(PWD /dist/vue-ssr-server-bundle.json)const clientManifest require(PWD /dist/vue-ssr-client-manifest.json)const tempStr fs.readFileSync(resolve(PWD /public/index.ejs), utf-8)const template ejs.render(tempStr, { title: {{title}}, mode: server })const renderer createBundleRenderer(bundle, { runInNewContext: false, template: template, clientManifest: clientManifest, basedir: PWD})const renderToString context new Promise((resolve, reject) { renderer.renderToString(context, (err, html) err ? reject(err) : resolve(html))})const renderToStream context renderer.renderToStream(context)const main async (ctx, next) { ctx.set(content-type, text/html) const context { title: get(ctx, currentRouter.meta.title, ssr mode), url: ctx.url } ctx.body await renderToString(context)}module.exports main然后我们为 package.json 配置新的打包命令和启动 ssr 服务的命令... scripts: { serve: vue-cli-service serve, build: vue-cli-service build TARGET_NODEnode vue-cli-service build --no-clean, start: NODE_ENVproduction TARGET_NODEnode PORT3000 node ./app/server.js },...这里需要注意一下在 build 命令中先执行客户端的构建命令然后再执行服务端的构建命令。服务端的构建命令与客户端的区别只有一个环境变量TARGET_NODE当将此变量设置值为 node则会按照服务端配置进行构建。另外在服务端构建命令中有一个参数--no-clean这个参数代表不要清除 dist 文件夹保留其中的文件。之所以需要 --no-clean 这个参数是因为服务端构建不应该影响到客户端的构建文件。这样能保证客户端即使脱离了服务端也能通过 nginx 提供的静态服务向用户提供完整的功能(也就是 spa 模式)。至此生产环境已经搭建完毕。接下来让我们来搭建开发环境的服务端。开发环境服务搭建开发环境的服务功能实际上是生产环境的超集。除了生产环境提供的服务之外开发环境还需要提供静态资源服务hot reload搭建静态资源服务生产环境中的静态资源因为都会放置到 CDN 上因此并不需要 NodeJS 服务来实现静态资源服务器一般都由 nginx 静态服务提供 CDN 的回源支持。但生产环境如果依赖独立的静态服务器可能导致环境搭建成本过高因此我们创建一个开发环境的静态资源服务中间件来实现此功能。我们的 spa 模式在开发环境通过命令 serve 启动后就是一个自带 hot reload 功能的服务。因此服务端在开发环境中提供的静态资源服务可以通过将静态资源请求路由到 spa 服务来提供静态服务功能。需要注意的是开发环境中服务端在启动之前需要先启动好 spa 服务。稍后我们会在 package.js 中创建 dev 命令来方便启动开发环境的 spa 与 ssr 服务。在 ./ssr-demo/app/middlewares/ 中创建文件 dev.static.js内容如下const path require(path)const get require(lodash.get)const send require(koa-send)const axios require(axios)const PWD process.env.PWDconst clientPort process.env.CLIENT_PORT || 8080const devHost http://localhost:${clientPort}const resolve file path.resolve(__dirname, file)const staticSuffixList [js, css, jpg, jpeg, png, gif, map, json]const main async (ctx, next) { const url ctx.path if (url.includes(favicon.ico)) { return send(ctx, url, { root: resolve(PWD /public) }) } // In the development environment, you need to support every static file without CDN if (staticSuffixList.includes(url.split(.).pop())) { return ctx.redirect(devHost url) } const clientEntryFile await axios.get(devHost /index.html) ctx.set(content-type, text/html) ctx.set(x-powered-by, koa/development) ctx.body clientEntryFile.data}module.exports main然后将中间件 dev.static.js 注册到服务端入口文件 app/server.js 中...if (process.env.NODE_ENV production) { app.use(require(./middlewares/prod.ssr.js))}else{ app.use(require(./middlewares/dev.static.js)) // TODO在这里引入开发环境请求处理中间件}app.listen(port, host, () { console.log([${process.pid}]server started at ${host}:${port})})因为我们需要在开发环境同时启动 spa 服务和 ssr 服务因此需要一个工具辅助我们同时执行两个命令。我们选择 concurrently关于此工具的具体细节请参照https://github.com/kimmobrunfeldt/concurrently安装 concurrentlyyarn add concurrently -D然后改造 package.json 中的 serve 命令... scripts: { serve: vue-cli-service serve, ssr:serve: NODE_ENVdevelopment PORT3000 CLIENT_PORT8080 node ./app/server.js, dev: concurrently npm run serve npm run ssr:serve,...其中:serve 开发环境启动 spa 服务ssr:serve 开发环境启动 ssr 服务dev 开发环境同时启动 spa 服务于 ssr 服务启动 ssr 服务的命令中NODE_ENV 是环境变量PORT 是 ssr 服务监听的端口CLIENT_PORT 是 spa 服务监听的端口因为静态资源需要从 spa 服务中获取所以 ssr 服务需要知道 spa 服务的 host 、端口 和 静态资源路径至此静态服务器搭建完毕接下来我们来搭建开发环境的请求处理中间件。(此中间件包含 hot reload 功能)实现 hot reload在 ./ssr-demo/app/middlewares/ 中创建文件 dev.ssr.js内容如下const path require(path)const fs require(fs)const ejs require(ejs)const PWD process.env.PWDconst webpack require(webpack)const axios require(axios)// memory-fs is a simple in-memory filesystem.// Holds data in a javascript object// See: https://github.com/webpack/memory-fsconst MemoryFS require(memory-fs)// Use parsed configuration as a file of webpack config// See: https://cli.vuejs.org/zh/guide/webpack.html#%E5%AE%A1%E6%9F%A5%E9%A1%B9%E7%9B%AE%E7%9A%84-webpack-%E9%85%8D%E7%BD%AEconst webpackConfig require(PWD /node_modules/vue/cli-service/webpack.config)// create a compiler of webpack configconst serverCompiler webpack(webpackConfig)// create the memory instanceconst mfs new MemoryFS()// set the compiler output to memory// See: https://webpack.docschina.org/api/node/#%E8%87%AA%E5%AE%9A%E4%B9%89%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F-custom-file-systems-serverCompiler.outputFileSystem mfslet serverBundle// Monitor webpack changes because server bundles need to be dynamically updatedserverCompiler.watch({}, (err, stats) { if (err) throw err stats stats.toJson() stats.errors.forEach(error console.error(ERROR:, error)) stats.warnings.forEach(warn console.warn(WARN:, warn)) const bundlePath path.join(webpackConfig.output.path, vue-ssr-server-bundle.json) serverBundle JSON.parse(mfs.readFileSync(bundlePath, utf-8)) console.log(vue-ssr-server-bundle.json updated)})const resolve file path.resolve(__dirname, file)const { createBundleRenderer } require(vue-server-renderer)const renderToString (renderer, context) new Promise((resolve, reject) { renderer.renderToString(context, (err, html) err ? reject(err) : resolve(html))})const tempStr fs.readFileSync(resolve(PWD /index.ejs), utf-8)const template ejs.render(tempStr, { title: {{title}}, mode: server })const clientHost process.env.CLIENT_PORT || localhostconst clientPort process.env.CLIENT_PORT || 8080const clientPublicPath process.env.CLIENT_PUBLIC_PATH || /const main async (ctx, next) { if (!serverBundle) { ctx.body Wait Compiling... return } ctx.set(content-type, text/html) ctx.set(x-powered-by, koa/development) const clientManifest await axios.get(http://${clientHost}:${clientPort}${clientPublicPath}vue-ssr-client-manifest.json) const renderer createBundleRenderer(serverBundle, { runInNewContext: false, template: template, clientManifest: clientManifest.data, basedir: process.env.PWD }) const context { title: ssr mode, url: ctx.url } const html await renderToString(renderer, context) ctx.body html}module.exports main在开发环境我们通过 npm run dev 命令启动一个 webpack-dev-server 和一个 ssr 服务通过官方文档可知我们可以通过一个文件访问解析好的 webpack 配置这个文件路径为node_modules/vue/cli-service/webpack.config.js使用 webpack 编译此文件并将其输出接入到内存文件系统(memory-fs)中监听 webpack当 webpack 重新构建时我们在监听器内部获取最新的 server bundle 文件并从 webpack-dev-server 获取 client bundle 文件在每次处理 ssr 请求的中间件逻辑中使用最新的 server bundle 文件和 client bundle 文件进行渲染最后将中间件 dev.ssr.js 注册到服务端入口文件 app/server.js 中...if (process.env.NODE_ENV production) { app.use(require(./middlewares/prod.ssr.js))}else{ app.use(require(./middlewares/dev.static.js)) app.use(require(./middlewares/dev.ssr.js))}app.listen(port, host, () { console.log([${process.pid}]server started at ${host}:${port})})至此我们基于 vue/cli v3 完成了一个简易的 ssr 工程项目目录结构如下./ssr-demo├── README.md├── app│ ├── middlewares│ │ ├── dev.ssr.js│ │ ├── dev.static.js│ │ └── prod.ssr.js│ └── server.js├── babel.config.js├── package.json├── public│   └── index.ejs├── src│ ├── App.vue│ ├── assets│ │ └── logo.png│ ├── components│ │ └── HelloWorld.vue│ ├── entry-client.js│ ├── entry-server.js│ ├── main.js│ ├── router│ │ └── index.js│ ├── store│ │ ├── index.js│ │ └── modules│ │ └── book.js│ └── views│ ├── About.vue│ └── Home.vue├── vue.config.js└── yarn.lock以上是我们基于 vue/cli v3 构建 ssr 工程的全部过程。虽然我们已经有了一个基础的 ssr 工程但这个工程项目还有以下缺失的地方没有降级策略如果 ssr 服务出现异常整个服务就会受到影响我们需要考虑在 ssr 服务出现问题时如何将其降级为 spa 服务没有日志系统ssr 服务内部接收到的请求信息、出现的异常信息、关键业务的信息这些都需要记录日志方便维护与追踪定位错误。没有缓存策略我们搭建的 ssr 服务对于每一次的请求都会耗费服务器资源去渲染这对于那些一段时间内容不会变化的页面来说浪费了资源。没有监控系统ssr 服务是常驻内存的我们需要尽可能实时得知道它当前的健康状况力求在出现问题之前得到通知并快速做出调整。没有弱网支持对于弱网用户我们需要给出功能完备但更加轻盈的页面以便让弱网环境下的用户也能正常使用服务。因此将此工程应用到产品项目中之前还需要对 ssr 工程再做一些改进未来我们会逐步为 ssr 服务提供以下配套设施降级日志缓存监控弱网下一篇文章我们讲解如何研发一个基于 vue/cli v3 的插件并将 ssr 工程项目中服务器端的功能整合进插件中。水滴前端团队招募伙伴欢迎投递简历到邮箱fedshuidihuzhu.com
http://www.pierceye.com/news/439091/

相关文章:

  • 网站建设是设开发公司质量管理流程
  • 金沙网站怎么做代理wordpress tag=
  • 做网站必须花钱吗建筑人才网证书查询
  • 0基础网站建设模板工商注册官方网站
  • 河南网站设计公司价格网站在建设中是什么意思
  • 网站建设公司的成本有哪些方面四川省城乡建设网查询
  • 和什么人合作做游戏视频网站做推送网站
  • 做竞价网站访问突然变少施工企业负责人带班检查计划
  • 网站统计数据分析wordpress安装 第二步
  • 网站续费续的是什么钱Wordpress1002无标题
  • 公司入口网站appui设计师创意平台
  • 济南住房和城乡建设厅网站影视广告创意拍摄
  • 卢松松网站源码网站建设讲师招聘
  • wordpress建站网页无法运vs网站开发表格大小设置
  • 网站怎么制作教程科技小论文怎么写
  • 青岛外贸建设网站制作小程序制作页面教程
  • wordpress 整合phpseo推广有效果吗
  • 毕业设计做网站代码营销推广软文案例
  • 网站seo 文章转载 修改标题手机oa办公系统下载
  • 营销型网站设计工资商城是什么平台
  • 有没有可以在线做化学实验的网站乐从网站制作
  • 网站qq 微信分享怎么做的网络销售网站有哪些
  • 长沙电商网站制作网页设计模板素材旅游
  • 阿里巴巴 网站 建设wordpress支付宝红包
  • 如何建一个企业网站网站建设方案保障措施
  • 网站制作工作室24小时接单一起做网站
  • 专业购物网站建设多少钱搜索引擎推广的基本方法
  • 高端手机网站建设需要多少钱五金制品东莞网站建设
  • 网站运营与维护是什么意思出入成都最新规定今天
  • 网站建设 企炬江阴企业形象包装公司