国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

從0到1:PostCSS 插件開發(fā)最佳實踐

nidaye / 1443人閱讀

摘要:單元測試秉承測試驅(qū)動開發(fā)的開發(fā)理念,單元測試的任務(wù)是必不可少的。維護一份按照建議,也將更新歷史等數(shù)據(jù)放在了一個名為文件上,并采用語義化的版本號。

本文原始來源:http://devework.com/postcss-p...。轉(zhuǎn)載請?zhí)峁┰紒碓矗x謝!

前陣子為了滿足工作上的一個需求開發(fā)了一個PostCSS 插件,后來也將這個插件提交給PostCSS 官方并得到認可。在這篇文章中筆者將記錄開發(fā)過程中遇到的一些問題,且斗膽將之稱為“最佳實踐”,希望對有興趣嘗試PostCSS 插件開發(fā)的您有所幫助。

簡介篇 開發(fā)成果展示

首先先上成果:https://github.com/Jeff2Ma/postcss-lazyimagecss (歡迎給個star 哦~)

postcss-lazyimagecss 插件實現(xiàn)的功能是為 CSS 中的background-image 對應(yīng)的圖片自動添加widthheight 屬性。簡單形象化的效果展示如下:

/* Input ./src/index.css */
.icon-close {
    background-image: url(../slice/icon-close.png); //icon-close.png - 16x16
}

.icon-new {
    background-image: url(../slice/icon-new@2x.png); //icon-new@2x.png - 16x16
}

/* Output ./dist/index.css */
.icon-close {
    background-image: url(../slice/icon-close.png);
    width: 16px;
    height: 16px;
}

.icon-new {
    background-image: url(../slice/icon-new@2x.png);
    width: 8px;
    height: 8px;
    background-size: 8px 8px;
}
為什么重復(fù)造一個輪子

開發(fā)這個PostCSS 插件的起因是原先工作流中使用的gulp-lazyimagecss 插件在加入SourceMap 功能后運行不正常,多次嘗試修復(fù)均告失敗。后來筆者想到,PostCSS 本身天然支持SourceMap,那如果將這個功能開發(fā)成PostCSS 插件豈不是也完美支持SourceMap 了?

于是筆者便在gulp-lazyimagecss 的基礎(chǔ)上開發(fā)出了這么一個輪子。在此也感謝原開發(fā)者hzlzh 與littledu 的大力幫助與支持。對筆者而言,更像是站在巨人的肩膀上開發(fā)出來這個插件。

準(zhǔn)備篇 原理

關(guān)于PostCSS 的原理,官方有這么一個圖:

簡單解釋,PostCSS 會將上一步傳入的 CSS 按照一條條樣式規(guī)則(rule)進行解析(Parser)得到一個節(jié)點樹;然后借助一系列插件在節(jié)點樹上進行轉(zhuǎn)換操作,并最終通過Stringifier 進行拼接。source map則記錄了前后的對應(yīng)關(guān)系。

當(dāng)然,在實際的開發(fā)中其實不必深究原理,最重要的是看其提供的API 來調(diào)用即可。

工欲善其事必先利其器

開發(fā)一個PostCSS 插件也是開發(fā)一個Node 模塊,想到后面要發(fā)布到NPM 跟PostCSS 官方,那么作為一個開源項目的可維護性、可擴展性也是很重要的。因此在進入正式的開發(fā)之前,筆者做了如下的工作:

1、配置 editorconfig

editorconfig 作為一套統(tǒng)一代碼格式的解決方案,已經(jīng)在團隊不少項目中使用,其很好地解決了因為團隊協(xié)作中因不同代碼編輯器及不同的代碼習(xí)慣產(chǎn)生的潛在風(fēng)險。這里是最終的配置文件。

2、基礎(chǔ)的開發(fā)工作流

在整個開發(fā)插件過程前,筆者根據(jù)需求配了個基于Gulp 的開發(fā)工作流,主要配備如下功能(任務(wù)):

代碼質(zhì)量監(jiān)控ESlint

