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編譯服務, 而後返回內容給後端框架, 這裏涉及兩個應用通訊. 以下:javascript

<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 絕對路徑css

<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

  • 最後, 模板渲染完成, 服務器輸出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.項目和插件

相關文章
相關標籤/搜索