為什么使用 npm Scripts 構建項目

nequ4745 7年前發布 | 22K 次閱讀 CSS 前端技術 JavaScript

已經有越來越多的觀點認為直接使用 node packages,與他們提供的命令行界面,是一個好的路線。反之,將功能抽象到任務運行器后臺運行已經越來越不被看好。在一定程度是,你無論如何都要使用npm,而同時npm提供了腳本功能,為什么不用呢?但使用npm的腳本功能的原因有很多。Damon會幫我們理解這樣做的原因,并確切的告訴我們如何通過這種方式來完成前端構建過程中的大部分重要任務。

在過去的大概六個月里,我已經開始在我的項目中使用 npm scripts 。在此之前,我使用 Gulp ,再之前是 Grunt 。他們給了我很好的功能,通過自動化幫助我做了許多原先需要我手工做的事情,并且更快更有效地執行我的工作。但是我卻開始覺得我在這些工具上花費的精力要比花在我自己代碼上的精力多得多。

Grunt,Gulp,Broccoli,Brunch等類似的工具都需要你把你的任務配置成適合他們的范例和配置。每個工具你需要學習他們自己的語法,奇怪的用法和特有的方法。這增加了代碼復雜性,構建復雜性,使您專注于修復工具的問題,而不是編寫代碼。

這些構建工具依賴于于包裝了核心命令行工具的插件。并基于這個核心工具做了進一步的抽象,這意味著更多的潛在的問題會發生。

以下三個問題我已經碰到過多次:

  • 如果您使用的命令行工具沒有你想用的插件,那么你將束手無策(除非你自己寫一個)。
  • 您嘗試使用的插件包含要使用的舊版本的工具。您使用的插件和當前版本的核心工具之間,功能和文檔并不匹配。
  • 錯誤不是處理得好。如果插件失敗的話,它可能不會傳遞來自核心工具的錯誤提示,這導致我很沮喪,并且不知道如何調試的問題。

但是,請記住…

讓我說:如果你對你當前的構建系統感到滿意,并且它能夠很好的完成你的需求的話,你可以繼續使用它!雖然 npm scripts 越來越流行,但這并不意味著你應該馬上轉過來。繼續專注于編寫代碼,而不是學習更多的工具。如果你開始感覺到不是你在使用工具,而是工作在使用你的時候,這是我建議考慮使用 npm scripts。

如果您決定要調研或開始使用 npm scripts ,那么繼續閱讀! 在這篇文章的其余部分,你會發現很多案例任務。此外,我已經為所有這些任務創建了 npm-build-boilerplate 示例項目,你可以用作一個學習的起點。讓我們開始吧!

編寫 npm scripts

我們將大部分時間花在 package.json 文件中。這個文件包含了我們所有的依賴和腳本。這里是一個示例項目的精簡版本:

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

我們將一起來構建我們的 package.json 文件。我們的腳本會進入 scripts 對象,我們要使用的任何工具都將被安裝并放入 devDependencies 對象中。

在我們開始之前,這里是示例項目的結構,我將在整篇文章中提到:

將SCSS編譯為CSS

我是SCSS的鐵粉,所以工作中我經常使用SCSS。要將SCSS編譯為CSS,我使用了 node-sass 。首先,我們需要安裝 node-sass ;

通過在命令行中運行以下命令來執行此操作:

npm install --save-dev node-sass

這個命令將會在當前目錄中安裝 node-sass 并將其添加到 package.json 的 devDependencies 對象中。當其他人運行您的項目時,這個特別有用,因為他們將擁有使項目運行所需的一切。一旦安裝,我們可以在命令行中使用它:

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

讓我們分解一下這個命令的作用。從結束的地方開始,他的意思是:在 src/scss 目錄中查找所有的SCSS文件;輸出( -o 標識)編譯的CSS到 dist/css 目錄;壓縮輸出(使用帶有 compressed 選項的 --output-style 標識)。

現在我們知道了 node-sass 在命令行中如何工作,讓我們把這個命令行移動到 npm scirpt 中。 在你的 package.json 的 scripts 對象中,添加如下內容:

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

現在,回到命令行并運行:

npm run scss

您將看到與在命令行中直接運行 node-sass 命令相同的輸出結果。

