亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么改造Vue SSR服務端渲染

發布時間:2021-11-03 14:35:22 來源:億速云 閱讀:144 作者:iii 欄目:web開發

本篇內容介紹了“怎么改造Vue SSR服務端渲染”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

Vue的SSR渲染,可以當作一個全新的項目,需要安裝依賴的模塊(node_modules),可以將原先使用vue cli 3創建的項目的package.json拷貝過來,確保不缺少相關模塊,然后在此基礎上添加SSR需要的模塊。

主要是vue-server-renderer:

npm install vue vue-server-renderer --save

vue-server-renderer是SSR渲染的核心,提供bundle renderer來調用renderToString()方法將Vue組件渲染成HTML字符串,需要注意的是vue-server-renderer 和 vue 必須匹配版本,例如@2.6.11版本的vue必須對應@2.6.11版本的vue-server-renderer 。

路由模式history

采用了vue-router的Vue的SSR渲染,必須使用history作為路由模式,因為hash模式的路由提交不到服務器上,如果之前使用的是hash模式,需要進行修改:

  const router = new Router({
   mode: 'history',
   ...
 })

兩個入口

Vue的SSR渲染,一般都會是同構的,也就是業務代碼是一套,通過不同的構建配置,來分別構建客戶端client和服務端server,對webpack構建而言,這就需要有兩個入口,修改vue.config.js來支持,代碼如下:

const TARGET_NODE = process.env.WEBPACK_TARGET === 'node'

const target = TARGET_NODE ? 'server' : 'client'
 ...
   configureWebpack: {
   // 將 entry 指向應用程序的 server / client 文件
   entry: `./src/entry-${target}.js`,
   // 這允許 webpack 以 Node 適用方式(Node-appropriate fashion)處理動態導入(dynamic import),
   // 并且還會在編譯 Vue 組件時,
   // 告知 `vue-loader` 輸送面向服務器代碼(server-oriented code)。
   target: TARGET_NODE ? 'node' : 'web',
   // node: TARGET_NODE? undefined : false,
   // 此處告知 server bundle 使用 Node 風格導出模塊(Node-style exports)
   output: {
     libraryTarget: TARGET_NODE ? 'commonjs2' : undefined
   },
   // devtool: 'source-map',
   // https://webpack.js.org/configuration/externals/#function
   // https://github.com/liady/webpack-node-externals
   // 外置化應用程序依賴模塊。可以使服務器構建速度更快,
   // 并生成較小的 bundle 文件。
   externals: TARGET_NODE ? nodeExternals({
     // 不要外置化 webpack 需要處理的依賴模塊。
     // 你可以在這里添加更多的文件類型。例如,未處理 *.vue 原始文件,
     // 你還應該將修改 `global`(例如 polyfill)的依賴模塊列入白名單
     whitelist: /\.css$/
   }) : undefined,
   optimization: {
     splitChunks: false
   },
 },
 chainWebpack: config => {
   config.module
     .rule('vue')
     .use('vue-loader')
     .tap(options => {
       return merge(options, {
         optimizeSSR: false //https://vue-loader-v14.vuejs.org/zh-cn/options.html#optimizeSSR
       })
     })
 },
 ...

其中,分別使用entry-client.js和entry-server.js作為entry入口即可,如果需要一次命令同時執行兩個構建,可以修改package.json如下:

  "scripts": {
   "build": "vue-cli-service build",
   "build:server": "cross-env WEBPACK_TARGET=node vue-cli-service build && vue-cli-service build"
 },

對于開發模式的SSR構建,由于使用不多,這里只提供生產模式的SSR構建,執行如下命令:

npm run build:server

bundle文件

Vue的SSR渲染服務端啟動時,bundle renderer主要解析兩個bundle文件,分別是:vue-ssr-server-bundle.json和vue-ssr-client-manifest.json文件,這兩個文件分別由webpack構建生成,可以修改之前的vue.config.js配置文件:

  configureWebpack: {
   ...
   plugins: [
     TARGET_NODE ? new VueSSRServerPlugin() : new VueSSRClientPlugin()
   ],
   ...
 },

其中vue-ssr-server-bundle.json主要存放的是資源的映射信息,是bundle renderer必須的,而vue-ssr-client-manifest.json是對象clientManifest配置項,此對象包含了 webpack 整個構建過程的信息,從而可以讓 bundle renderer自動推導需要在HTML模板中注入的內容,從而實現最佳的預加載(preload)和預取(prefetch)資源,如下圖所示:

怎么改造Vue SSR服務端渲染

模擬window對象

