也許你并不需要 Gulp, Grunt ?
我已經在我的項目中使用 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
{ "name": "npm-build-boilerplate", "version": "1.0.0", "scripts": { ... }, "devDependencies": { ... } }
</tr>
</tbody>
</table>
</figure>
我們的 scripts 都會寫在 scripts 下面,而devDependencies 下存放的是我們項目的依賴。
開始之前,想看看這個項目的結構:
項目結構
SCSS => CSS
我是 SCSS 的狂熱愛好者,所以我迫不及待地想跟你介紹。我使用 node-sass 來幫我做這項任務,
npm install --save-dev node-sass
</tr>
</tbody>
</table>
</figure>
使用上面的命令安裝好 node-sass, 那么它會出現在你的 package.json 中的 devDependencies里面,這樣對于其他想跑你代碼的人就方便多了。安裝完成之后,我們來使用它:
node-sass --output-style compressed -o dist/css src/scss
</tr>
</tbody>
</table>
</figure>
這行命令干了這樣的事: node-sass 同學 (你是學計算機的吧?) 去把 src/scss
下的所有 SCSS 文件都編成 CSS 然后放在 dist/css
下面,對了,幫我壓縮一下(compressed)
但是大領導通常都懶得說這么長的話,它跟 scripts 說 Just do IT
:
"scripts": { "scss": "node-sass --output-style compressed -o dist/css src/scss" }
</tr>
</tbody>
</table>
</figure> 然后大領導就只需要喊口號即可:
npm run scss
</tr>
</tbody>
</table>
</figure>
這樣,大領導(你)就完成了編譯 Sass 的任務(just kidding)。
接下的的部分,任何時候你都可以像上面那樣創建 npm scripts
只需要替換把 scss 替換成你的命令即可。
正如你所見,很多命令行工具都需要一大把選項供你選擇。比如這里是 node-sass options 下面是多個選項的配置:
"scripts": { "scss": "node-sass --output-style nested --indent-type tab --indent-width 4 -o dist/css src/scss" }
</tr>
</tbody>
</table>
</figure> Autoprefix CSS with PostCSS
現在我們使用 Autoprefixer & PostCSS 來自動添加前綴,我們可以同時安裝多個模塊:
npm install --save-dev postcss-cli autoprefixer
</tr>
</tbody>
</table>
</figure>
我們安裝了兩個模塊,因為 PostCSS 默認什么都不做,他依賴于像Autoprefixer 這類插件。
現在我們都把兩個工具添加到 devDependencies 中,在 scripts 對象中再添加一個任務:
"scripts": { ... "autoprefixer": "postcss -u autoprefixer -r dist/css/*" }
</tr>
</tbody>
</table>
</figure> 這個任務說,postcss 你用 autoprefixer 幫我把 dist/css/*
下的所有 css 文件給處理一下,那具體要適應什么瀏覽器你也要告訴 Autoprefix:
"autoprefixer": "postcss -u autoprefixer --autoprefixer.browsers '> 5%, ie 9' -r dist/css/*"
</tr>
</tbody>
</table>
</figure>
同樣的,postcss-cli , autoprefixer 也有很多可選項
Linting JavaScript
保持良好的編程風格和規范是錯誤最小化和開發效率的保障,Linting
幫助我們自動地檢查,我們可以使用 eslint
再一次,我們安裝 package,這一次使用快捷方式:
npm i -D eslint
</tr>
</tbody>
</table>
</figure>
同下面的方式一樣
npm install --save-dev eslint
</tr>
</tbody>
</table>
</figure>
安裝完,我們使用 eslint 設置一些執行我們代碼的基本規則,執行下面代碼進入指引:
eslint --init
</tr>
</tbody>
</table>
</figure>
我建議你選擇”Answer questions about your style” 并且回答它問的問題,這會生成一個新的文件在你的項目根部。
再次豐富 scripts 對象:
"scripts": {
...
"lint": "eslint src/js"
}
</tr>
</tbody>
</table>
</figure>
這13個字符的命令會查找在 src/js 下的所有js文件,并根據配置重新執行一遍。另外你會被這些配置 逼瘋的。
Uglifying JavaScript files
接下來是合并壓縮 JavaScript文件,我們選擇 uglify-js 來做:
npm i -D uglify-js
</tr>
</tbody>
</table>
</figure> 然后再次配置 package.json :
"scripts": { ... "uglify": "mkdir -p dist/js && uglifyjs src/js/*.js -m -o dist/js/app.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 && uglifyjs src/js/*.js -m -c -o dist/js/app.min.js" }
</tr>
</tbody>
</table>
</figure> Compressing Images
接下來看看壓縮圖片。根據 httparchive.org , 前1000 個熱門網站的頁面大小是 1.9mb ,而其中圖片就占了 1.1mb ,所以頁面提速的首要因素是壓縮圖片體積。
安裝 imagemin-cli
npm i -D imagemin-cli
</tr>
</tbody>
</table>
</figure> Imagemin 幾乎可以壓縮所有類型的圖片,包括 GIF,JPG,SVG。你可以傳遞一個文件夾路徑,然后它會處理其中的所有圖片:
"scripts": { ... "imagemin": "imagemin src/images dist/images -p", }
</tr>
</tbody>
</table>
</figure> 這個任務是壓縮所有在 src/images
下的圖片,并把結果輸出到 dist/images
。-p 的意思是 盡量創建 “progressive” 的圖片。
SVG Sprites
近幾年 SVG 越來越受歡迎,因為它幾乎兼容所有設備,可以用 CSS 調整,視覺效果良好。然而很多 SVG 編輯器會殘留多余和不必要的代碼。我們使用 svgo 來移除。
你可以把壓縮 SVG 和拼接精靈圖放在一塊,拼接精靈圖我們使用svg-sprite-generator
npm i -D svgo svg-sprite-generator
</tr>
</tbody>
</table>
</figure> 現在你應該很熟悉這種模式了吧。
"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> icons 這個任務做了三件事,傳遞了一個文件夾路徑(-f)給 svgo, 然后如果沒有(-p) dist/images
這個文件夾則創建一個,接著就拼接精靈圖,結果保存到(-d) src/images/icons
, 產出(-o)叫做 dist/images/icons.svg
Serve and Automatically Inject Changes with BrowserSync
最后一個問題是 BrowserSync ,他可以幫我們做的是:開啟一個本地服務器,自動更新文件,自動在瀏覽器中同步點擊,滾動效果。
npm i -D browser-sync
</tr>
</tbody>
</table>
</figure>
"scripts": { ... "serve": "browser-sync start --server --files 'dist/css/*.css, dist/js/*.js'" }
</tr>
</tbody>
</table>
</figure> 這個任務打開一個本地服務(—server),以當前路徑作為根目錄,—files 參數告訴 Browsersync 監聽 dist
下的所有css 和 js文件,一有更新,馬上自動刷新頁面。
Grouping tasks
有了上面的代碼,我們現在能夠:
編譯 SCSS 并且自動添加前綴
檢查并壓縮 JavaScript
壓縮圖片
將一個 SVG 文件夾轉成一張 SVG 精靈圖
創建一個本地服務器,并實時自動刷新瀏覽器
</ul>
Combining CSS tasks
我們可以把 CSS 相關的任務合并在一起:
"scripts": { ... "build:css": "npm run scss && npm run autoprefixer" }
</tr>
</tbody>
</table>
</figure>
當你執行 npm run build:css ,它會在執行 scss 任務成功之后在執行 autoprefixer 。
其他任務也類似,我們也可以這樣做
"scripts": { ... "build:js": "npm run lint && 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> Watching for changes
我們現在還需要監聽文件的變動,并自動執行相應的任務,我推薦使用 onchange ,安裝:
npm i -D onchange
</tr>
</tbody>
</table>
</figure> 添加任務:
"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> 任務是給 onchange 傳遞一個需要監聽的文件路徑,我們需要 onchange 自動執行的命令則放在 — 后面。
Let’s add one more watch command to finish off our npm scripts build process.
安裝多一個 package, parallelshell
npm i -D parallelshell
</tr>
</tbody>
</table>
</figure> 再一次,添加新的任務到 scripts 對象上:
"scripts": { ... "watch:all": "parallelshell 'npm run serve' 'npm run watch:css' 'npm run watch:js'" }
</tr>
</tbody>
</table>
</figure> parallelshell 允許我們同時執行多個任務,為什么不使用 && 呢?
因為 && 的執行順序必須是前面的執行完了才輪到后面的任務,但是 watch 類型的任務永遠不會完成啊~
現在 watch:all 任務開啟服務器,并監聽代碼,一旦有變動,馬上刷新瀏覽器 perfect!
Other useful tasks
npm 有很多其他任務 。我們再寫一個總的啟動任務:
"scripts": { ... "postinstall": "npm run watch:all" }
</tr>
</tbody>
</table>
</figure> npm install 之后就執行一下 postinstall 吧,這在團隊開發中是很好的體驗,克隆你代碼的人執行 npm install 然后 馬上 watch: all
Wrap Up
噢,我們做到了(終于翻譯完了,好長的文章。。。),希望看完這篇文章你能學會使用 npm scripts
對了,我把代碼都放在 npm-build-boilerplate 上了,歡迎交流。
譯者的廢話
最近看到關于 npm scripts 的字眼比較多,然后就找了篇文章翻譯。