1. package.json
{
"name": "npm-build-boilerplate",
"version": "1.0.0",
"scripts": {
...
},
"devDependencies": {
...
}
}
2. 項(xiàng)目結(jié)構(gòu)

3. 插件整理
3.1 編譯scss為css
npm install --save-dev node-sass
"scripts": {
"scss": "node-sass --output-style compressed -o dist/css src/scss"
}
從后向前看,查找src/scss目錄的SCSS文件,輸出(-o 標(biāo)識(shí))編譯的CSS到dist/css目錄,壓縮輸出文件(使用 --output-style 標(biāo)識(shí),設(shè)置選項(xiàng)值為"compressed")。
node-sass
3.2 PostCSS自動(dòng)給CSS加前綴
npm install --save-dev postcss-cli autoprefixer
"scripts": {
...
"autoprefixer": "postcss -u autoprefixer -r dist/css/*"
}
嗨postcss,使用(-u標(biāo)識(shí)符)Autoprefixer替換(-r標(biāo)識(shí)符)dist/css目錄下的所有.css文件,給他們添加廠商前綴代碼。
配置你自己的構(gòu)建代碼有很多選項(xiàng)可以使用:postcss-cli 和autoprefixer
3.3 JavaScript 代碼檢查
npm i -D eslint
npm install --save-dev eslint 和上面的代碼有相關(guān)的效果
eslint --init // 譯者注:這里直接使用會(huì)拋錯(cuò)eslint找不到,因?yàn)檫@種使用方法必須安裝在全局,即通過 npm install i -g eslint方式安裝
"scripts": {
...
"lint": "eslint src/js"
}
查找src/js目錄下的所有JavaScript文件,并根據(jù)剛才生成的規(guī)則進(jìn)行代碼檢測(cè)。
eslint 和 eslint doc 和 eslint config
3.4 混淆壓縮JavaScript文件
npm i -D uglify-js
"scripts": {
...
"uglify": "mkdir -p dist/js && uglifyjs src/js/*.js -m -o dist/js/app.js"
}
這個(gè)任務(wù)使用了兩個(gè)標(biāo)準(zhǔn)命令行特性:mkdir 和 &&。
- 這個(gè)任務(wù)的第一部分“ mkdir -p dist/js”:如果不存在目錄(-p標(biāo)識(shí))就創(chuàng)建一個(gè)目錄結(jié)構(gòu)(mkdir),創(chuàng)建成功后執(zhí)行uglifyjs命令。&&幫助你連接多個(gè)命令,如果前一個(gè)命令成功執(zhí)行的話,就分別順序執(zhí)行剩余的命令。
- 這個(gè)任務(wù)的第二部分告訴uglifyjs針對(duì)
src/js/目錄下的所有JS文件(*.js),使用"mangle"命令(-m 標(biāo)識(shí)),輸出結(jié)果到dist/js/app.js文件中。這里是uglifyjs工具的全部配置選項(xiàng) list of options。
讓我們來更新一下uglify任務(wù),創(chuàng)建一個(gè)dist/js/app.js的壓縮版本,鏈接另外一個(gè)uglifyjs的命令并傳參給"compress"(-c標(biāo)識(shí))。
"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"
}
3.5 壓縮圖片
npm i -D imagemin-cli
"scripts": {
... "
imagemin": "imagemin src/images dist/images -p"
}
這個(gè)任務(wù)告訴imagemin找到并壓縮src/images中的所有圖片并輸出到dist/images中。-p標(biāo)志在允許的情況下將圖片處理成漸進(jìn)圖片。更多配置可查看文檔 all available options
imagemin-cli
3.6 SVG精靈(Sprites)
npm i -D svgo svg-sprite-generator
"scripts": {
...
"icons": "svgo -f src/images/icons && mkdir -p dist/images && svg-sprite-generate -d src/images/icons -o dist/images/icons.svg"
}
注意icons任務(wù)通過兩個(gè)&&引導(dǎo)符做了三件事情:
- 使用svgo傳參一個(gè)SVG目錄(-f標(biāo)識(shí)),這個(gè)操作壓縮了目錄內(nèi)的全部SVG文件;
- 如果不存在'dist/images'目錄則創(chuàng)建該目錄(使用mkdir -p命令);
- 使用svg-sprite-generator,傳參一個(gè)SVG目錄(-d標(biāo)識(shí))以及輸出處理后的SVG文件的目錄路徑名(-o標(biāo)識(shí))。
安裝svg-sprite-generator,用于自動(dòng)處理并整合多個(gè)SVG文件為一個(gè)SVG文件(更多處理方案:more on that technique here)。
3.7 通過BrowserSync提供服務(wù)、自動(dòng)監(jiān)測(cè)并注入變更
npm i -D browser-sync
BrowserSync,它可以做如下事情:?jiǎn)?dòng)一個(gè)本地服務(wù),向連接的瀏覽器自動(dòng)注入更新的文件,并同步瀏覽器的點(diǎn)擊和滾動(dòng)。
"scripts": {
...
"serve": "browser-sync start --server --files 'dist/css/*.css, dist/js/*.js'"
}
BrowserSync任務(wù)默認(rèn)使用當(dāng)前根目錄下的路徑啟動(dòng)一個(gè)服務(wù)器(--server標(biāo)識(shí)),--files標(biāo)識(shí)告訴BrowserSync去監(jiān)測(cè)dist目錄的CSS或JS文件,一旦有任何變化,則自動(dòng)向頁(yè)面注入變化的文件。
3.8 分組任務(wù)
使用以上任務(wù)我們可以做到如下功能:
- 編譯SCSS到CSS并自動(dòng)添加廠商前綴
- 對(duì)Javascript進(jìn)行代碼檢查及混淆壓縮
- 壓縮圖片
- 整合整個(gè)文件夾內(nèi)的SVG文件為一個(gè)SVG文件
- 啟動(dòng)一個(gè)本地服務(wù)并向連接至該服務(wù)的瀏覽器自動(dòng)注入更新。
這還不是全部?jī)?nèi)容!
4. 合并任務(wù)
4.1 合并CSS任務(wù)
我們會(huì)添加一個(gè)新的任務(wù),用于合并兩個(gè)CSS相關(guān)的任務(wù)(處理SASS和執(zhí)行加前綴的Autoprefixer),有了這個(gè)任務(wù)我們就不用分別執(zhí)行兩個(gè)相關(guān)任務(wù)了:
"scripts": {
...
"build:css": "npm run scss && npm run autoprefixer"
}
4.2 合并JavaScript任務(wù)
"scripts": {
...
"build:js": "npm run lint && npm run uglify"
}
我們可以通過npm run build:js一步調(diào)用,來進(jìn)行代碼檢測(cè)、混淆壓縮JavaScript代碼了!
4.3 合并剩余任務(wù)
對(duì)于圖片任務(wù)、其他剩余構(gòu)建任務(wù),我們可以用相同的方法把他們變成一個(gè)任務(wù):
"scripts": {
...
"build:images": "npm run imagemin && npm run icons",
"build:all": "npm run build:css && npm run build:js && npm run build:images"
}
4.4 變更監(jiān)控
我們的任務(wù)不斷的需要對(duì)文件做一些變更,我們不斷的需要切回命令行去運(yùn)行相應(yīng)的任務(wù)。針對(duì)這個(gè)問題,我們可以添加一個(gè)任務(wù)來監(jiān)聽文件變更,讓文件在變更的時(shí)候自動(dòng)執(zhí)行這些任務(wù)。這里我推薦使用onchange插件,安裝方法如下:
npm i -D onchange
"scripts": {
...
"watch:css": "onchange 'src/scss/*.scss' -- npm run build:css",
"watch:js": "onchange 'src/js/*.js' -- npm run build:js"
}
onchange需要你傳參想要監(jiān)控的文件路徑(字符串),這里我們傳的是SCSS和JS源文件,我們想要運(yùn)行的命令跟在--之后,這個(gè)命令當(dāng)路徑內(nèi)的文件發(fā)生增刪改的時(shí)候就會(huì)被立即執(zhí)行。
4.5 讓我們?cè)偬砑右粋€(gè)監(jiān)控命令來完成我們的npm scripts構(gòu)建過程。
再添加一個(gè)包,parallelshell:
npm i -D parallelshell
"scripts": {
...
"watch:all": "parallelshell 'npm run serve' 'npm run watch:css' 'npm run watch:js'"
}
parallelshell支持多個(gè)參數(shù)字符串,它會(huì)給npm run傳多個(gè)任務(wù)用于執(zhí)行。
為什么時(shí)候parallelshell去合并多個(gè)任務(wù),而不是像之前的任務(wù)一樣使用&&呢?最開始我也嘗試這么做了,但是問題是:&&鏈接多個(gè)命令到一塊,需要等待每一個(gè)命令成功完成后才會(huì)執(zhí)行下一個(gè)任務(wù)。然而當(dāng)我們運(yùn)行watch命令時(shí),這些命令一直都不會(huì)結(jié)束!這樣我們就會(huì)卡在一個(gè)無限循環(huán)里。
因此,使用parallelshell使得我們可以同時(shí)執(zhí)行多個(gè)watch命令。(譯者注:后來在評(píng)論里有人推薦使用npm-run-all插件來代替parallelshell,它支持這種用法可以一次性檢測(cè)全部watch任務(wù)更加方便:"watch": "npm-run-all --parallel serve watch:*")
這個(gè)任務(wù)使用了BrowserSync的npm run serve任務(wù)啟動(dòng)了一個(gè)服務(wù),然后對(duì)CSS和JavaScript文件執(zhí)行了監(jiān)控命令,一旦CSS或JavaScript文件有變更,監(jiān)控任務(wù)就會(huì)執(zhí)行相應(yīng)的構(gòu)建(build)任務(wù)。由于BrowserSync被設(shè)置成監(jiān)控dist目錄下的變更,所以它會(huì)自動(dòng)的向相關(guān)聯(lián)的URL內(nèi)注入新的文件,真是太棒了!
4.6 其他實(shí)用任務(wù)
npm有大量可以實(shí)用的插件(ots of baked in tasks ),讓我們?cè)偬砑右粋€(gè)新的任務(wù)來看看這些插件對(duì)構(gòu)建腳本的影響:
"scripts": {
...
"postinstall": "npm run watch:all"
}
當(dāng)你在命令行中執(zhí)行npm install的時(shí)候postinstall會(huì)立即執(zhí)行,當(dāng)團(tuán)隊(duì)合作時(shí)這個(gè)功能非常有用。當(dāng)別人復(fù)制了你的項(xiàng)目并運(yùn)行了npm install的時(shí)候,我們的watch:all任務(wù)就會(huì)馬上執(zhí)行,別人馬上就會(huì)準(zhǔn)備好一切開發(fā)環(huán)境:?jiǎn)?dòng)一個(gè)服務(wù)、打開一個(gè)瀏覽器窗口、監(jiān)控文件變更。
4.7 打包
萬(wàn)一你忘記了什么知識(shí)點(diǎn),我用以上所有提到的任務(wù)創(chuàng)建了一個(gè)npm-build-boilerplate 項(xiàng)目以方便你學(xué)習(xí)。