Vue的SSR渲然Vue組件(包括根組件App.vue和其若干個子組件)時,由于沒有動態更新,所有的組件生命周期鉤子函數中,只有 beforeCreate 和 created 會在SSR渲染過程中被調用。這就是說任何其他生命周期鉤子函數中的代碼(例如 beforeMount 或 mounted),只會在客戶端執行。此外還需要注意的是,應該避免在 beforeCreate 和 created 生命周期時產生全局副作用的代碼,例如在其中使用 setInterval 設置 timer。在純客戶端 (client-side only) 的代碼中,我們可以設置一個 timer,然后在 beforeDestroy 或 destroyed 生命周期時將其銷毀。但是,由于在 SSR 期間并不會調用銷毀鉤子函數,所以 timer 將永遠保留下來。為了避免這種情況,請將副作用代碼移動到 beforeMount 或 mounted 生命周期中。對于SSR渲染,由于采用的Node.js環境,所以需要對于window對象做兼容處理,這里推薦使用jsdom:

npm install jsdom --save

然后,在SSR的入口文件service.js中(非entry-server.js),添加如下代碼:

const jsdom = require('jsdom')
const { JSDOM } = jsdom

/* 模擬window對象邏輯 */
const resourceLoader = new jsdom.ResourceLoader({
 userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1",
});// 設置UA
const dom = new JSDOM('', {
 url:'https://app.nihaoshijie.com.cn/index.html',
 resources: resourceLoader
});

global.window = dom.window
global.document = window.document
global.navigator = window.navigator
window.nodeis = true //給window標識出node環境的標志位
/* 模擬window對象邏輯 */

normalizeFile get undefined file錯誤

當運營SSR渲染,遇到如下錯誤時:

怎么改造Vue SSR服務端渲染

該錯誤通常會導致vue-ssr-client-manifest.json文件中的映射信息異常,導致無法正確找到對應的資源文件,可能屬于VueSSRClientPlugin()的bug,但是可以通過webpack配置來進行規避,修改vue.config.js,添加代碼如下:

  css: {
   sourceMap: true
 }

相關的issue地址。

在服務端請求SSR首屏數據

對于一些首屏非靜態頁面的場景,這些頁面的渲染依賴后端數據,所以在SSR端進行數據的拉取,并且在SSR渲染完成之后,將數據直接帶給客戶端進行二次渲染,減少請求的次數,所以對于數據共享的方案,最合適的方式是通過Vuex的Store完成,所以這里推薦項目使用Vuex,首先修改entry-server.js代碼如下:

      // 對所有匹配的路由組件調用 `asyncData()`
     Promise.all(matchedComponents.map(Component => {
       if (Component.asyncData) {

         return Component.asyncData({
           store,
           route: router.currentRoute
         })
       }
     })).then(() => {
       // 在所有預取鉤子(preFetch hook) resolve 后,
       // 我們的 store 現在已經填充入渲染應用程序所需的狀態。
       // 當我們將狀態附加到上下文,
       // 并且 `template` 選項用于 renderer 時,
       // 狀態將自動序列化為 `window.__INITIAL_STATE__`,并注入 HTML。
       context.state = store.state

       resolve(app)
     }).catch((err)=>{
       console.error(err)
       reject(err)
     })

同時給首屏的第一個路由組件添加asyncData方法來請求數據,注意是組件的靜態方法,而非在methods中定義的方法,代碼如下:

export default {
 name: 'wecircle',
 ...
 asyncData ({ store }) {
   // 觸發 action 后,會返回 Promise
   return store.dispatch('setWecircleDataListSSR')
 },
 ...
}

后面的action和mutation按照正常邏輯寫即可,最后,當SSR數據渲染完成后,會在生成的HTML中添加一個window.__INITIAL_STATE__對象,修改entry-client.js可以將數據直接賦值給客戶端渲染,代碼如下:

const { app, router, store } = createApp()

if (window.__INITIAL_STATE__) {
 store.replaceState(window.__INITIAL_STATE__)
}

最后一點需要注意是由于客戶端和服務端代碼是同構的,但是服務端請求數據的地址和客戶端是完全不一樣的,所以針對這種場景,需要利用之前設置的window.nodejs標志位來判斷在不同場景下的接口地址,從而區分對待。

cookie透傳

當在SSR端請求數據時,可能會需要帶上瀏覽器的cookie,在客戶端到SSR服務器的請求中,客戶端是攜帶有cookie數據的。但是在SSR服務器請求后端接口的過程中,卻是沒有相應的cookie數據的。因此在SSR服務器進行接口請求的時候,我們需要手動拿到客戶端的cookie傳給后端服務器。這里如果使用是axios,就可以手動設置axios請求的headers字段,代碼如下:在server.js中獲取瀏覽器cookie,并利用window對象存儲:

app.use('*', (req, res) => {
 ...
 window.ssr_cookie = req.cookie
 ...
})

