這篇文章是一年前寫(xiě)的定续,當(dāng)時(shí)還用著Webpack1.x谍咆,而如今Webpack已經(jīng)是3.x版本了,如果放著不更新難免會(huì)誤人子弟私股。感謝一些網(wǎng)友的正面反饋摹察,最近總算也抽出點(diǎn)時(shí)間來(lái)更新該文章。
0. 說(shuō)點(diǎn)廢話(huà)
從文章最初發(fā)布到如今已經(jīng)整整過(guò)去一年了倡鲸,這一年里面好事沒(méi)做多少供嚎,壞事倒是做了一大堆(包括問(wèn)候一些產(chǎn)品經(jīng)理)。在這一年里我接觸過(guò)前后端分離項(xiàng)目峭状,也接觸過(guò)一些基于Ruby On Rails的全棧式項(xiàng)目克滴。然而這一年來(lái)我卻并沒(méi)有掌握多少流行的前端框架,唯一能夠確定的是
- 寫(xiě)頁(yè)面的時(shí)候能夠有意識(shí)地用上HTML5的標(biāo)簽优床。
- 熟悉基本的CSS劝赔,能夠根據(jù)設(shè)計(jì)圖,寫(xiě)出酷炫(或者不酷炫)的頁(yè)面胆敞。
- 對(duì)JavaScript的了解更為深入(不只是停留在Hello World的層面)着帽。
或許我還不能算是一只合格的前端狗,我沒(méi)有熟練任何框架(如果JQuery也算的話(huà))移层,也沒(méi)有精力去折騰各種各樣的框架仍翰,我只想安安靜靜寫(xiě)樣式以及交互罷了。
1. 前言
今天的主題是Webpack观话,我似乎有點(diǎn)跑題了予借。關(guān)于如何用Webpack去搭建前端項(xiàng)目,Webpack官方文檔已經(jīng)有較為詳細(xì)的說(shuō)明匪燕,我們只需要自己著跟著文檔搭建蕾羊,掌握了套路之后便可根據(jù)自己的需求去搜索相關(guān)的插件來(lái)使用。
我這個(gè)Webpack腳手架并不是什么最佳實(shí)踐帽驯,它只是我能想到的最簡(jiǎn)單的實(shí)踐龟再,平時(shí)可以用來(lái)開(kāi)發(fā)靜態(tài)頁(yè)面。如果只是用來(lái)開(kāi)發(fā)靜態(tài)頁(yè)面那我覺(jué)得它應(yīng)該具有如下功能
- 簡(jiǎn)單易懂的目錄結(jié)構(gòu)尼变。
- 能夠自動(dòng)編譯Sass利凑,CoffeeScript等靜態(tài)資源文件。
- 修改HTML嫌术,CSS哀澈,JavaScript之后能夠動(dòng)態(tài)刷新頁(yè)面,不需要手動(dòng)進(jìn)行刷新度气。
下面我們逐步來(lái)實(shí)現(xiàn)這些功能割按,或者你可以直接從Github(這個(gè)不是master分支)上獲取相關(guān)代碼。
2. Webpack構(gòu)建簡(jiǎn)單的前端腳手架
從零開(kāi)始搭建Webpack服務(wù)沒(méi)有比官方文檔更詳細(xì)的了磷籍,我這里就順著文檔簡(jiǎn)單講講構(gòu)建流程适荣。
1) 初始化項(xiàng)目现柠,安裝Webpack
mkdir static-page && cd static-page # 創(chuàng)建并移動(dòng)到項(xiàng)目目錄
npm init -y # 生成項(xiàng)目信息,并把信息存放到 package.json文件中
npm install --save-dev webpack # 安裝webpack弛矛,由于只在開(kāi)發(fā)環(huán)境下會(huì)用到够吩,這里用了`--save-dev`標(biāo)識(shí)
完成之后我們目錄下會(huì)有這些文件
> ls
node_modules package.json
- node_modules 用來(lái)存放我們通過(guò)
npm
命令安裝的軟件。 - package.json 文件記錄該項(xiàng)目的元信息丈氓,以及一些依賴(lài)包信息周循。
2) 創(chuàng)建頁(yè)面文件,以及js入口文件
創(chuàng)建一個(gè)index.html
文件用于存放我們的頁(yè)面內(nèi)容万俗,我把它放在dist/
目錄里面湾笛,以及一個(gè)名為index.js
的webpack入口文件,我把它放在src/
目錄下面该编。
目錄結(jié)構(gòu)大概如下
├── dist
│ └── index.html
├── node_modules
├── package.json
└── src
└── index.js
PS: 所謂入口文件就是從這個(gè)文件中引入的資源都會(huì)被Webpack統(tǒng)一打包處理迄本,無(wú)論它是圖片資源,樣式資源课竣,還是JS資源嘉赎。Webpack會(huì)根據(jù)配置對(duì)不同類(lèi)型的資源文件進(jìn)行不同方式的處理。
<!-- dist/index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<h1>Ruby</h1>
</body>
</html>
// src/index.js
document.body.style.background = 'red'
簡(jiǎn)單起見(jiàn),這里的js只做了改變背景色的操作。大家都能看出來(lái)坷牛,目前兩個(gè)文件是還沒(méi)有關(guān)聯(lián)的肉盹,接下來(lái)我想辦法讓他們關(guān)聯(lián)起來(lái)看峻。這個(gè)時(shí)候就需要先配置Webpack,這里我采用了官方的配置。文件放在根目錄下的 webpack.config.js
文件中
// webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
配置文件都用js來(lái)寫(xiě)。寫(xiě)過(guò)js的人應(yīng)該很容易就可以理解关霸,它所代表的任務(wù)是解析入口文件./src/index.js
然后對(duì)資源進(jìn)行處理,最后把處理好的資源統(tǒng)一輸出到./dist/bundle.js
文件中杰扫。
配置好之后運(yùn)行命令
> ./node_modules/webpack/bin/webpack.js # 運(yùn)行我們一開(kāi)始安裝的Webpack
Hash: 15871b00d29beee17361
Version: webpack 3.8.1
Time: 63ms
Asset Size Chunks Chunk Names
bundle.js 2.51 kB 0 [emitted] main
[0] ./src/index.js 33 bytes {0} [built]
它會(huì)自動(dòng)尋找當(dāng)前目錄下的webpack.config.js
配置文件队寇,然后編譯并打包相應(yīng)的文件,現(xiàn)在我們的目錄結(jié)構(gòu)大概會(huì)是這樣了
.
├── dist
│ ├── bundle.js
│ └── index.html
├── node_modules
├── package.json
├── src
│ └── index.js
└── webpack.config.js
期望的出口文件已經(jīng)生成章姓,接下來(lái)只需要在html里面引入這個(gè)入口文件便可佳遣, 加上一行<script src="bundle.js"></script>
<html>
...
<body>
<script src="bundle.js"></script>
</body>
</html>
直接在瀏覽器打開(kāi)index.html
頁(yè)面就能看到如下效果。
這樣第一點(diǎn)就已經(jīng)完成了凡伊,它有良好的目錄結(jié)構(gòu)零渐,不過(guò)現(xiàn)在看來(lái)這種簡(jiǎn)單的目錄結(jié)構(gòu)我們自己也懂得怎么構(gòu)建,用Webpack的必要性似乎不大系忙。接下來(lái)我們看看如何用Webpack方便地管理Sass等靜態(tài)資源诵盼。
3) 編譯并打包Sass文件
現(xiàn)代的前端領(lǐng)域,為了方便樣式文件的管理與開(kāi)發(fā),我們一般會(huì)在項(xiàng)目引入Sass拦耐,或者Less這些技術(shù)耕腾,然而,瀏覽器卻無(wú)法直接解析這類(lèi)型的樣式文件杀糯,也就是說(shuō)如果要用到生產(chǎn)環(huán)境中,我們必須把這些資源進(jìn)行預(yù)編譯苍苞。
那么Webpack如何管理Sass資源呢固翰?很簡(jiǎn)單,我們只需要在入口文件src/index.js
里面引入Sass的文件便可羹呵。我們首先創(chuàng)建一個(gè)src/example.scss
的文件骂际,并像下面這般引入。
// src/example.scss /
body {
h1 {
color: #fff;
font-size: 40px;
font-family: fantasy;
}
}
// src/example.scss
import './example.scss';
document.body.style.background = 'red'
接下來(lái)在根目錄下運(yùn)行webpack的命令
./node_modules/webpack/bin/webpack.js
發(fā)現(xiàn)會(huì)有報(bào)錯(cuò)信息
ERROR in ./src/example.scss
Module parse failed: Unexpected token (1:5)
You may need an appropriate loader to handle this file type.
| body {
| h1 {
| color: #fff;
@ ./src/index.js 1:0-24
Webpack還是非常人性化的冈欢,它告訴我們?nèi)鄙倭撕线m的Loader用來(lái)加載對(duì)應(yīng)的Sass文件歉铝,如果沒(méi)有對(duì)應(yīng)的加載器則無(wú)法加載對(duì)應(yīng)的資源文件。而Webpack對(duì)應(yīng)的Sass加載器在這里凑耻。
只需要按照文檔的說(shuō)法太示,安裝缺少的加載器與編譯工具便可
npm install style-loader sass-loader node-sass css-loader --save-dev
具體每一個(gè)包有什么作用,文檔會(huì)提到香浩,這里不詳細(xì)說(shuō)类缤。接下來(lái)只需要把加載器的配置放到webpack.config.js
文件里面便可。
// webpack.config.js
module.exports = {
...
module: {
rules: [{
test: /\.scss$/,
use: [{
loader: "style-loader" // creates style nodes from JS strings
}, {
loader: "css-loader" // translates CSS into CommonJS
}, {
loader: "sass-loader" // compiles Sass to CSS
}]
}]
}
};
然后再次運(yùn)行Webpack的命令邻吭, 便可以編譯通過(guò)了餐弱。
如果我們不想要每次修改資源都運(yùn)行一次Webpack的命令,而是想讓W(xué)ebpack監(jiān)控我們的文件改動(dòng)囱晴,并自動(dòng)打包膏蚓,我們可以在命令后面加上--watch
標(biāo)識(shí)
> ./node_modules/webpack/bin/webpack.js --watch
Webpack is watching the files…
Hash: 691c616891a1a6c230b3
Version: webpack 3.8.1
Time: 698ms
Asset Size Chunks Chunk Names
bundle.js 19.1 kB 0 [emitted] main
[0] ./src/index.js 65 bytes {0} [built]
[1] ./src/example.scss 1.15 kB {0} [built]
[2] ./node_modules/css-loader!./node_modules/sass-loader/lib/loader.js!./src/example.scss 237 bytes {0} [built]
+ 3 hidden modules
這樣每次我們改動(dòng)資源文件,Webpack就會(huì)自動(dòng)重新編譯打包畸写,我們只管刷新頁(yè)面便可驮瞧。下面是我把字體顏色改成綠色之后直接刷新頁(yè)面的結(jié)果。
由于我們的Webpack服務(wù)開(kāi)啟了--watch
模式艺糜,我們不需要再次手動(dòng)去運(yùn)行Webpack命令重新打包資源剧董。
4) 頁(yè)面自動(dòng)刷新
如果每次改了樣式文件之后還要手動(dòng)刷新的話(huà),還是有點(diǎn)麻煩破停,效率還不夠高翅楼。有沒(méi)有辦法修改前端文件之后自動(dòng)刷新頁(yè)面?這個(gè)時(shí)候請(qǐng)出神器webpack-dev-server.
npm install --save-dev webpack-dev-server
簡(jiǎn)單配置一下webpack.config.js
文件真慢,加上下面配置
module.exports = {
.....
devServer: {
contentBase: './dist'
},
};
接下來(lái)運(yùn)行命令
./node_modules/webpack-dev-server/bin/webpack-dev-server.js
Project is running at http://localhost:8081/
webpack output is served from /
便可啟動(dòng)服務(wù)毅臊,我們只需要在瀏覽器訪問(wèn)http://localhost:8081/
這個(gè)地址便可。
此時(shí)簡(jiǎn)單改變一下我們的js文件的內(nèi)容黑界,改變背景色
import './example.scss';
document.body.style.background = 'blue'
我們不再需要手動(dòng)刷新頁(yè)面了管嬉,webpack會(huì)自動(dòng)被重新打包皂林,并使得頁(yè)面自動(dòng)刷新。
但這里有一個(gè)問(wèn)題蚯撩,如果我們?nèi)バ薷臎](méi)有被入口文件托管的文件础倍,比如index.html
文件,就算我們修改html文件的內(nèi)容胎挎,頁(yè)面也不會(huì)自動(dòng)更新沟启。
可見(jiàn)修改index.html
文件后需要要手動(dòng)刷新才行,要怎么使得當(dāng)HTML文件被修改后自動(dòng)刷新頁(yè)面呢犹菇?很簡(jiǎn)單
修改webpack.config.js
配置文件德迹,在devServer
上面加上watchContentBase: true
這個(gè)配置便可。
.....
module.exports = {
....
devServer: {
contentBase: './dist',
watchContentBase: true
},
....
};
結(jié)果如下
可見(jiàn)揭芍,當(dāng)我們修改index.html
文件的時(shí)候網(wǎng)頁(yè)會(huì)自動(dòng)刷新胳搞。
5) 還有點(diǎn)小問(wèn)題
這個(gè)問(wèn)題是我后來(lái)才發(fā)現(xiàn)的,我們?cè)谕ㄟ^(guò)webpack
命令生成了一個(gè)叫bundle.js
的文件称杨,但是很奇怪的是肌毅,當(dāng)我們刪除了這個(gè)文件之后運(yùn)行webpack-dev-server
這個(gè)服務(wù)的話(huà),它并不會(huì)重新生成這個(gè)文件列另。
> ls dist/
index.html
上面是我刪除了dist/bundle.js
并運(yùn)行webpack-dev-server
之后的結(jié)果芽腾,dist/
目錄下并不會(huì)重新生成bundle.js
文件。但是我們的服務(wù)并不會(huì)提示我們說(shuō)找不到bundle.js
這個(gè)文件页衙。我們的一切服務(wù)依然正常運(yùn)行摊滔。
這是因?yàn)?strong>webpack-dev-server
會(huì)把打包好的數(shù)據(jù)存在內(nèi)存中,并不會(huì)做文件IO操作店乐,所以我們看不到對(duì)應(yīng)文件的生成艰躺。
因此,如果我們使用webpack-dev-server
來(lái)輔助開(kāi)發(fā)的話(huà)其實(shí)是不會(huì)生成對(duì)應(yīng)出口文件的眨八,從內(nèi)存中加載數(shù)據(jù)往往效率更高腺兴。
3. 尾聲
有經(jīng)驗(yàn)的webpack使用者來(lái)說(shuō)或許不屑于像我這樣做,況且如今不同的框架官方都對(duì)webpack配置進(jìn)行了深度定制廉侧。在項(xiàng)目初始化的時(shí)候我們大可以站在巨人的肩膀上直接構(gòu)建項(xiàng)目腳手架页响。使用如create-react-app,vue-cli等腳手架工具來(lái)初始化我們的項(xiàng)目段誊。大家可以根據(jù)自己的技術(shù)棧來(lái)選擇合適的工具闰蚕。
前端技術(shù)著實(shí)讓人眼花繚亂,技術(shù)本身也參差不齊连舍,各種技術(shù)都有他們的優(yōu)缺點(diǎn)没陡,我以為能夠結(jié)合場(chǎng)景解決實(shí)際問(wèn)題的方案才能算是最佳實(shí)踐,我不排斥折騰,但我并不推薦瞎折騰盼玄。當(dāng)如今前端技術(shù)讓你難以選擇贴彼,并感到焦慮的時(shí)候,我建議可以先考慮從基礎(chǔ)入手埃儿,就是下面這三位
流行前后端分離的今天我們就一定要把我們的項(xiàng)目前后端分離嗎器仗?流行使用Vue,React這些框架的今天我們就必須拋棄JQuery嗎蝌箍?個(gè)人不敢茍同青灼,前后端分離的項(xiàng)目固然有它的優(yōu)勢(shì)。如果你正在使用前后端分離的方式去構(gòu)建一個(gè)簡(jiǎn)單的博客系統(tǒng)妓盲,或許你該靜下心來(lái)想想,這種選擇是否只是在增加開(kāi)發(fā)難度专普?
當(dāng)你手上有錘子的時(shí)候悯衬,看什么都像釘子。
很感謝看到這里檀夹。