摘要:之前我們著力于通過代碼樣式規(guī)范以及重構(gòu)等手段協(xié)同工作,而保障代碼質(zhì)量,但是還是會有很多的錯誤悄悄從眼皮底下溜走,被提交進入到代碼庫里。我們老的還有個問題就是沒有單元測試,這點就好像代碼上線前不進行單元測試一樣不靠譜。
原文地址
本文從屬于筆者的Web 前端入門與最佳實踐
在Facebook里,上千名工程師工作在不同的產(chǎn)品線上,為全世界的用戶提供可靠優(yōu)質(zhì)的服務(wù),而我們在代碼質(zhì)量管理方面也面臨著獨一無二的挑戰(zhàn)。不僅僅是因為我們面對的是一個龐大的代碼基庫,還有日漸增加的各種各樣的特性,有時候如果你想去重構(gòu)提高某一個模塊,往往會影響到其他很多模塊。具體在CSS而言,我們需要處理上千份不停變化的CSS文件。之前我們著力于通過Code Review、代碼樣式規(guī)范以及重構(gòu)等手段協(xié)同工作,而保障代碼質(zhì)量,但是還是會有很多的錯誤悄悄從眼皮底下溜走,被提交進入到代碼庫里。我們一直用自建的CSS Linter來檢測基本的代碼錯誤與保證一致的編碼風(fēng)格,盡管它基本上已經(jīng)滿足了我們的目標(biāo),但還是存在很多的問題,因此我也想在這篇文章里對如何保障CSS的代碼質(zhì)量進行一些討論。
Regex is not Enough:之前用的是正則匹配,不咋的啊老的Linter主要是基于很多個正則表達式對CSS中的語法進行提取,大概是這個樣子的:
preg_match_all( // This pattern matches [attr] selectors with no preceding selector. "http://*.*?*/|{[^}]*}|s([[^]]+])/s", $data, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE); foreach ($matches as $match) { if (isset($match[1])) { raiseError(...); }
基本上一個檢測規(guī)則就需要添加一個專門的匹配規(guī)則,非常不好維護,在性能上也有很大的問題。對于每個規(guī)則俺們都需要遍歷整個文件,性能差得很。
Abstract Syntax Tree受夠了正則表達式,我們想搞一個更好用的也是更細致的CSS解釋器。CSS本身也是一門語言,老把它當(dāng)做純文本文件處理也不好,因此我們打算用AST,即抽象語法樹的方式構(gòu)建一個解析器。這種新的處理方式在性能上面有個很不錯的提升,譬如我們的代碼庫中有這么一段CSS代碼:
{ display: none: background-color: #8B1D3; padding: 10px,10px,0,0; opacity: 1.0f; }
眼神好的估計才能看出這個代碼片段中存在的問題,譬如某個屬性名錯了、十六進制的顏色代碼寫錯的,分隔符寫錯了等等。瀏覽器才不會主動給你報錯呢,這樣開發(fā)者自己也就很難找到錯誤了。在具體實現(xiàn)上,我們發(fā)現(xiàn)PostCSS 是個不錯的工具,因此我們選擇了Stylelint作為我們新的Linter工具,它是基于PostCSS構(gòu)建的,非常的靈活,社區(qū)也不錯。
就像JavaScript中的Esprima以及ESLint一樣,Stylelint提供了對于完整的AST的訪問方式,能夠讓你根據(jù)不同的情況更快速簡單的訪問具體的代碼節(jié)點,譬如現(xiàn)在我們的檢測規(guī)則寫成了這個樣子:
root.walkDecls(node => { if (node.prop === "text-transform" && node.value === "uppercase") { report({ ... }); } });
我們也可以傳入一些基本的函數(shù),譬如linear-gradient,就像這個樣子:
// disallow things like linear-gradient(top, blue, green) w. incorrect first valueroot.walkDecls(node => { const parsedValue = styleParser(node.value); parsedValue.walk(valueNode => { if (valueNode.type === "function" && valueNode.value === "linear-gradient") { const firstValueInGradient = styleParser.stringify(valueNode.nodes[0]); if (disallowedFirstValuesInGradient.indexOf(firstValueInGradient) > -1) { report({ ... }); } } }); });
這樣子寫出來的檢測規(guī)則可讀性更好,也更好去理解與維護,并且這種方式無論是在怎樣的CSS格式化的情況下,以及不管規(guī)則和聲明放在哪邊,都能正常地工作。
Custom rules:自定義規(guī)則我們默認使用了一些Stylelint內(nèi)置的規(guī)則,譬如declaration-no-important,selector-no-universal, 以及 selector-class-pattern。如何添加自定義規(guī)則的方法可以參考built-in plugin mechanism,而我們使用的譬如:
slow-css-properties 來告警一些性能較差的屬性,譬如opacity或者box-shadow
filters-with-svg-files 來告警Edge中不支持SVG的過濾
use-variables來告警那些可以被內(nèi)置的常量替換的一些變量
common-properties-whitelist 來檢測是否有些誤寫的其實不存在的屬性
mobile-flexbox 來檢測一些不被老版本手機瀏覽器支持的屬性
text-transform-uppercase 來告警 "text-transform: uppercase",這個在某些語言表現(xiàn)的不友好
我們也貢獻了部分規(guī)則 以及 ad插件itions 給Stylelint。
Automatic replacement:自動替換我們檢測過程中有一個重要的工作就是自動格式化,Linter會在發(fā)現(xiàn)某些問題的時候問你是否需要根據(jù)規(guī)則進行替換,這個功能會節(jié)約你大量的手動修改校正的時間。一般來說,我們提交代碼之前都會審視下Linter報出的錯誤,然后去修復(fù)這些錯誤。可惜的是Stylelint并沒有內(nèi)嵌的自動格式化與修復(fù)機制,因此我們重寫了部分的Stylelint的規(guī)則來增加一個自動替換與修復(fù)的功能。
Test all the things我們老的Linter還有個問題就是沒有單元測試,這點就好像代碼上線前不進行單元測試一樣不靠譜。我們面對的可能是任意格式的處理文本,因此我們也要保證我們的檢測規(guī)則能夠適用于真實有效的環(huán)境,這里我們是選擇了Jest這個測試框架,Stylelint對它的支持挺好的,然后大概一個單元測試是這個樣子:
test.ok("div { background-image: linear-gradient( 0deg, blue, green 40%, red ); }", "linear gradient with valid syntax"); test.notOk("a { background: linear-gradient(top, blue, green); }", message, "linear-gradient with invalid syntax");What‘s next
換一個靠譜的CSS Linter工具只是保證高質(zhì)量的CSS的代碼的第一步,我們還打算添加很多自定義的檢測規(guī)則來捕獲一些常見的錯誤,保證使用規(guī)定的最佳實踐以及統(tǒng)一代碼約定規(guī)范。我們已經(jīng)在JavaScript的校驗中進行了這一工作。
另外對于React社區(qū)中存在的CSS-in-JS這種寫法,對于CSS Linter也是個不小的挑戰(zhàn),現(xiàn)在的大部分的Linter都是著眼于處理傳統(tǒng)的CSS文件,以后會添加對于JSX的處理規(guī)范吧。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/115304.html
摘要:整個系統(tǒng)變得日益繁復(fù),人們也會去選擇使用一些預(yù)處理器或者后處理器來管理這種復(fù)雜性。的預(yù)處理器或者語言的擴展會在無聲無息之間提供類似于變量以及繼承這些特性。最主要的兩個的預(yù)處理器就是與。 本文的 Github Repo本文翻譯自 FreeCodeCamp 的 from-zero-to-front-end-hero-part。本文的第二部分:這里 譯者的廢話,不感興趣的直接忽略 前兩天才翻...
摘要:一般來說,聲明式編程關(guān)注于發(fā)生了啥,而命令式則同時關(guān)注與咋發(fā)生的。聲明式編程可以較好地解決這個問題,剛才提到的比較麻煩的元素選擇這個動作可以交托給框架或者庫區(qū)處理,這樣就能讓開發(fā)者專注于發(fā)生了啥,這里推薦一波與。 本文翻譯自FreeCodeCamp的from-zero-to-front-end-hero-part。 繼續(xù)譯者的廢話,這篇文章是前端攻略-從路人甲到英雄無敵的下半部分,在...
摘要:如果你正在尋找編程技巧,或是想了解編程界發(fā)生了哪些新鮮事那么,今天我們帶來的年最佳開發(fā)者博客列表,一定是你的菜。地址它是為數(shù)不多的印度開發(fā)者博客中,能夠提供有價值信息的博客。地址又一個專注前端開發(fā)的博客。 如果你正在尋找編程技巧,或是想了解編程界發(fā)生了哪些新鮮事?那么,今天我們帶來的 2019 年最佳開發(fā)者博客列表,一定是你的菜。這些博客將會幫助你發(fā)現(xiàn)新的工具,并帶給你編程技巧的啟發(fā)。...
摘要:如果你正在尋找編程技巧,或是想了解編程界發(fā)生了哪些新鮮事那么,今天我們帶來的年最佳開發(fā)者博客列表,一定是你的菜。地址它是為數(shù)不多的印度開發(fā)者博客中,能夠提供有價值信息的博客。地址又一個專注前端開發(fā)的博客。 如果你正在尋找編程技巧,或是想了解編程界發(fā)生了哪些新鮮事?那么,今天我們帶來的 2019 年最佳開發(fā)者博客列表,一定是你的菜。這些博客將會幫助你發(fā)現(xiàn)新的工具,并帶給你編程技巧的啟發(fā)。...
閱讀 3650·2021-10-12 10:11
閱讀 1013·2021-09-22 15:42
閱讀 3465·2019-08-30 13:06
閱讀 906·2019-08-29 17:05
閱讀 1650·2019-08-29 12:21
閱讀 2377·2019-08-29 11:31
閱讀 1135·2019-08-23 18:37
閱讀 1257·2019-08-23 14:58