在axios中,添加header將cookie塞進去:

axios.create({
 ...
 headers: window.ssr_cookie || {}
 ...
})

這樣就可以將瀏覽器的cookie帶給SSR服務器了。

No stacktrace on NavigationDuplicated error錯誤

該錯誤本身是由于重復的點擊相同的導航組件,會報錯NavigationDuplicated,由于SSR渲染會使用hostory模式,所以在第一次進入路由時,會經過多次導航(可以通過給router添加beforeEach鉤子可以看到),所以也會報NavigationDuplicated錯誤,本身這個錯誤不影響使用,但是如果需要規避,可以采用如下代碼,在router.js中添加:

const originalPush = Router.prototype.push
Router.prototype.push = function push(location, onResolve, onReject) {
 if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject)
 return originalPush.call(this, location).catch(err => err)
}

相關的issue地址。

同時支持客戶端渲染和服務端渲染

既然使用了Vue的SSR渲染,那么首先需要考慮的就是SSR服務的穩定性,所以為了最大程度的保證服務可用,當服務端渲染掛掉時,需要有容錯邏輯保證頁面可用,所以,原先的客戶端渲染相關的構建要保留,即通過直接訪問index.html的方式能夠正常使用頁面,這里直接通過nginx配置路徑轉發,代碼如下:

location /index.html {
    return 301 https://$server_name/;
}

即將原先的通過http://www.abc.com/index.html訪問的地址轉發到http://www.abc.com/,這樣就能夠觸發采用history模式的vue-router的path="/"的路由,對于客戶端訪問和服務的訪問,分別配置不同的轉發,如下:

 # 客戶端渲染服務
 location / {
    # 給靜態文件添加緩存
    location ~ .*\.(js|css|png|jpeg)(.*) {
         valid_referers *.nihaoshijie.com.cn;
         if ($invalid_referer) {
           return 404;
         }
         proxy_pass http://localhost:8080;
         expires  3d;# 3天
     }
     proxy_pass http://localhost:8080; # 靜態資源走8080端口
 }

 # ssr服務
 location  = /index_ssr {
    proxy_pass http://localhost:8888; # ssr服務使用8888端口
 }

只保留/index_ssr作為SSR渲染的入口,然后在server.js中,將/index_ssr處理成首頁的路徑,并添加對SSR渲染的容錯邏輯,代碼如下:

  if (req.originalUrl === '/index_ssr' || req.originalUrl === '/index_ssr/') {
   context.url = '/'
 }
 ...
 renderer(bundle, manifest).renderToString(context, (err, html) => {
   ...
   if (err) {
     // 發現報錯,直接走客戶端渲染
     res.redirect('/')
     // 記錄錯誤信息 這部分內容可以上傳到日志平臺 便于統計
     console.error(`error during render : ${req.url}`)
     console.error(err)
   }
   ...
 })

針對服務端渲染的容錯機制,不限于使用上面介紹的方案,也可以自行根據實際場景來解決。

PWA和SSR的集成

由于本項目使用到了PWA技術,這樣在集成時需要注意PWA相關的代碼和插件只需要在entry-client.js入口的邏輯中添加即可,SSR服務端是不需要配置PWA相關的邏輯,例如之前的OfflinePlugin插件,在vue.config.js做如下配置:

if (TARGET_NODE) {
 plugins.push(new VueSSRServerPlugin())
} else {
 plugins.push(new VueSSRClientPlugin())

 plugins.push(new OfflinePlugin({
     // 要求觸發ServiceWorker事件回調
     ServiceWorker: {
       events: true,
       // push事件邏輯寫在另外一個文件里面
       entry: './public/sw-push.js'
     },
     // 更更新策略選擇全部更新
     updateStrategy: 'all',
     // 除去一些不需要緩存的文件
     excludes: ['**/*.map', '**/*.svg', '**/*.png', '**/*.jpg', '**/sw-push.js', '**/sw-my.js','**/*.json'],

     // 添加index.html的更新
     rewrites (asset) {
       if (asset.indexOf('index.html') > -1) {
         return './index.html'
       }

       return asset
     }
   }))
}

“怎么改造Vue SSR服務端渲染”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

韩城市| 兴海县| 芦山县| 延津县| 盖州市| 汨罗市| 河津市| 泰和县| 修武县| 射阳县| 治多县| 平度市| 盐池县| 宁德市| 正宁县| 监利县| 安西县| 通榆县| 崇文区| 巢湖市| 加查县| 江华| 永和县| 高青县| 宁津县| 中方县| 北海市| 光山县| 长沙县| 抚州市| 洞头县| 留坝县| 仁怀市| 筠连县| 龙口市| 阿克| 广河县| 福海县| 昌都县| 吴川市| 巩留县|