Egg React SSR 服務端渲染 Webpack 構建流程

1. 本地Egg項目啓動

  • 首先執行node index.js 或者 npm run dev 啓動 Egg應用
  • 在 Egg Agent 裏面啓動koa服務, 同時在koa服務裏面啓動Webpack編譯服務
  • 掛載Webpack內存文件讀取方法覆蓋本地文件讀取的邏輯
app.react.render = (name, locals, options) => {
   const filePath = path.isAbsolute(name) ? name : path.join(app.config.view.root[0], name);
   const promise = app.webpack.fileSystem.readWebpackMemoryFile(filePath, name);
   return co(function* () {
     const code = yield promise;
     if (!code) {
       throw new Error(`read webpack memory file[${filePath}] content is empty, please check if the file exists`);
     }
     // dynamic execute javascript
     const wrapper = NativeModule.wrap(code);
     vm.runInThisContext(wrapper)(exports, require, module, __filename, __dirname);
     const reactClass = module.exports;
     if (options && options.markup) {
       return Promise.resolve(app.react.renderToStaticMarkup(reactClass, locals));
     }
     return Promise.resolve(app.react.renderToString(reactClass, locals));
   });
};
  • Worker 監聽Webpack編譯狀態, 檢測Webpack 編譯是否完成, 如果未完成, 顯示Webpack 編譯Loading, 如果編譯完成, 自動打開瀏覽器
  • Webpack編譯完成, Agent 發送消息給Worker,  Worker檢測到編譯完成, 自動打開瀏覽器, Egg服務正式可用

2. 本地服務端渲染頁面訪問

  • npm run dev

  • 瀏覽器輸入URL請求地址, 然後 Egg 接收到請求, 然後進入 Controller
  • Node層獲取數據後(Node通過http/rpc方式調用Java後端API數據接口), 進入模板render流程
  • 進入render流程後, 通過worker進程通過調用 app.messenger.sendToAgent 發送文件名給Agent進程, 同時通過 app.messenger.on 啓動監聽監聽agent發送過來的消
  • Agent進程獲取到文件名後, 從Webpack編譯內存裏面獲取文件內容, 然後Agent 通過 agent.messenger.sendToApp 把文件內容發送給Worker進程
  • Worker進程獲取到內容以後, 進行React編譯HTML, 編譯成HTML後, 進入jss/css資源依賴流程
  • 如果啓動代理模式(見easywebpack的setProxy),  HTML直接注入相對路徑的JS/CSS, 如下:

頁面可以直接使用 /public/client/js/vendor.js 相對路徑,  /public/client/js/vendor.js 由後端框架代理轉發到webpack編譯服務, 然後返回內容給後端框架, 這裏涉及兩個應用通信. 如下:

<link rel="stylesheet" href="/public/client/css/home/android/home.css">
<script type="text/javascript" src="/public/client/js/vendor.js"></script>
<script type="text/javascript" src="/public/client/js/home.js"></script>
  • 如果非代理模式(見easywebpack的setProxy),  HTML直接注入必須是絕對路徑的JS/CSS, 如下:

頁面必須使用 http://127.0.0.1:9000/public/client/js/vendor.js 絕對路徑

<link rel="stylesheet" href="http://127.0.0.1:9000/public/client/css/home/android/home.css">
<script type="text/javascript" src="http://127.0.0.1:9000/public/client/js/vendor.js"></script>
<script type="text/javascript" src="http://127.0.0.1:9000/public/client/js/home.js"></script>

其中 http://127.0.0.1:9000 是 Agent裏面啓動的Webpack編譯服務地址, 與Egg應用地址是兩回事

  • 最後, 模板渲染完成, 服務器輸出HTML內容給瀏覽器.

3. 正式環境發佈模式構建流程和運行模式

  • Webpack通過本地構建或者ci直接構建好服務端文件和客戶端資源文件到磁盤
  • Egg render直接讀取本地文件, 然後渲染成 HTML
  • 根據 manfifest.json 文件注入 jss/css資源依賴注入
  • 模板渲染完成, 服務器輸出HTML內容給瀏覽器.

4. 關於 Egg 框架中的 Agent 和 Worker

  • 我們利用本地開發修改Node層代碼修復重啓時, 只會重啓Worker進程, 不會重啓Agent進程, 我們可以在Agent裏面啓動Webpack編譯服務解決Webpack compiler實例問題.
  • 因爲Egg App進程 和 Agent進程是兩個進程, 當url訪問時, 我們通過worker發送消息給agent進程, 獲取服務端渲染的文件內容, 然後Agent再發送消息給Worker解決文件讀取問題.
  • 本地開發webpack熱更新內存存儲讀取和線上應用本機文件讀取邏輯分離功能, 我們通過本地開發模式時, 通過讀取Webpack內存內容覆蓋本地文件讀取的邏輯, 這樣在開發模式和發佈模式可以無縫對接.
  • worker和agent通信機制: https://eggjs.org/zh-cn/core/cluster-and-ipc.html
  • 實現egg項目服務器代碼修改項目自動重啓的功能可以使用egg-development插件.

5.項目和插件

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章