我們在本文的剩余部分創建的任何一個npm script,你任何時候都可以像上面的命令一樣運行它。

只需將 scss 替換為你要運行的任務的名稱即可。

正如你將看到的,我們使用的很多命令行工具都有很多的配置項,你可以使用配置項來精確完成你想要做的工作。

你可以使用配置項它完全看到合適。

例如,下面是列表。下面是一個不同的設置,演示如何傳遞多個選項:

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

使用PostCSS Autoprefix 自動給 CSS 加前綴

現在我們已經能夠將Scss編譯為CSS了,我們可以使用 Autoprefixer 和 PostCSS自動添加瀏覽器前綴。 我們可以同時安裝多個 Node 模塊,用空格分隔它們:

npm install --save-dev postcss-cli autoprefixer

我們需要安裝兩個模塊,因為 PostCSS 默認情況下不執行任何操作。它依賴于其他插件,比如 Autoprefixer ,來操縱你提供的CSS。

安裝并保存必要的工具到 devDependencies ,在您的 scripts 對象中添加一個新任務:

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

這個任務的意思是:嘿, postcss ,使用( -u 標識) autoprefixer 替換( -r 標志) dist/css 中的任何 .css 文件, 給他們自動添加瀏覽器前綴。 就是這樣簡單! 需要更改 autoprefixer 的默認瀏覽器支持? 只要給腳本添加如下代碼即可:

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

同樣,有很多選項可以用來配置自己的構建: postcss-cli 和 autoprefixer 。

JavaScript 代碼檢查

在編寫代碼的同時,保持標準格式和樣式很重要,它可以確保將錯誤降低到最低程度,并提高開發人員的效率。“Linting(代碼檢查)”可以幫助我們自動完成這項工作,所以讓我們使用 eslint 來進行 JavaScript 代碼檢查。

如上文所述,安裝 eslint 包; 這一次,讓我們使用一個快捷方式:

npm i -D eslint

這行代碼等效于:

npm install --save-dev eslint

一旦安裝完成后,我們可以使用 eslint 來設置一些運行代碼的基本規則。 運行以下命令啟動向導:

eslint --init

愚人碼頭注:這樣直接使用會拋錯eslint找不到,因為這種使用方法必須通過 npm install i -g eslint 全局方式安裝;

我建議選擇“回答關于你的風格的問題”,并回答它問的問題。 這將在您的項目的根目錄中生成一個新文件,eslint將檢查您的代碼。

現在,讓我們在 package.json 的 scripts 對象中添加一個 lint 任務:

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

我們的lint任務僅有13個字符長! 它會在 src/js 文件夾中查找所有的JavaScript文件,并根據之前生成的規則進行代碼檢測。

混淆壓縮 JavaScript 文件

讓我們來合并和壓縮我們的JavaScript文件,我們可以使用 uglify-js 來做這項工作。 首先我們需要安裝 uglify-js :

npm i -D uglify-js

然后,我們可以在 package.json 中設置 混淆壓縮(uglify) 任務:

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

npm scripts 其中一個偉大的功能是,它們本質上是一個命令行任務的別名,你可以重復執行。這意味著您可以在 npm scripts 中直接使用標準命令行代碼!此任務使用兩個標準命令行功能, mkdir 和 && 。

這個任務的前半部分, mkdir -p dist/js 意思是說:當 dist/js 目錄結構不存在( -p 標識)時,那就創建 dist/js 目錄結構(使用 mkdir 命令)。一旦成功完成,運行 uglifyjs 命令。 && 允許你將多個命令連接在一起,如果前一個命令成功完成,就按順序運行下一個命令。

這個任務的第二部分告訴 uglifyjs 從 src/js/ 中的所有JS文件( *.js )開始,應用 mangle 命令( -m 標識),并將結果輸出到 dist/js/app.js 中。

讓我們更新我們的 uglify 任務來創建一個壓縮版的 dist/js/app.js 。鏈接另一個 uglifyjs 命令并傳遞 compress ( -c 標識):

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

壓縮圖片

讓我們把注意力轉到壓縮圖片上。根據 httparchive.org 的數據統計,在互聯網上前1000個URL的平均頁面大小為 1.9 MB, 其中圖片占了 1.1 MB 。您可以做的提升頁面速度的最好辦法就之一是減少圖片的大小。

