工程化即供,簡單來說就是使小作坊生產(chǎn)變成流水線生產(chǎn)感局,實現(xiàn)自動化、模塊化琐凭、性能優(yōu)化等芽隆。
自動化可以通過命令行來實現(xiàn)。
實現(xiàn)從SCSS到CSS的自動化
- 全局安裝Node-sass node-sass
npm install -g node-sass
(事實上SASS是Ruby社區(qū)寫的) - 為了演示實現(xiàn)過程统屈,我先把目錄已有的一個style.css后綴改成style.scss
mv style.css style.scss
這樣直接改后綴是沒有問題的胚吁,因為SCSS是完全兼容CSS的,它只是在CSS語法上加上一些更高級的用法愁憔。 - 現(xiàn)在可以用node-sass把SCSS翻譯成CSS了
node-sass style.scss style.css
實際上現(xiàn)在只是將排版變得漂亮了一點腕扶,因為我們并沒有改SCSS的內(nèi)容。 - 在style.scss寫一些新語法吨掌,例如:
.topNavBar{
nav {
padding-top: 5px;
> ul {
list-style: none;
margin: 0;
padding: 0;
> li {
float: left;
margin-left: 17px;
margin-right: 17px;
position: relative;
> a {
font-size: 12px;
color: inherit;
font-weight: bold;
border-top: 3px solid transparent;
border-bottom: 3px solid transparent;
padding-top: 5px;
padding-bottom: 5px;
display: block;
position: relative;
}
}
}
}
}
- 再次運(yùn)行命令
node-sass style.scss style.css
半抱,可以看到style.css里對應(yīng)內(nèi)容已經(jīng)被翻譯成CSS語法:
.topNavBar nav {
padding-top: 5px; }
.topNavBar nav > ul {
list-style: none;
margin: 0;
padding: 0; }
.topNavBar nav > ul > li {
float: left;
margin-left: 17px;
margin-right: 17px;
position: relative; }
.topNavBar nav > ul > li > a {
font-size: 12px;
color: inherit;
font-weight: bold;
border-top: 3px solid transparent;
border-bottom: 3px solid transparent;
padding-top: 5px;
padding-bottom: 5px;
display: block;
position: relative; }
- 由于不能直接引入style.scss,現(xiàn)在每次改style.scss都要執(zhí)行一次命令將其翻譯成CSS語法膜宋,這樣寫豈不是很傻窿侈?
- 使用
-w
監(jiān)聽style.scss的變動,每次style.scss有改動都自動翻譯
node-sass style.scss style.css -w
如此就實現(xiàn)了從SCSS到CSS的自動化秋茫。
Babel自動將下一代JS代碼變成瀏覽器兼容的JS代碼
- 我在寫JS的時候已經(jīng)用到了很多新的語法史简,當(dāng)把代碼下發(fā)給很多用戶時,總會有不兼容的瀏覽器肛著,比如IE圆兵。我需要將使用了新語法代碼變?yōu)闉g覽器兼容的代碼
- Babel命令行可以實現(xiàn)這個需求。
- 安裝Babel
npm install --save-dev babel-cli
安裝之前應(yīng)該有package.json
策泣,如果沒有衙傀,新建一個。
npm init
可以創(chuàng)建一個合法的package.json
萨咕。
安裝完成后檢查一下package.json统抬,如果多出下面代碼,說明已經(jīng)成功將Babel安裝到項目中了。
{
"devDependencies": {
+ "babel-cli": "^6.0.0"
}
}
- 在package.json里加代碼:(如果有上一句聪建,記得寫逗號)
{
"name": "my-project",
"version": "1.0.0",
+ "scripts": {
+ "build": "babel src -d lib"
+ },
"devDependencies": {
"babel-cli": "^6.0.0"
}
}
- 根據(jù)文檔運(yùn)行
npm run build
钙畔,報錯。
為什么呢金麸?因為運(yùn)行npm run build
就是在運(yùn)行前面加的代碼babel src -d lib
擎析,也就是運(yùn)行npm run build
和直接運(yùn)行babel src -d lib
沒有任何區(qū)別。而我們的Babel是局部安裝的挥下,安裝在./node_modules/.bin/babel
揍魂,路徑?jīng)]有寫全當(dāng)然會報錯。
運(yùn)行./node_modules/.bin/babel src -d lib
相當(dāng)于第4步npm在scripts里加入的一句代碼棚瘟,反過來說现斋,當(dāng)npm運(yùn)行第4步所加的這句話的時候會優(yōu)先認(rèn)為babel是./node_modules/.bin/babel
,會優(yōu)先找這個路徑偎蘸。
命令行的實質(zhì)就是文件庄蹋,全局安裝和項目安裝的區(qū)別看這里 -
babel src -d lib
的意思是把src目錄的JS全部翻譯成兼容瀏覽器的JS,放在lib目錄里迷雪。d限书,destination。命令行基礎(chǔ)要扎實章咧,從一個字母猜到它的意思倦西。
例如,運(yùn)行./node_modules/.bin/babel js -d dist
赁严,將js目錄里的文件翻譯到dist目錄里 - 頁面中要引入/js的地方路徑改為/dist调限,也就是引入dist里面的js,而不是js里面的js
- 我們又遇到了跟上文寫SASS一樣的問題误澳,每次改寫js都要再執(zhí)行一次命令耻矮,很傻。babel也提供了跟SASS一樣的命令忆谓,讓它自動翻譯:
./node_modules/.bin/babel js -d dist --watch
整理代碼
按照前端一般的規(guī)范裆装,項目里有兩個大目錄,src(source)放未經(jīng)翻譯的代碼倡缠,dist(distribution)放待發(fā)布代碼哨免。如果有第三方代碼,放在node_modules里昙沦。
把所有html琢唾,SCSS,js盾饮,包括img都放進(jìn)src中采桃。
mkdir src
mkdir src/css
mv *.html src/
mv *.scss src/css
mv js/ src/
mv img src/
現(xiàn)在src目錄中包含一個首頁懒熙、一個css目錄、一個js目錄普办、一個img目錄工扎,整齊多了。(整理完要改引入文件的路徑)
雖然整齊了衔蹲,但是現(xiàn)在代碼不能運(yùn)行了肢娘,必須要做翻譯。
進(jìn)程1:
先用node-sass將src/css/
翻譯到dist/css/
并監(jiān)聽舆驶,輸出到一個目錄里要用-o
node-sass src/css -o dist/css -w
進(jìn)程2:
再用Babel將src/js/
翻譯到dist/js/
并監(jiān)聽
./node_modules/.bin/babel src/js/ -d dist/js/ --watch
進(jìn)程3橱健,進(jìn)程4:
此外,index.html和img目錄也需要被監(jiān)聽沙廉,每次有變化就拷貝到dist目錄畴博,這又需要兩個進(jìn)程。watch-cli
以上所實現(xiàn)的自動化蓝仲,是因為前端比較分裂,有人喜歡寫css官疲,有人喜歡寫sass袱结;有人喜歡寫ES5的JS,有人喜歡寫ES6的JS途凫,等等垢夹。用翻譯工具把它們自動翻譯成兼容瀏覽器的代碼,就是自動化维费。
如果有更復(fù)雜的需求果元,比如dist發(fā)布時加版本號,一旦有需求自動改版本號犀盟,則需要開更多的進(jìn)程而晒。請看Cache-Control 如何更新緩存
這一大堆進(jìn)程可以用一個工具實現(xiàn),一開始是Grunt阅畴,后來被更快的Gulp替代倡怎,再后來又被Webpack替代。
配置Webpack
- 在一個安全的目錄中演示
mkdir webpack-demo
cd webpack-demo
npm init -y
npm install webpack@3 webpack-cli --save-dev
演示webpack3
現(xiàn)在可以看到package.json中多了一條依賴:
"devDependencies": {
"webpack": "^3.12.0",
"webpack-cli": "^3.0.1"
}
- 創(chuàng)建配置文件
touch webpack.config.js
- 把
src/index.js
輸出為dist/bundle.js
贱枣,創(chuàng)建演示需要的目錄和文件
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
- 試一下监署,在index.js里寫入
let a = 1
console.log(a)
執(zhí)行命令npx webpack
或node_modules/.bin/webpack
可以看到當(dāng)前目錄里出現(xiàn)了dist/bundle.js
,可以在這個文件中找到index.js里的代碼纽哥,現(xiàn)在webpack可以做簡單的JS拷貝工作了钠乏。
- 繼續(xù)寫配置,讓JS兼容瀏覽器春塌,讓let變成var
babel-loader 7.x
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['env']
}
}
}
]
}
再次運(yùn)行npx webpack
晓避,報錯簇捍,找不到什么就npm install 找不到的東西
如果是找不到env
,npm install @babel/preset-env
運(yùn)行成功后够滑,dist/bundle.js
中的let
已經(jīng)變成var
了
- 使用模塊化
在當(dāng)前目錄下src/js目錄里創(chuàng)建module-1.js垦写,module-2.js和app.js三個文件:
//module-1.js
function fn(){
console.log(1)
}
export default fn //如果有人引用module-1.js,就默認(rèn)把fn傳給他
//module-2.js
function fn(){
console.log(2)
}
export default fn
//app.js
import x from './module-1'
import y from './module-2' //x彰触,y就是module-1梯投,module-2返回的fn
x()
y()
然后只需要把a(bǔ)pp.js翻譯成瀏覽器兼容的JS即可。更改webpack配置况毅,把src/js中的三個JS文件翻譯到dist/js/bundle.js中:
const path = require('path');
module.exports = {
entry: './src/js/app.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist/js')
}
};
再次運(yùn)行./node_modules/.bin/webpack
分蓖,可以看到結(jié)果三個文件輸出到了一個文件中:
bundle.js 3.27 kB 0 [emitted] main
[0] ./src/js/app.js 343 bytes {0} [built]
[1] ./src/js/module-1.js 141 bytes {0} [built]
[2] ./src/js/module-2.js 141 bytes {0} [built]
頁面中只需要引入一個bundle.js就可以了。
這樣就實現(xiàn)了JS的模塊化有JS自己來控制尔许,而不是在html里面控制么鹤。
- 用sass-loader把SCSS翻譯成CSS:
安裝sass-loader:npm install sass-loader node-sass webpack --save-dev
安裝style-loader和css-loader:npm install style-loader css-loader --save-dev
寫配置:
module: {
rules: [
{......}, //前面已有的配置
{
test: /\.scss$/,
use: [ //從下往上
"style-loader", // 用JS字符串創(chuàng)建style節(jié)點
"css-loader", // translates CSS into CommonJS 把css變成字符串
"sass-loader" // 把sass編譯成css
]
}]
}
模塊化:把src/css/main.scss
加載到dist/js/bundle.js
中變成一個字符串,等bundle.js運(yùn)行的時候把這個字符串放到頁面里的style標(biāo)簽里味廊。(css可以用字符串的形式存儲蒸甜,例如皮卡丘)
// src/js/app.js
import x from './module-1.js'
import y from './module-2.js'
import '../css/main.scss' //css也從這里引入
x()
y()
- 自動加前綴 postcss-loader
安裝postcss-loadernpm i -D postcss-loader
新建postcss.config.js寫配置:touch postcss.config.js
module.exports = {
//parser: 'sugarss',
plugins: {
'postcss-import': {},
'postcss-cssnext': {},
'cssnano': {}
}
}
寫webpack.config.js:
use: [
"style-loader",
"css-loader",
"postcss-loader", //必須寫在style-loader和css-loader之后,其他之前
"sass-loader"
]
再運(yùn)行./node_modules/.bin/webpack
余佛,看報錯柠新,找不到什么就安裝什么。
webpack每次需要實現(xiàn)一個功能都需要寫配置辉巡,很不方便恨憎。可以使用不需要寫配置的parcel代替它郊楣。