也許你并不需要 Gulp, Grunt ?

jopen 8年前發布 | 16K 次閱讀

我已經在我的項目中使用 npm scripts 有六個月。在之前,我一直使用 Gulp , Grunt ,它們幫了我很多,讓我的任務完成得更加高效,也自動幫我處理很多繁瑣的任務。 然而,我開始感覺到我好想是在跟工具戰斗而不是關乎自己的代碼。

Grunt, Gulp, Broccoli,, Brunch 等等工具都要求你的任務符合它們定出的規則,每個工具都要你花時間去了解。并且一旦代碼復雜性提高了,你需要花更多精力去處理這些工具。

這些構建工具依靠的插件外面包裹了一層命令行工具,在核心工具外面多了一層抽象,這也意味著可能存在隱患。

下面三個問題我遇到過好多次

  • 如果這個工具下沒有你想要的插件,那你就太不幸了(除非你自己寫一個)
  • 你嘗試使用的插件包裹著你想用的另一個工具的老版本,那么會導致特性和文檔對不上號。
  • 錯誤不是一直都能被很好處理,如果一個插件出錯了,它可能不會把錯誤拋出,這會導致你很痛苦,因為不知道如何 Debug 。
  • </ul>

    但是,記住

    我想說:如果你對當前使用的構建工具非常滿意,并且你要的它都能給你,咁你keep住就嘚啦。 只是因為 npm scripts 越來越重要,而不是說你必須跳船。把注意力集中于編寫程序而不是用在學習工具。如果你也覺得你是在和工具戰斗,那么我建議你嘗試使用 npm scripts

    如果你真的想開始使用 npm scripts,那么請繼續看下去!你會看到很多例子,并且我建好了 npm-build-boilerplate 給你作為出發點。開始吧!

    編寫 npm scripts

    我們都花了大把時間在 package.json 文件上,我們的依賴和 scripts 都在這,這是我 boilerplate 項目的精簡版 package.json

    </tr> </tbody> </table> </figure>

    我們的 scripts 都會寫在 scripts 下面,而devDependencies 下存放的是我們項目的依賴。
    開始之前,想看看這個項目的結構:

    項目結構

    SCSS => CSS

    我是 SCSS 的狂熱愛好者,所以我迫不及待地想跟你介紹。我使用 node-sass 來幫我做這項任務,

    {   "name": "npm-build-boilerplate",   "version": "1.0.0",   "scripts": {     ...   },   "devDependencies": {     ...   } } 

    </tr> </tbody> </table> </figure>

    使用上面的命令安裝好 node-sass, 那么它會出現在你的 package.json 中的 devDependencies里面,這樣對于其他想跑你代碼的人就方便多了。安裝完成之后,我們來使用它:

    npm install --save-dev node-sass 

    </tr> </tbody> </table> </figure>

    這行命令干了這樣的事: node-sass 同學 (你是學計算機的吧?) 去把 src/scss 下的所有 SCSS 文件都編成 CSS 然后放在 dist/css 下面,對了,幫我壓縮一下(compressed)

    但是大領導通常都懶得說這么長的話,它跟 scripts 說 Just do IT:

    node-sass --output-style compressed -o dist/css src/scss 

    </tr> </tbody> </table> </figure>

    然后大領導就只需要喊口號即可:

    "scripts": {   "scss": "node-sass --output-style compressed -o dist/css src/scss" } 

    </tr> </tbody> </table> </figure>

    這樣,大領導(你)就完成了編譯 Sass 的任務(just kidding)。

    接下的的部分,任何時候你都可以像上面那樣創建 npm scripts

    只需要替換把 scss 替換成你的命令即可。

    正如你所見,很多命令行工具都需要一大把選項供你選擇。比如這里是 node-sass options 下面是多個選項的配置:

    npm run scss 

    </tr> </tbody> </table> </figure>

    Autoprefix CSS with PostCSS

    現在我們使用 Autoprefixer & PostCSS 來自動添加前綴,我們可以同時安裝多個模塊:

    "scripts": {   "scss": "node-sass --output-style nested --indent-type tab --indent-width 4 -o dist/css src/scss" } 

    </tr> </tbody> </table> </figure>

    我們安裝了兩個模塊,因為 PostCSS 默認什么都不做,他依賴于像Autoprefixer 這類插件。

    現在我們都把兩個工具添加到 devDependencies 中,在 scripts 對象中再添加一個任務:

    npm install --save-dev postcss-cli autoprefixer 

    </tr> </tbody> </table> </figure>

    這個任務說,postcss 你用 autoprefixer 幫我把 dist/css/* 下的所有 css 文件給處理一下,那具體要適應什么瀏覽器你也要告訴 Autoprefix:

    "scripts": {   ...   "autoprefixer": "postcss -u autoprefixer -r dist/css/*" } 

    </tr> </tbody> </table> </figure>

    同樣的,postcss-cli, autoprefixer也有很多可選項

    Linting JavaScript

    保持良好的編程風格和規范是錯誤最小化和開發效率的保障,Linting 幫助我們自動地檢查,我們可以使用 eslint

    再一次,我們安裝 package,這一次使用快捷方式:

    "autoprefixer": "postcss -u autoprefixer --autoprefixer.browsers '> 5%, ie 9' -r dist/css/*" 

    </tr> </tbody> </table> </figure>

    同下面的方式一樣

    npm i -D eslint 

    </tr> </tbody> </table> </figure>

    安裝完,我們使用 eslint 設置一些執行我們代碼的基本規則,執行下面代碼進入指引:

    npm install --save-dev eslint 

    </tr> </tbody> </table> </figure>

    我建議你選擇”Answer questions about your style” 并且回答它問的問題,這會生成一個新的文件在你的項目根部。

    再次豐富 scripts 對象:

    eslint --init 

    </tr> </tbody> </table> </figure>

    這13個字符的命令會查找在 src/js 下的所有js文件,并根據配置重新執行一遍。另外你會被這些配置逼瘋的。

    Uglifying JavaScript files

    接下來是合并壓縮 JavaScript文件,我們選擇 uglify-js 來做:

    "scripts": {
      ...
      "lint": "eslint src/js"
    } 

    </tr> </tbody> </table> </figure>

    然后再次配置 package.json :

    npm i -D uglify-js 

    </tr> </tbody> </table> </figure>

    值得一提的是 npm scripts 本質上是命令行的別名,這意味著你可以在 scripts 中使用標準命令行代碼,這里用到了 mkdir 和 &&

    前半部分,mkdir -p dist/js 的意思是如果(-p)不存在這樣的目錄結構,則創建一個新的執行成功之后(&&) 再執行后半部分 uglifyjs src/js/*.js -m -o dist/js/app.js" 這部分是告訴 uglifyjs 使用 “mangle” (-m) 命令,應用在 src/js 的所有js 上,并產出到 dist/js/app.js

    讓我們再豐富下 uglify , 創建一個 compress 版本的 dist/js/app.js (使用 -c )

    "scripts": {   ...   "uglify": "mkdir -p dist/js && uglifyjs src/js/*.js -m -o dist/js/app.js" } 

    </tr> </tbody> </table> </figure>

    Compressing Images

    接下來看看壓縮圖片。根據 httparchive.org , 前1000 個熱門網站的頁面大小是 1.9mb ,而其中圖片就占了 1.1mb ,所以頁面提速的首要因素是壓縮圖片體積。

    安裝 imagemin-cli

    "scripts": {   ...   "uglify": "mkdir -p dist/js &amp;&amp; uglifyjs src/js/*.js -m -o dist/js/app.js &amp;&amp; uglifyjs src/js/*.js -m -c -o dist/js/app.min.js" } 

    </tr> </tbody> </table> </figure>

    Imagemin 幾乎可以壓縮所有類型的圖片,包括 GIF,JPG,SVG。你可以傳遞一個文件夾路徑,然后它會處理其中的所有圖片:

    npm i -D imagemin-cli 

    </tr> </tbody> </table> </figure>

    這個任務是壓縮所有在 src/images 下的圖片,并把結果輸出到 dist/images。-p 的意思是 盡量創建 “progressive” 的圖片。

    SVG Sprites

    近幾年 SVG 越來越受歡迎,因為它幾乎兼容所有設備,可以用 CSS 調整,視覺效果良好。然而很多 SVG 編輯器會殘留多余和不必要的代碼。我們使用 svgo 來移除。

    你可以把壓縮 SVG 和拼接精靈圖放在一塊,拼接精靈圖我們使用svg-sprite-generator

    "scripts": {   ...   "imagemin": "imagemin src/images dist/images -p", } 

    </tr> </tbody> </table> </figure>

    現在你應該很熟悉這種模式了吧。

    npm i -D svgo svg-sprite-generator 

    </tr> </tbody> </table> </figure>

    icons 這個任務做了三件事,傳遞了一個文件夾路徑(-f)給 svgo, 然后如果沒有(-p) dist/images 這個文件夾則創建一個,接著就拼接精靈圖,結果保存到(-d) src/images/icons, 產出(-o)叫做 dist/images/icons.svg

    Serve and Automatically Inject Changes with BrowserSync

    最后一個問題是 BrowserSync,他可以幫我們做的是:開啟一個本地服務器,自動更新文件,自動在瀏覽器中同步點擊,滾動效果。

    "scripts": {   ...   "icons": "svgo -f src/images/icons && mkdir -p dist/images && svg-sprite-generate -d src/images/icons -o dist/images/icons.svg" } 

    </tr> </tbody> </table> </figure>
    npm i -D browser-sync 

    </tr> </tbody> </table> </figure>

    這個任務打開一個本地服務(—server),以當前路徑作為根目錄,—files 參數告訴 Browsersync 監聽 dist 下的所有css 和 js文件,一有更新,馬上自動刷新頁面。

    Grouping tasks

    有了上面的代碼,我們現在能夠:

    • 編譯 SCSS 并且自動添加前綴
    • 檢查并壓縮 JavaScript
    • 壓縮圖片
    • 將一個 SVG 文件夾轉成一張 SVG 精靈圖
    • 創建一個本地服務器,并實時自動刷新瀏覽器
    • </ul>

      Combining CSS tasks

      我們可以把 CSS 相關的任務合并在一起:

    "scripts": {   ...   "serve": "browser-sync start --server --files 'dist/css/*.css, dist/js/*.js'" } 

    </tr> </tbody> </table> </figure>

    當你執行 npm run build:css ,它會在執行 scss 任務成功之后在執行 autoprefixer 。
    其他任務也類似,我們也可以這樣做

    "scripts": {   ...   "build:css": "npm run scss && npm run autoprefixer" } 

    </tr> </tbody> </table> </figure>

    Watching for changes

    我們現在還需要監聽文件的變動,并自動執行相應的任務,我推薦使用 onchange,安裝:

    "scripts": {   ...   "build:js": "npm run lint &amp;&amp; npm run uglify",   "build:images": "npm run imagemin && npm run icons",   "build:all": "npm run build:css && npm run build:js && npm run build:images" } 

    </tr> </tbody> </table> </figure>

    添加任務:

    npm i -D onchange 

    </tr> </tbody> </table> </figure>

    任務是給 onchange 傳遞一個需要監聽的文件路徑,我們需要 onchange 自動執行的命令則放在 — 后面。

    Let’s add one more watch command to finish off our npm scripts build process.

    安裝多一個 package, parallelshell

    "scripts": {   ...   "watch:css": "onchange 'src/scss/*.scss' -- npm run build:css",   "watch:js": "onchange 'src/js/*.js' -- npm run build:js", } 

    </tr> </tbody> </table> </figure>

    再一次,添加新的任務到 scripts 對象上:

    npm i -D parallelshell 

    </tr> </tbody> </table> </figure>

    parallelshell 允許我們同時執行多個任務,為什么不使用 && 呢?

    因為 && 的執行順序必須是前面的執行完了才輪到后面的任務,但是 watch 類型的任務永遠不會完成啊~

    現在 watch:all 任務開啟服務器,并監聽代碼,一旦有變動,馬上刷新瀏覽器 perfect!

    Other useful tasks

    npm 有很多其他任務。我們再寫一個總的啟動任務:

    "scripts": {   ...   "watch:all": "parallelshell 'npm run serve' 'npm run watch:css' 'npm run watch:js'" } 

    </tr> </tbody> </table> </figure>

    npm install 之后就執行一下 postinstall 吧,這在團隊開發中是很好的體驗,克隆你代碼的人執行 npm install 然后 馬上 watch: all

    Wrap Up

    噢,我們做到了(終于翻譯完了,好長的文章。。。),希望看完這篇文章你能學會使用 npm scripts

    對了,我把代碼都放在 npm-build-boilerplate 上了,歡迎交流。

    譯者的廢話

    最近看到關于 npm scripts 的字眼比較多,然后就找了篇文章翻譯。

    "scripts": {   ...   "postinstall": "npm run watch:all" }