組件系統之SSR動態渲染——DEMO版

2021-02-16 VK前端

為什麼要寫這篇文章呢?因為給團隊的同學提了要求,要有思考,設計和產出。很多時候技術實現都是一個idea,想到就搞了,搞了之後又覺得如此簡單,如此簡單還回顧它做什麼呢?其實不然,每一個方案的落地,可能都是N個想法相互拼殺的結果。

團隊維護了一個Landing Page系統,準備將這個系統平臺化,平臺化就需要具備組件的多元化的能力,這樣才能夠適應更多的場景,滿足更多的用戶。

目前的所有組件都是標準組件,包含在整個Landing Page平臺中;所以頁面的首屏、SEO和性能完全可以基於同構策略去實現。

基於目前的同構策略,csr和ssr都用的是同一份代碼,那如果要引入自定義組件,就會涉及到重新編譯。那麼將面臨如下兩個問題1、自定義組件將會越來越多,如果每次都重新編譯,代碼會越來越大。

2、自定義組件發布了不能立即使用,需要重新發布Landing Page的服務。

首先最容易想到的解決方案,是動態組件,但是動態組件不能很好的支持seo和首屏,所以這個idea在腦袋中過了三秒就pass了。

然後想想SSR和CSR的能夠保持一致的本質是虛擬dom計算的結果是一致的,那麼要保證結果一致,就一定要保證服務端代碼和客戶端代碼是一致的嗎?答案是是否定的。

下面我們來看一下,通過build以後的client和server的代碼結構(基於nuxt腳手架)

顯而易見client和server的js代碼完全是不一樣的,client由於要考慮按需和文件大小的問題將項目的js文件按照一定規則拆成了若干份,但是server端則將所有內容都打包進了server.js。

所以可以得到一個簡單的結論,我們可以將客戶端的代碼按照自己的想法,拆成一份份的,那如果我們把所有的自定義組件當成一份文件或者幾分文件不就ok了嗎?

具體實現:

1、將組件庫通過webpack打包成若干個文件,並根據commonjs2和iife原則分別打包成兩份,配置如下

commonjs配置

const path = require('path');const ProgressBarPlugin = require('progress-bar-webpack-plugin');const VueLoaderPlugin = require('vue-loader/lib/plugin');
const webpackConfig = { mode: 'production', devtool: false, entry: { 'comp1': './comp1.js', 'comp2': './comp2.js', 'comp3': './comp3.js', }, output: { path: path.resolve(process.cwd(), './lib'), publicPath: '/dist/', filename: '[name].js', libraryTarget: 'commonjs2' }, resolve: { extensions: ['.js', '.vue', '.json'], modules: ['node_modules'] }, performance: { hints: false }, stats: 'none', optimization: { minimize: false }, module: { rules: [ { test: /\.(jsx?|babel|es6)$/, include: process.cwd(), loader: 'babel-loader' }, { test: /\.vue$/, loader: 'vue-loader' }, { test: /\.(svg|otf|ttf|woff2?|eot|gif|png|jpe?g)(\?\S*)?$/, loader: 'url-loader' } ] }, plugins: [ new ProgressBarPlugin(), new VueLoaderPlugin() ]};
module.exports = webpackConfig;

iife配置