優(yōu)秀的開源代碼必然是有著標(biāo)準(zhǔn)化的JavaScript 代碼風(fēng)格,因此在整個開發(fā)過程中借助ESlint 來嚴(yán)格控制自己的代碼質(zhì)量。這里是本項目的ESlint 配置文件。

var eslint = require("gulp-eslint");
gulp.task("lint", function () {
    return gulp.src(files)
        .pipe(eslint())
        .pipe(eslint.format())
        .pipe(eslint.failAfterError());
});

基礎(chǔ)的CSS 轉(zhuǎn)換

這個任務(wù)其實就是本PostCSS 插件實現(xiàn)的功能,之所以在開發(fā)過程中也要配置是為了下面的單元測試任務(wù)的調(diào)用。

單元測試

秉承TDD(測試驅(qū)動開發(fā))的開發(fā)理念,單元測試的任務(wù)是必不可少的。

gulp.task("test", function () {
    return gulp.src("test/*.js", { read: false })
        .pipe(mocha({ timeout: 1000000 }));
}); 

watch 任務(wù)

gulp watch 任務(wù)是上面任務(wù)的集體調(diào)用,實現(xiàn)的功能是在開發(fā)過程中,每當(dāng)按下保存鍵就自動運行ESlint 代碼質(zhì)量監(jiān)控及進行單元測試任務(wù)。有效保障了整個開發(fā)過程中的質(zhì)量。

3、托管到 Github 并配置Travis-ci 持續(xù)集成

整個開發(fā)過程使用Github 托管源代碼并通過Travis-ci 持續(xù)集成。PostCSS 官方建議最低需要支持Node.js 0.12 的版本,所以整個Travis-ci 的配置文件如下:

sudo: false
language: node_js
node_js:
  - "0.12"
  - "4"
  - "5"
  - "6"
  - "stable"
before_script:
  - npm install -g mocha

相應(yīng)的在Travis-ci 管理后臺配置push 操作作為動作鉤子,這樣每次有commit push 上去就會自動進行測試并在log 上展示出結(jié)果:

開發(fā)篇 從最小開始

一個PostCSS 插件最基礎(chǔ)的構(gòu)成如下:

var postcss = require("postcss");
module.exports = postcss.plugin("PLUGIN_NAME", function (opts) {
    opts = opts || {};
    // 傳入配置相關(guān)的代碼
    return function (root, result) {
        // 轉(zhuǎn)化CSS 的功能代碼
    };
});

然后就是不同的需求情況來決定是否引入第三方模塊,是否有額外配置項,然后在包含root,result 的匿名函數(shù)中進行最為核心的轉(zhuǎn)換代碼功能編寫。

root(css),rule, nodes, decl, prop, value

如本文一開頭的PostCSS 原理解析,CSS 文件在經(jīng)過Parser 轉(zhuǎn)化后的遞歸單個子單位可以歸為如下:

root(css) :也是整個CSS 代碼段,包含多個rule。

rule: 包含一個CSS class 范圍內(nèi)的代碼段

.icon-close {
    background-image: url(../slice/icon-close.png);
    font-size: 14px;
}

nodes: 代指rule 中{}中間的多個 decl 部分。

decl: 單行CSS ,即有屬性與值的部分

background-image: url(../slice/icon-close.png);

prop,value

相應(yīng)的CSS 屬性與值,如上面 propbackground-image,valueurl(../slice/icon-close.png)

偽代碼實現(xiàn)

根據(jù)postcss-lazyimagecss 插件要實現(xiàn)的內(nèi)容,涉及到CSS 轉(zhuǎn)化的有如下情景:

增加 width 屬性及獲取到真實值

增加 height 屬性及獲取到真實值

二倍圖情況下增加 background-size 屬性并計算出值

結(jié)合上一小節(jié),可以先寫出如下簡潔版?zhèn)未a:

