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