const path = require('path');const ProgressBarPlugin = require('progress-bar-webpack-plugin');const VueLoaderPlugin = require('vue-loader/lib/plugin');
const webpackConfig = { mode: 'production', devtool: false, entry: { 'comp1': './comp1.js', 'comp2': './comp2.js', 'comp3': './comp3.js' }, output: { path: path.resolve(process.cwd(), './lib'), publicPath: '/dist/', filename: '[name].iife.js', iife: true }, resolve: { extensions: ['.js', '.vue', '.json'], modules: ['node_modules'] }, performance: { hints: false }, stats: 'none', optimization: { minimize: false }, module: { rules: [ { test: /\.(jsx?)$/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'], plugins: ['@vue/babel-plugin-transform-vue-jsx'] } } }, { test: /\.vue$/, loader: 'vue-loader' }, { test: /\.(svg|otf|ttf|woff2?|eot|gif|png|jpe?g)(\?\S*)?$/, loader: 'url-loader' } ] }, plugins: [ new ProgressBarPlugin(), new VueLoaderPlugin() ]};
module.exports = webpackConfig;

import comp from './comp1.vue';
function regiseterComp(vue) { vue.component('comp1', comp);}
if (typeof window !== 'undefined') { window.dynamicCompFuncList = window.dynamicCompFuncList || []; window.dynamicCompFuncList.push(regiseterComp);}
export default regiseterComp;

1、由於在客戶端中,我們需要擇機觸發組件的註冊;

所以我們需要將組件組冊緩存起來,找一個合適的時機觸發。

2、將自定義組件引入代碼邏輯中,保證客戶端和服務端正確的渲染邏輯 (得益於webpack的打包邏輯,打包的client的時候,執行不到的引用不會被打包)

module.exports = function (vue) { if (process.server) {  const comp1 = require('../../dynamic-comp/lib/comp1.js').default;  const comp2 = require('../../dynamic-comp/lib/comp2.js').default;  const comp3 = require('../../dynamic-comp/lib/comp3.js').default;  comp1(vue);  comp2(vue);  comp3(vue); } else {  if (window.dynamicCompFuncList) {   window.dynamicCompFuncList.forEach((fn) => {    fn(vue);   });  } }};

3、保證客戶端的正確渲染結果,需要將動態組件庫優先加載,才能通過 window.dynamicCompFuncList獲取到,並在客戶端渲染前註冊需要的組件。

最簡單的辦法就是將script內置到head裡,nuxt的中間件可以很容易地做到這件事情

項目跑起來,想要的結果就實現了,這樣的實踐也產生了一些問題,需要再做一些優化:

1、內嵌script容易造成頁面html內容很多,不利於網絡傳輸;

2、動態計算需要的自定義組件依賴(這個需要別的平臺提供能力來配合實現);

3、實時獲取自定義組件,或者通過mq獲取新增組件,動態改變服務端渲染的自定義入口文件(服務端公用一個vue實例,需要重新啟動);

相關焦點

  • 虛幻引擎學習之路:渲染模塊之材質系統
    上周的Unreal 4引擎文章介紹了渲染模塊的光照系統,在本篇文章中,我們繼續介紹渲染模塊的另一重要部分:材質系統。
  • 漫談Android組件化及Web化
    相信大家都經常遇到產品的某些需求要緊急上線的情況,但是App不同於H5開發那樣可以隨時發版,需要經過眾多的渠道進行發布,而如果能夠做到動態發版,對整個產品的演進和動態開發都會有比較好的推進作用。另外減少包體積同樣也很重要,一般同個App,iOS的包體積會比Android的更大,這是由於iOS無法進行本地代碼的動態下發,而國內的安卓渠道審核相對比較松一些。
  • Vulkan - 高性能渲染
    循環的最外層,通常每一幀都會有好幾個render pass,例如shadow map和gbuffer的渲染,光照以及各種後處理等。每個pass都有需要設定特定的管線狀態,例如blending,depth,raster的狀態等等。在下面幾層循環中通暢需要遍歷所有的shader和著色系統需要的材質參數,如紋理,常量等等。
  • Vue.js:輕量高效的前端組件化方案
    </div> 在渲染的同時,Vue.js也已經完成了數據的動態綁定:此時如果改動data.msg的值,DOM將自動更新。是不是非常簡單易懂呢?除此之外,Vue.js對自定義指令、過濾器的API也做了大幅的簡化,如果你有Angular的開發經驗,上手會非常迅速。
  • Unity3D研究院之動態解析度降低渲染開銷
    需要注意的是動態解析度安卓Android(僅適用於Vulkan) 或者也可以用SRP可編程渲染管線,最後在修改RT這樣就都支持了。Screen.currentResolution.width); int rezHeight = (int)Mathf.Ceil(ScalableBufferManager.heightScaleFactor * Screen.currentResolution.height); screenText.text = string.Format("Scale: {0:F3}x{1:F3}\n動態解析度
  • 虛幻引擎學習之路:渲染模塊之全局光照明
    之前UWA為大家分別介紹了Unreal 4引擎中渲染模塊的光照系統、材質系統和相機圖像後處理
  • 2018 年值得嘗試的11 個 React 組件庫
    React 組件庫,其中有一些已經十分流行,也有一些是新出現的庫。使用 React 的另一個重要原因是組件。組件讓你把用戶界面分成獨立的,可重複使用的部分,並且將每個部分分開考慮。以下推薦 11 個可考慮在後續應用中使用的優秀 React 組件庫,其中有一些已經十分流行,也有一些是新出現的庫。希望能對大家有所幫助。
  • 最好用的SketchUp組件庫(模型庫)- SUMOD
    SketchUp 7.0 增加的動態組件功能就是開發團隊針對於此的一大嘗試。這個功能是 SketchUp 邁向參數化的重要開端。不過由於動態組件製作的局限和難度,國內外對此功能的應用至今依舊差強人意。
  • Facebook:Avatar VR頭像系統已經可以模擬全身
    ,該系統基於容積攝影等3D動捕技術,可在AR/VR中動態渲染高度還原的面部表情和特徵,與真人樣貌十分接近。前不久,青亭網報導了Facebook在毛髮渲染上的最新成果,已經可以對頭髮進行3D建模,細緻到可渲染一縷髮絲。除此之外,近期Facebook也公布了一項基於容積捕捉的動態全身虛擬形象方案:可感知驅動信號的全身動態虛擬形象系統。其特點是採用一個根據條件變化的自動編碼模型,可以將姿態、面部關鍵點等不完整的驅動信號轉化成動畫數據,生動且逼真的體現人體結構和動態外觀變化。
  • 圖解 SpringMVC 五大組件
    SpringMVC最重要的就是五大組件下面一一介紹這五大控制項1.DispatcherServlet這個控制項是SpringMVC 最核心的一個控制項,顧名思義其實他就是一個Servlet,是SpringViewResolver視圖解析器明確了視圖名與視圖對象的關係,是調用demo.jsp還是調用demo.html,以及明確視圖的位置五大組件的關係
  • Python快速生成web動態展示機器學習項目
    Streamlit一句話,Streamlit是一個可以用python編寫web app的庫,可以方便的動態展示你的機器學習的項目。優點你不需要懂html, css, js等,純python語言編寫web app包括web常用組件:文本框, 按鈕,單選框,複選框, 下拉框,多媒體(圖片,視頻)和文件上傳等應用場景可以方便動態展示你的機器學習成果(可以和jupyter notebook做個比較)https
  • 三維仿真訓練系統
    學員們在安全可控的狀態,重複使用和測試場景,並提高他們處理危機情況的能力平臺特點:實時逼真渲染「開箱即用」的AAA級視覺效果。GVR引擎基於物理的渲染技術、高級動態陰影選項、光線追蹤功能、屏幕空間反射以及光照通道等強大功能將幫助您靈活而高效地製作出令人讚嘆的內容。
  • Unity高級知識點總結:性能優化與圖形渲染進階
    比如lua中獲取一個組件,可以用組件Type作為參數傳遞,而不是組件名。7、注意字符串比較時的參數傳遞。一般都是Ordinal。使用Culture的參數會考慮國際化因素,性能較低。同理,可以實現一個 StartWithFast,簡單進行字符比對。它會比C#默認的StartWith快很多。
  • Enlighten引擎Demo演示第二彈 完美支持PS4打造深度動態光照
    昨日相信大家都已經看過了Enlighten引擎的渲染Demo。不過昨日的Demo演示應該是第一部分,因為現在外媒公布了最新的Enlighten引擎渲染視頻。如果昨日還沒有盡興,那就再看看Enlighten引擎技術Demo的第二部分吧。
  • Unity可編程渲染管線系列(二)自定義著色器(HLSL和核心庫)
    4、支持動態批處理和GPU實例這是涵蓋Unity的可腳本化渲染管線的教程系列的第二部分。雖然GLSL用於默認著色器以及「渲染2,著色器基礎知識」(Shader Fundamentals),但Unity的新渲染管線著色器使用HLSL,因此我們也將其用於管線。這意味著我們必須將所有代碼放在HLSLPROGRAM和ENDHLSL語句之間。
  • 【3dsmax2021破解版】中文破解版下載與安裝方法
    全世界只有不到3 % 的人關注了 weirdo科技你真的真的很了不起【3dsmax2021破解版】中文破解版 安裝教程 下載軟體回覆:3dmax軟體集突出特點1、基於PC系統的低配置要求 2、安裝插件(plugins)可提供3D Studio Max所沒有的功能(比如說3DS Max 6版本以前不提供毛髮功能)以及增強原本的功能 ;3、強大的角色(Character)動畫製作能力 ;4、可堆疊的建模步驟,使製作模型有非常大的彈性軟體應用