AC 2017實錄(一)
第二次來Alloy Team的Conference了,依舊是乾貨滿滿。感謝老師們的精彩分享,下次再來就不是學生票了。從大二就開始追隨著大牛們的腳步,依然還是那句話:Be a warrior not a worrior。
0x001 開場
一如既往的小姐姐熱舞,主辦方致辭。大佬還小心機的打了個廣告。
AC大會:團隊成員的年度總結
TFC大會:業界邀請與分享
0x002 面向億萬級用戶的Web同構直出
其實我覺得,把分享主題改成 」如何把React項目改造成SSR 「比較容易懂(逃
需求
- 首屏測速不理想
- SEO優化不足
直出
非直出:Node伺服器返回Html頁面給瀏覽器,瀏覽器通過Ajax向伺服器請求數據,瀏覽器將數據渲染到頁面
直出:Node伺服器請求後台數據, 把數據渲染到頁面後直接返回給用戶
註:直出不一定比不直出快,但一般體驗要比不直出好(不會出現頁面載入出空白數據的問題)
同構
客戶端和服務端共享部分代碼,不需要完全重寫視圖邏輯
原理
ReactDOMServer.renderToString ==> virtual DOM ==> HTML
ReactDOM.render ==> virtual DOM ==> DOM
React在內存中維護了一個虛擬DOM樹。在我們平時使用時(瀏覽器端渲染),React將虛擬DOM翻譯成DOM節點插入Document。而直出則是在伺服器端,將虛擬DOM翻譯成HTML字元串,返回給用戶。因此在編譯時根據執行環境調用renderToString/render介面就行了。
難點
DOM一致性(React)
服務端 - 渲染組件
ReactDOMServer.renderToString(<Main />)
渲染後生成的div
// data-react-checksum 是用來檢驗一致性的標識符<div data-reactroot data-reactid="1" data-react-checksum="xxx">...</div>
將生成後的div
插入HTML中
<html> <head> </head> <body> <div id="root"> <div data-reactroot data-reactid="1" data-react-checksum="xxx"> ... </div> </div> </body></html>
瀏覽器接收到HTML,進行渲染,與此同時前端的React渲染執行
ReactDOM.render(<Main />, document.getElementById("root"))
將HTML生成的DOM和React生成的虛擬DOM對比,校驗checksum是否相同
- 如果相同則綁定事件,進行接下來的操作
- 如果不相同,則進行diff並更新DOM,然後綁定事件進行接下來的操作
Data一致性(Redux)
要解決這個問題,主要是保證Node渲染的HTML中Store里的數據和瀏覽器內執行Redux的數據一樣
在服務端可以將這樣的標籤嵌入HTML
<script> window.__INITIAL_STATE=JSON.stringfy(store.getState())</script>
在瀏覽器中獲取服務端嵌入的Store中的數據
const sotre = createStore(reducers, window.__INITIAL_STATE)ReactDOM.render( <Provider store={store}> <Main /> </Provider>)
Route一致性
使用正則匹配路由,解析到不同的組件,轉為String填充在HTML中
const vm = require(vm)// http://buluo.qq.com/a.html ==> a組件let page = //([^.,^/]+).html/.exec(url)[1]
還有一些小技巧
有些代碼不能在Node執行
- 打標記,通過loader區別對待
_BROWSER_require(xxx.less)import xxx.gif_END_
- 替換方法名稱
ajax ==> window.ajax// 瀏覽器使用ajax,node使用http.request
首屏的action往往不需要那麼多,可以提取幾個需要的單獨寫在一個文件里
// firstAction.jsimport {todo1, todo2} from ./actionsexport default () => async(dispatch) => { await Promise.all([ dispatch(todo1()), dispatch(todo2()) ])}
直出的邏輯
打包的邏輯
打包需要生成直出和非直出的兩份代碼
開發調試
本地調試工具
大佬本來提供了一個叫做fireDragon的工具,但是我在GIthub上搜索了一下,發現沒有什麼內容。感覺應該是涉及到一些公司內部的東西,暫時下架整改了吧。還是把使用方法貼出來。
tnpm link // 鵝廠的NPM包管理firedragon init // 初始化配置firedragon // 運行
調試流程
自動化測試
這裡大佬採用的是github中push的鉤子,在push之前會先執行一個動作。這個動作主要使用mocha、chai做自動化檢測。如果通過的話就可以成功push上去了。
可用性保障
柔性處理
在伺服器收到請求後,Nginx會首先檢測Node伺服器的負載和內存狀態,如果無法處理請求,則會轉到靜態HTML流程。
降級處理
在編譯報錯,或者服務不可達的狀態下(5xx),Nginx會自動將不可達的服務代理到靜態的HTML流程上去。
server { listen 80; server_name xxx; location ^~ /mobile/ { proxy_pass http://static_env; } location ^~ /mobile/v2/ { proxy_pass http://nodejs_env; proxy_intercept_errors on; error_page 403 404 408 500 501 502 503 504 =200 @static_page; } location @static_page { rewrite_log on; error_log logs/rewrite.log notice; rewrite /mobile/v2/(.*)$ /mobile/$1 last; }}
壓測處理
這裡大佬給自家WeTest壓測平台打了個廣告。我們主要關注以下幾個指標就可以了:
- 響應時間
- TPS(找到服務規模的最優值)
- 伺服器性能(可以找到瓶頸:如內存泄露等)
灰度測試
為了防止Node伺服器爆炸,大佬選擇了控制一部分用戶走SSR,通過伺服器監控保障伺服器可用性。如果伺服器壓力較大,就放棄一部分SSR,轉向直接返回靜態HTML。
同構的弊端
- 減輕了瀏覽器的消耗,但是加大了伺服器的消耗,伺服器比原來多4倍
- 加大Node的IO和計算壓力
0x002 大型Web項目可用性提升
這個標題也很高大上呢,按照我的理解應該是,如何發現線上代碼的BUG(逃
糾錯流程
- 代碼監控
- 數據上報
- 數據處理
代碼監控
- try-catch
一般來說,意料之內的報錯都會用try-catch捕獲,但是它有一個致命的問題,沒法捕獲非同步錯誤
try { setTimeout(function(){ test // 非同步錯誤 }, 0)}catch(err){ console.log(error)}
- window.onerror
/** * @param {String} errorMessage 錯誤信息 * @param {String} scriptURI 出錯的文件 * @param {Long} lineNumber 出錯代碼的行號 * @param {Long} columnNumber 出錯代碼的列號 * @param {Object} errorObj 錯誤的詳細信息,Anything */window.onerror = function(errorMessage, scriptURI, lineNumber,columnNumber,errorObj) { // TODO}
可以捕獲到錯誤的message,url等等,一般用來捕獲意料之外的錯誤
錯誤上報
- ajax:缺點是不一定能夠上傳上去
- img的src:缺點是長度有限制,需要手動限制長度
監控服務
- 編寫介面,接收用戶請求
- 將報錯信息存儲進資料庫
- 統計分析
錯誤信息
同源策略
有些錯誤信息上傳上來只顯示script error 卻沒有具體的錯誤內容。這是瀏覽器的非同源策略導致的。解決這個問題我們可以有兩種方法
同域化:
- 外聯同域
- 灰度同域
CORS機制:
我們可以在script標籤中添加cross origin 屬性
<script crossorgin></script>
或者是在請求頭中添加兩行設置
Access-Control-Allow-Origin: http:a.comVary: Origin // 緩存
壓縮代碼查錯困難
這裡大佬採用了sourcemap,sourcemap是在代碼壓縮時生成的映射文件,我們可以通過sourcemap查找壓縮後代碼對應原來代碼的哪個句子。
比如,你有一個壓縮後的代碼文件jquery.min.js,你只需要在最後一行添加註釋信息,指定它soucemap的地址,然後在瀏覽器運行就可以了。
//@ sourceMappingURL=jquery.min.map
開源方案
Sentry是一個錯誤監控平台。可以幫助我們從報錯中提取發掘異常。
它分為客戶端和服務端兩部分,客戶端就嵌入在網頁中,程序出現異常就向服務端發送消息。服務端將消息記錄到資料庫中並提供一個頁面進行分析和統計。
應對流量劫持
大佬發現他的頁面被劫持了,因此採取了以下幾種方案。
上報白名單之外的資源
通過onload事件,對載入的src進行檢驗,只上報白名單之外的資源。
document.addEventListener(load, function(e) { if (...) { report(e.target) }}, true)
上報白名單之外的資源
通過onload事件,對載入的src進行檢驗,只上報白名單之外的資源。
document.addEventListener(load, function(e) { if (...) { report(e.target) }}, true)
CSP內容安全策略
使用HTML Meta標籤
<meta http-equiv="Content-Security-Policy" content="script-src self"></meta>
使用HTTP Header
Content-Security-Policy: script-src self *.qq.com *.url.cn// 直接組織Content-Security-Policy-Report-Only: script-src self *.qq.com *.url.cn// 只上報不阻止
使用HTTPs
開發時檢錯
這裡大佬編寫了一個開發報錯的插件 ,提供了及時、可視化的報錯。提示的報錯信息有:
- 報錯位置
- 基礎報錯(UA、客戶端類型等)
報錯位置使用sourcemap查詢,在star大佬的github的時候,看到了大佬寫的sourcemap示例。我們可以這樣根據原代碼、壓縮之後的代碼生成sourcemap:
import { generator } from js-sourcemap;// use cdn, window.js_sourcemap.generatorvar src = `function test(){console.log("js-sourcemap")};`;var dist = `function test(){ console.log(js-sourcemap)}`var sourcemap = generator(src, dist);console.log(sourcemap);
然後這樣根據sourcemap查找源代碼的行數:
import { consumer } from js-sourcemap;// use cdn, window.js_sourcemap.consumervar smConsumer = consumer(sourcemap);// get generated loc by original positionvar loc = smConsumer.getGenerated({ line: lineNum, column: columnNum})// get original loc by generated positionvar loc2 = smConsumer.getOriginal({ line: lineNum2, column: columnNum2})
結束
最後,大佬將來展示了將來的開發規劃:
- 在uglify的plugin中自動捕獲錯誤並上報
- 使用babel AST解析上報錯誤
0x003 如何構建後現代化的工程化開發體系
開發體系的構成
一個開發體系應該包括開發環境、生產環境以及他們之間的銜接。
Steamerjs
Steamerjs是Alloy Team提供的工程化工具。由模板引擎和命令行構成,模板引擎用來生成react、vue、angular等項目的腳手架,命令行則用來在不同場景下執行構建、編譯等命令。
我們可以通過即裝即用的插件形式安裝
npm i -g steamerjsnpm i -g steamer-plugin-kitnpm i -g steamer-react
然後我們可以通過命令生成項目
steamer kit
基於模板生成頁面
steamer kit react-mobx
更新腳手架
steamer kit -u
開發環境 - 腳手架與命令行
要考慮的五大因素
- 快速部署與更新
- 團隊約定
- 快速配置
- 頁面性能
- 構建性能
開發環境 - 組件化
在項目內組建開發的流程是:
- 無腳手架進行開發
- 複製使用
- 手寫demo和api文檔
跨項目的組件開發則需要更加規範、自動和專業:
- 組件開發(目錄、命令、測試、打包方式)
- 組件展示(example和demo)
- 通過npm發布
開發環境 - 介面聯調
- postman 定義數據結構
- http://easys-mock.com 假數據測試
- steamer-plugin-mock 記錄介面文檔
生產開發銜接 - 數據上報
- 百度統計 / 谷歌統計 (產品數據)
- wetest (性能數據)
- http://sentry.io (報錯)
生產開發銜接 - 持續集成
開源項目: Github + Travis-CI
私有項目:Bitbucket + Pipeline / Gitlab + Pipeline
生產開發銜接 - 代碼規範
通過Pre-Commit添加Hook進行檢查
JavaScript(ESLint) + CSS(StyleLint)
發布上線
靜態資源:cos + cdn
- webhook
- git
- cos script
動態資源:cvm
上半場結束,午餐茶歇。下半場請移步AC 2017實錄(二)
推薦閱讀:
※前端日刊-2018.02.10
※css垂直居中整理
※前端日刊-2018.02.24
※React填坑記(四):render !== hydrate
TAG:前端開發 |