安裝 imagemin-cli

npm i -D imagemin-cli

Imagemin非常棒,因為它以壓縮大多數類型的圖片,包括GIF,JPG,PNG和SVG。 你可以傳遞整個圖片文件夾,它會壓縮該文件夾中所有的圖片,像這樣:

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

這個任務告訴 imagemin 查找和壓縮 src/images 目錄中的所有圖片,并將它們放在 dist/images 中。傳遞 -p 標志在允許的情況下將圖片處理成漸進圖片。

SVG精靈(Sprites)

在過去幾年里,關于圍繞SVG的討論逐漸增加了,并且使用 SVG 有很多好的理由。 他們在所有的設備上保持松散結構、可通過CSS編輯、對讀屏軟件友好。然而,SVG編輯軟件通常會留下無關而且不必要的代碼。幸運的是, svgo 可以幫助刪除所有的冗余信息(我們將在下面安裝它)。

您還可以自動化合并和精靈化SVG,來制作一個單一的SVG文件。

為了自動化整個過程,我們可以安裝 svg-sprite-generator 。

npm i -D svgo svg-sprite-generator

這種模式現在你可能已經很熟悉了:一旦安裝完成,在你的 package.json 的 scripts 對象中添加一個任務:

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

注意: icons 任務通過兩個 && 指令做了三件事。首先,我們使用 svgo ,傳遞一個包含SVG的文件夾( -f 標識);這將壓縮文件夾內的所有SVG。其次,如果 dist/images 文件夾內不存在,我們將創建該文件夾內(使用 mkdir -p 命令)。

最后,我們使用 svg-sprite-generator ,傳遞一個SVG文件夾內( -d 標識)和我們想讓SVG精靈輸出的一個文件夾內路徑,( -o 標識)。

通過BrowserSync提供服務并且自動注入變更

最后一個難題是 BrowserSync 。它可以做的一些事情:啟動一個本地服務,向連接的瀏覽器自動注入更新的文件,并同步瀏覽器的點擊和滾動。安裝它并添加任務:

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

默認情況下,我們的 BrowserSync 任務使用當前路徑作為啟動服務器的根目錄( --server 標識)。 --files 標志告訴 BrowserSync 監視 dist 文件夾中的任何CSS或JS文件;每當有任何變化時,自動將更改的文件注入頁面。

您可以同時打開多個瀏覽器(即使在不同的設備上),他們都將會獲得實時更新的文件變化!

任務分組

有了上面的所有任務,我們能夠:

  • 將SCSS編譯為CSS并自動添加瀏覽器前綴
  • 檢查 和 混淆壓縮 JavaScript
  • 壓縮圖片
  • 將SVG的文件夾轉換為單個SVG文件
  • 啟動本地服務并自動將更改注入連接到服務器的任何瀏覽器

還不止如此!

合并 CSS 任務

讓我們添加一個任務,合并兩個CSS相關的任務(預處理 Sass 和運行 Autoprefixer ),這樣我們就不必分別運行每個任務:

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

當你運行 npm run build:css 時,它會告訴命令行運行 npm run scss ; 當它成功完成后,然后( && )運行 npm run autoprefixer 。

類似于 build:css 任務一樣,我們可以把JavaScript任務也合并到一起以方便執行:

合并 JavaScript 任務

"scripts": {
  ...
  "build:js": "npm run lint && npm run uglify"
}

現在,我們可以通過 npm run build:js 來一步進行代碼檢測、合并和壓縮JavaScript代碼了!

合并剩余任務

對于圖片任務,我們可以做同樣的事情,以及將所有構建任務合并為一個任務的執行:

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

監聽變更

直到這一步,當我們需要更改某一文件時,我們需要切換回命令行并運行相應的任務。 我們可以做的最有用的事情之一是添加一個任務,監視文件更改時自動運行任務。 為此,我建議使用 onchange 。 像往常一樣安裝:

npm i -D onchange

讓我們為 CSS 和 JavaScript 設置監聽(watch)任務:

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