css.walkRules(function (rule) { // 遍歷所有 CSS
    rule.walkDecls(/^background(-image)?$/, function (decl) { // 遍歷每條 CSS 規(guī)則,找出目標(biāo) rule
        // 一些傳參等代碼
        nodes.forEach(function (node) { // 遍歷其它 rules
            ...
        });

        ... // 其它代碼實現(xiàn),如找出圖片真實width 等

        rule.append({prop: "width", value: valueWidth}); // 在該decl 追加width 屬性
    });
});
細化代碼

接下來就是考慮不同情況增加一些邏輯判斷:

判斷url 中是否為網(wǎng)絡(luò)地址或Base64 的data 形式:imageRegex.exec(value).indexOf("data:")

判斷該rule 下是否已經(jīng)有width 等屬性,在nodes 循環(huán)中:

if (node.prop === "width") {
    CSSWidth = true;
}

判斷2倍圖圖片寬高是否為偶數(shù):

value.indexOf("@2x") > -1 && (info.width % 2 !== 0 || info.height % 2 !== 0

再具體的不再詳述,完整的代碼實現(xiàn)可以見這里。

難點解決

postcss-lazyimagecss 插件使用了第三方模塊fast-image-size 來進行圖片數(shù)據(jù)(文件類型、寬高)的獲取,大大提高了開發(fā)效率。然而在尋找圖片絕對路徑的這個實現(xiàn)上還是繞了不少彎路。

插件的思路是需要獲取CSS 中background-image屬性對應(yīng)值中url()的相對圖片路徑,以此來找到圖片的絕對路徑,之后用fast-image-size 模塊獲取到相應(yīng)的數(shù)據(jù)。

然而在一些特殊情況并不能準(zhǔn)確找到絕對路徑。

在CSS 預(yù)處理器(如Less 或Sass)中,常借助@import來組件化CSS 代碼,然而在層層@import 下路徑可能已經(jīng)被產(chǎn)生變化。舉個例子,有如下結(jié)構(gòu):

.
├── css
├── html
├── img
│?? └── icon.png
└── scss
    ├── index.scss
    └── second
        └── _import.scss

上面的文件樹中展示的 scss/index.scss @import 了二級目錄下的 _import.scss,在_import.scss中有一個類需要用到img/icon.png

因為同時也配置了local server(以上面的./目錄作為server 的根目錄),那么在 url 中可以寫成../../img/icon.png../img/icon.png,甚至寫成../../../../../img/icon.png(N個../)——這些情況下Sass 編譯后的index.css 均可正常讀取。原因相信也知道,因為root url的存在,上面的路徑寫法均相當(dāng)于/img/icon.png

在這個情況下于用戶而言是感受不到錯誤的,但在插件中可就找不到真實絕對路徑了。筆者對于這個情況是采用了如下方式進行解決:

借助Node.js 中的fs.existsSync 函數(shù)檢測絕對路徑對應(yīng)的文件是否存在。第一次為正常fs.existsSync,如果找到就跳出;如果沒有則先對路徑的字符串執(zhí)行replace("../", "");然后再次執(zhí)行fs.existsSync。如果兩次均沒有找到則在終端進行提示,但這種情況下并不會報錯破壞進程的運行。

function fixAbsolutePath(dir, relative) {
    // find the first time
    var absolute = path.resolve(dir, relative);

    // check if is a image file
    var reg = /.(jpg|jpeg|png|gif|svg|bmp)/i;
    if (!reg.test(absolute)) {
        pluginLog("Not a image file: ", absolute);
        return;
    }

    if (!fs.existsSync(absolute) && (relative.indexOf("../") > -1)) {
        relative = relative.replace("../", "");
        // find the second time
        absolute = path.resolve(dir, relative);
    }

    return absolute;
}

不敢說這是一種最好的處理方式,但至少是一種可行的處理方式。

單元測試

單元測試上采用Mocha 測試工具, should.js 做斷言庫。在筆者看來,結(jié)合TDD 進行開發(fā),單元測試僅作為一種開發(fā)的輔助手段,規(guī)避開發(fā)過程中一些產(chǎn)生致命的報錯。本文不展開如何寫單元測試,具體實現(xiàn)可點擊這里。

優(yōu)化篇

在Postcss 官方Github Repo,有一個Plugin Guidelines。對于其提倡的“Do one thing, and do it well” 深感認同,因此在基本完成插件功能后筆者又做了如下優(yōu)化工作。

更友好的log 提示

官方其實是建議用內(nèi)置的result.warn來代替console.logconsole.warn來展示log 信息(原因據(jù)說是一些PostCSS 處理器會忽略這類console log 輸出)。不過筆者嘗試后發(fā)現(xiàn)官方函數(shù)下提示的信息會非常長,后面采用了借助chalk 模塊封裝了console.log的形式增加了高亮態(tài)信息展示。

錦上添花 “找不到圖片文件”的場景處理

用戶在寫CSS 代碼的時候,background-image 的url 可能會有如下情況:

輸入的是目錄

輸入的非圖片路徑

輸入了一半就保存了

根本就是瞎輸入

場景很多,但對于插件而言僅僅是能否找到與否的結(jié)果。在處理這些錯誤場景的情況下也給出的細分到“File does not exist” 或 “Not a image file”的情況,讓這類錯誤提醒更加友好一些。

提示二倍圖不正確

如果用戶引用的二倍圖(類似xxx@2x.png)的寬度高度為非偶數(shù)的話,也會有相應(yīng)的提醒。

以上的報錯提示在實際運行效果如下:

英文版 README

PostCSS 官方建議是README.md用英文寫,其余語種采用類似README.zh.md的方式。

維護一份 changelog

按照建議,也將更新歷史等數(shù)據(jù)放在了一個名為CHANGELOG.md文件上,并采用語義化的版本號。

其它

根據(jù)自己的開發(fā)習(xí)慣,在Github 上的Repo 也放置了一份LICENSE 文件。

發(fā)布篇 發(fā)布到NPM 官方

發(fā)布到NPM 官方的步驟在這里就不再詳述。僅分享一個不錯的版本號增加方式(告別packup.json 的手動改版本數(shù)字)。

npm version patch => z+1
npm version minor => y+1 && z=0
npm version major => x+1 && y=0 && z=0

與上文所講的語義化的版本號相關(guān),vX.Y.Z(主版本號.次版本號.修訂號)三個選項分別對應(yīng)三部分的版本號,每次運行命令會導(dǎo)致相應(yīng)的版本號遞增一,同時子版本號清零。記得運行上面命令前先將文件變動提交到git 上去。

之后運行npm publish命令即可。

發(fā)布到PostCSS 官方

Postcss 官方主頁上有個plugin list 文件展示了所有的第三方插件,提交的話Fork 一份然后在該文件增加自己的插件詳細然后提交合并,等作者允許即可。

發(fā)布到postcss.part

postcss.parts 是一個非官方的PostCSS 插件搜索平臺。提交自己插件可按照這個說明。其實本質(zhì)也是Fork 然后加信息在Pull request 的方式,在此不累述。

結(jié)束篇 效果

在開發(fā)完postcss-lazyimagecss 插件后,筆者按照上面的發(fā)布方式提交了給官方。后面效果還不錯,PostCSS 作者也提了個star 跟issue。PostCSS 官方推特上的推薦也帶來了第一批Stargazers。

因為這個緣故,在第三屆中國CSS 大會上也有幸與PostCSS 作者ai 大神勾搭了下,并得到了大神贈送的俄羅斯巧克力。

思考

在筆者看來,PostCSS 的作為一個CSS 轉(zhuǎn)換引擎,其不參與細分功能實現(xiàn)僅交于第三方插件的設(shè)計理念,讓其產(chǎn)生了一個非常的開放的生態(tài)。但對于個開放機制下的一些情況筆者并不是很贊同,如一些用中文寫CSS 的插件(當(dāng)然這個更多是for fun),一些自定義CSS 屬性如用size: 10px 2px 等代替width/height的插件——在筆者看來PostCSS 插件應(yīng)該更多在遵從CSS 標(biāo)準(zhǔn)語法的基礎(chǔ)上進行擴展。

但無論如何,還是挺佩作者開發(fā)出了這么個造福前端屆的工具;也因為認同作者,筆者寫了這篇文章為推廣PostCSS 做了一點微小的工作;也希望對看到文末的您有所幫助,積極參與到開源創(chuàng)作的事業(yè)中。

參考文章:

http://ai.github.io/postcss-way/

https://github.com/postcss/po...

https://css-tricks.com/want-m...

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/86675.html

相關(guān)文章

  • Webpack 最佳實踐總結(jié)(三)

    摘要:這里要介紹的是工作流中的一種很普遍的代碼加工流程正常的業(yè)務(wù)邏輯開發(fā)流程需要經(jīng)過預(yù)處理器如或,然后再經(jīng)過后處理器如進行深加工。 還未看的,可以點擊查看上兩篇文章喲:Webpack 最佳實踐總結(jié)(一)、Webpack 最佳實踐總結(jié)(二) 好了,這篇是第三篇,也是完結(jié)篇,我感覺這一篇是最亂的一篇,湊合著看吧,不會讓你失望的 整合 CSS 加工流 有時候,前端項目中除了 JavaScript ...

    pkhope 評論0 收藏0
  • Webpack 最佳實踐總結(jié)(三)

    摘要:這里要介紹的是工作流中的一種很普遍的代碼加工流程正常的業(yè)務(wù)邏輯開發(fā)流程需要經(jīng)過預(yù)處理器如或,然后再經(jīng)過后處理器如進行深加工。 還未看的,可以點擊查看上兩篇文章喲:Webpack 最佳實踐總結(jié)(一)、Webpack 最佳實踐總結(jié)(二) 好了,這篇是第三篇,也是完結(jié)篇,我感覺這一篇是最亂的一篇,湊合著看吧,不會讓你失望的 整合 CSS 加工流 有時候,前端項目中除了 JavaScript ...

    jerryloveemily 評論0 收藏0
  • postcss-lazysprite: 一種生成CSS 雪碧圖的懶惰姿勢

    摘要:無論是早期工具,還是現(xiàn)在流行的配合這類構(gòu)建工具而產(chǎn)生的雪碧圖插件。 本文原文鏈接:https://devework.com/postcss-...,轉(zhuǎn)載請注明原始來源,謝謝! showImg(https://segmentfault.com/img/bVPmaC?w=1692&h=754); postcss-lazysprite 是一個基于PostCSS 開發(fā)的用于生成雪碧圖圖片及其C...

    BearyChat 評論0 收藏0
  • 正在失業(yè)中的《課多周刊》(第3期)

    摘要:正在失業(yè)中的課多周刊第期我們的微信公眾號,更多精彩內(nèi)容皆在微信公眾號,歡迎關(guān)注。若有幫助,請把課多周刊推薦給你的朋友,你的支持是我們最大的動力。是一種禍害譯本文淺談了在中關(guān)于的不好之處。淺談超時一運維的排查方式。 正在失業(yè)中的《課多周刊》(第3期) 我們的微信公眾號:fed-talk,更多精彩內(nèi)容皆在微信公眾號,歡迎關(guān)注。 若有幫助,請把 課多周刊 推薦給你的朋友,你的支持是我們最大的...

    robin 評論0 收藏0
  • 正在失業(yè)中的《課多周刊》(第3期)

    摘要:正在失業(yè)中的課多周刊第期我們的微信公眾號,更多精彩內(nèi)容皆在微信公眾號,歡迎關(guān)注。若有幫助,請把課多周刊推薦給你的朋友,你的支持是我們最大的動力。是一種禍害譯本文淺談了在中關(guān)于的不好之處。淺談超時一運維的排查方式。 正在失業(yè)中的《課多周刊》(第3期) 我們的微信公眾號:fed-talk,更多精彩內(nèi)容皆在微信公眾號,歡迎關(guān)注。 若有幫助,請把 課多周刊 推薦給你的朋友,你的支持是我們最大的...

    Joyven 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<