以下是這些任務的明細: onchange 希望您傳遞一個要監聽文件的路徑字符串。我們將通過我們的 SCSS 和 JS 源文件來監聽。我們要運行的命令在 -- 之后,當給定路徑中的任何一個文件被添加,更改或刪除的時候,這些任務就會被立即執行。

讓我們再添加一個監聽(watch)命令來完成我們的npm scripts構建過程。

安裝一個軟件包, parallelshell :

npm i -D parallelshell

再次在 scripts 對象中添加一個新任務:

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

parallelshell 接受多個字符串,我們將會執行多個 npm run 任務。

為什么使用 parallelshell 來合并多個任務,而不是像以前一樣,在任務中使用 && 呢?起初,我也嘗試這么做了。 問題是 && 將多個命令鏈接在一起,需要等待每個命令成功完成后才會執行下一個命令。但是,由于我們正在運行 watch 命令,這些命令永遠不會完成(愚人碼頭注:一直在監聽中,不會結束)!我們會陷入一個無限循環中。

因此,使用 parallelshell 可以同時運行多個監聽(watch)命令。

這個任務使用了BrowserSync的 npm run serve 任務啟動了一個服務,然后對 CSS 和 JavaScript 文件執行了監聽(watch)命令,一旦CSS或JavaScript文件有更改,監聽(watch)任務就會執行相應的構建(build)任務。由于BrowserSync被設置成監控 dist 目錄下的變更,所以它會自動的向相關聯的URL內注入新的文件,真是太棒了!

其他實用任務

npm有 大量實用的任務 ,讓我們使用其中一個構建的腳本再寫一個任務。

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

當你在命令行中執行 npm install 后, postinstall 會立即執行,當團隊合作時這個功能非常有用。當別人復制了你的項目并運行了 npm install 的時候,我們的 watch:all 任務就會馬上執行,它們將自動啟動服務器,打開瀏覽器窗口,并且監聽(watch)文件是否有更改。

打包

太棒了!我們做到了!我希望你能夠學到一些使用npm scripts構建過程和常用命令行的方法。

為了防止你錯過某些知識點,我創建了一個包含所有這些任務的 npm-build-boilerplate 示例項目,你可以用作學習的起點。如果您有問題或意見,請在 推ter上@我 或發表評論。我會盡我所能的幫助您!

原文中一些有用的評論

愚人碼頭注:這部分是原文的評論,作為對文章的補充。

Sean Walsh 評論:

切換到 npm scripts 非常好,但是如果你正在維護一個開源項目并希望最大化貢獻,請確保您的腳本也能在非 *nix 機器上運行。跨平臺最大的難點是設置環境變量(例如 NODE_ENV )。 better-npm-run 是一個很好的庫來處理這個問題。

> Louis-rémi 回復評論:

> 另一個問題是注釋你的代碼,并保持其可讀性和可維護性。我已經建立了 gulp-shelter ,可以使 npm scripts 和 gulpfiles 很好的結合,而不需要重復造輪子。

Craig Jennings 評論:我發現 npm-run-all 是非常有用的,可以代替 parallelshell 。它允許在任務執行時重新這些執行任務(愚人碼頭注:不用等帶任務成功完成),比如:

"scripts": {
  ...
  "serve": "browser-sync start --server --files 'dist/css/*.css, dist/js/*.js'",
  "watch:css": "onchange 'src/scss/*.scss' -- npm run build:css",
  "watch:js": "onchange 'src/js/*.js' -- npm run build:js",
  "watch": "npm-run-all --parallel serve watch:*"
}

對于構建步驟也是如此:

"scripts" {
  ...
  "build:css": "npm run scss && npm run autoprefixer",
  "build:images": "npm run imagemin && npm run icons",
  "build:js": "npm run lint && npm run uglify",
  "build": “npm-run-all build:*"
}

Michael 評論: 關于Sass Sourcemaps

“min-sass”: “node-sass resources/sass/main.scss | cleancss -o public/stylesheets/main.min.css –source-map”

npm run min-sass

Christopher 回復評論: ‘mkdir’ 和 ‘rm’ 在 Windows 下步工作?

可以使用 rimraf 和 mkdirp

 

來自:http://www.css88.com/archives/7025

 

 本文由用戶 nequ4745 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!