
by yugasun from https://yugasun.com/post/you-may-not-know-vuejs-5.html
本文可全文轉(zhuǎn)載,但需要保留原作者和出處。
開(kāi)發(fā)環(huán)境
既然是實(shí)戰(zhàn),怎離不開(kāi)項(xiàng)目開(kāi)發(fā)的環(huán)境呢?先給大家推薦下我的個(gè)人開(kāi)發(fā)環(huán)境:
硬件設(shè)備:Mac OSX
編譯器:Visual Studio Code
命令行工具:iTerm2
調(diào)試工具:Chrome Dev tool + vue-devtools
版本管理:Git
具體工具的操作界面和如何使用,這里就不展示了。隨便用搜索引擎搜索,就是相關(guān)介紹。大家可以根據(jù)個(gè)人喜好,來(lái)選擇適合你的開(kāi)發(fā)環(huán)境。
模塊化開(kāi)發(fā)
前面的文章中使用 Vue,都是直接引入源碼方式來(lái)使用,但是實(shí)際開(kāi)發(fā)中項(xiàng)目一般很復(fù)雜,并且會(huì)涉及到很多頁(yè)面模板,不可能所有的功能我們都寫在同一個(gè)js文件,然后在通過(guò) script 標(biāo)簽引入,這樣項(xiàng)目大了會(huì)越來(lái)越不易維護(hù),所以項(xiàng)目需要模塊化開(kāi)發(fā)。
關(guān)于什么事模塊化,具體如何模塊化構(gòu)架我們的項(xiàng)目,推薦閱讀 JavaScript 模塊化入門Ⅰ:理解模塊 和 JavaScript 模塊化入門Ⅱ:模塊打包構(gòu)建。
當(dāng)項(xiàng)目代碼多了,我們的模塊文件越來(lái)越多,就需要工具來(lái)幫助我們更好的管理和打包這些模塊,讓我們能更好的關(guān)注模塊化開(kāi)發(fā),而不是這些瑣碎的事情。于是 webpack 類似的工具就應(yīng)運(yùn)而生,當(dāng)然除了 webpack 還有很多類似的工具,他們各有各的優(yōu)點(diǎn),比如:rollup、parcel...。
今后文章所有的實(shí)例將用到 webpack 的 3.x 版本工具來(lái)結(jié)合Vue 完成開(kāi)發(fā)工作。
初始 webpack
這里不得不說(shuō)一下,很多朋友在開(kāi)發(fā) Vue 項(xiàng)目的時(shí)候,一上來(lái)就使用 vue-cli 腳手架工具開(kāi)發(fā)項(xiàng)目,雖然可以很快的構(gòu)建項(xiàng)目模板,不用關(guān)注初始化配置問(wèn)題。但是我不建議這么做,因?yàn)橐簧蟻?lái)就是 vuejs + webpack + es6 + babel + eslint... 等各種工具,有人都還不知道他們是什么,就開(kāi)始用。出了問(wèn)題,就不知道如何是好。雖然借助搜索引擎可以幫助我們解決80%的難題,但還是需要花費(fèi)大量的精力去搜索查詢,不斷的嘗試,等問(wèn)題解決了,一天就過(guò)去了,得不償失啊。
所以我建議先從學(xué)會(huì)使用 webpack 開(kāi)始,一步一步的引入進(jìn)來(lái),會(huì)容易接受一些。畢竟這世界上大多數(shù)人都不是天才,要學(xué)會(huì)跑,得先學(xué)會(huì)走路。
雖然當(dāng)前社會(huì)比較浮躁,但是擁有一顆寧?kù)o的心,腳踏實(shí)地,才是成功之道啊~
好了廢話不多說(shuō),直接進(jìn)入今天的正題,使用 webpack 愉快的進(jìn)行 Vuejs 項(xiàng)目開(kāi)發(fā)。
在閱讀下面代碼之前,請(qǐng)?zhí)崆笆煜?nodejs 模塊的使用,包括基本的通過(guò) npm 安裝模塊依賴和如何引入第三方模塊使用,這里雖然會(huì)提到,但不會(huì)詳細(xì)解釋。
我們先新建一個(gè)項(xiàng)目文件夾,在根目錄下新建 index.html,代碼如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue webpack demo</title>
</head>
<body>
<div id="app"></div>
<script src="./build.js"></script>
</body>
</html>
命令行運(yùn)行 npm init,按照交互提示,填寫項(xiàng)目相關(guān)信息(當(dāng)然都是英文,不懂得直接翻一下就明白了),填寫完成后,項(xiàng)目根目錄下會(huì)出現(xiàn) package.json 文件(關(guān)于package.json文件內(nèi)容具體介紹,可以閱讀這篇文章:package.json文件)。然后通過(guò) npm 安裝我們需要的 vue 庫(kù):
# 添加 --save 參數(shù),會(huì)將 vue 依賴添加到 package.json 文件中
npm install vue --save
然后新建一個(gè) src 目錄,在 src 目錄下創(chuàng)建一個(gè) app.js 入口文件,代碼如下:
// 模塊化的引入 vue,并將其賦值給 Vue 變量
var Vue = require('vue')
new Vue({
el: "#app",
template: "<h1>{{ msg }}</h1>",
data () {
return {
msg: 'Hello Vue.js'
}
}
})
當(dāng)然 require 函數(shù)瀏覽器是無(wú)法識(shí)別的,這是就需要通過(guò) webpack 幫我們實(shí)現(xiàn)編譯打包工作,轉(zhuǎn)化為主流瀏覽器可是別的 ES5 代碼。
先安裝 webpack 包依賴:
# 添加 --save-dev 參數(shù),會(huì)將 webpack 開(kāi)發(fā)依賴添加到 package.json 文件中
npm install webpack --save-dev
然后在項(xiàng)目根目錄下創(chuàng)建 webpack.config.js 文件,代碼如下:
module.exports = {
// 入口文件
entry: './src/app.js',
// 編譯輸出文件
output: {
filename: 'build.js'
},
resolve: {
alias: {
// 因?yàn)槲覀冞@里用的是 require 引入方式,所以應(yīng)該使用vue.common.js/vue.js/vue.min.js
'vue$': 'vue/dist/vue.common.js'
}
}
}
因?yàn)樯厦娴?index.html 中引入的是編譯后的 build.js 文件,要看到開(kāi)發(fā)效果,就需要手動(dòng)運(yùn)行 webpack 打包命令:
./node_modules/.bin/webpack
這里如果你想直接運(yùn)行
webpack,那么就需要你的電腦全局安裝 webpack,可以通過(guò)運(yùn)行npm install webpack -g命令來(lái)全局安裝。
然后你會(huì)看到輸出以下結(jié)果:
$ webpack
Hash: 8a61c2605578f38f46cd
Version: webpack 3.10.0
Time: 386ms
Asset Size Chunks Chunk Names
build.js 104 kB 0 [emitted] main
[0] (webpack)/buildin/global.js 509 bytes {0} [built]
[1] ./src/app.js 148 bytes {0} [built]
+ 4 hidden modules
此時(shí)根目錄下就會(huì)出現(xiàn) build.js 文件,我們?cè)偻ㄟ^(guò)瀏覽器打開(kāi) index.html 文件,熟悉的畫(huà)面出現(xiàn)了,Hello Vue.js。
到這里一個(gè)簡(jiǎn)單的基于 vue + webpack 的項(xiàng)目就構(gòu)建完成了,是不是很簡(jiǎn)單,迫不及待想自己動(dòng)手試試呢?當(dāng)然 webpack 的功能遠(yuǎn)不止如此更詳細(xì)的功能,請(qǐng)閱讀 官方文檔,全面的了解下 webpack 的強(qiáng)大。
實(shí)時(shí)重新加載(live reloading)
上面的例子還有個(gè)問(wèn)題,就是每次我們更新了代碼,就需要重新進(jìn)行打包編譯,并手動(dòng)刷新瀏覽器,才能看到我們更改的效果,實(shí)在是太麻煩了。webpack 作者也考慮到了這個(gè)問(wèn)題,于是同時(shí)開(kāi)發(fā)了 webpack-dev-server 工具,來(lái)幫助我們實(shí)現(xiàn) live reloading 的功能,也就是當(dāng)我們更新代碼時(shí),瀏覽器會(huì)實(shí)時(shí)刷新,呈現(xiàn)更新后的效果。
趕緊用起來(lái)~ 先安裝下依賴:
npm install webpack-dev-server --save-dev
然后修改 webpack.config.js 配置文件如下:
module.exports = {
// 入口文件
entry: './src/app.js',
// 編譯輸出文件
output: {
filename: 'build.js'
},
resolve: {
alias: {
// 因?yàn)槲覀冞@里用的是 require 引入方式,所以應(yīng)該使用vue.common.js/vue.js/vue.min.js
'vue$': 'vue/dist/vue.common.js'
}
},
// 這里添加的是有關(guān) webpack-dev-server 的配置
devServer: {
// 這里定義 webpack-dev-server 開(kāi)啟的web服務(wù)的根目錄
contentBase: './'
}
}
然后執(zhí)行命令:
./node_modules/.bin/webpack-dev-server
控制臺(tái)會(huì)輸出一下內(nèi)容:
$ ./node_modules/.bin/webpack-dev-server
Project is running at http://localhost:8080/
webpack output is served from /
Content not from webpack is served from ./
Hash: d33155f6797f2c78c448
Version: webpack 3.10.0
Time: 903ms
Asset Size Chunks Chunk Names
build.js 627 kB 0 [emitted] [big] main
[0] (webpack)/buildin/global.js 509 bytes {0} [built]
[3] multi (webpack)-dev-server/client?http://localhost:8080 ./src/app.js 40 bytes {0} [built]
[4] (webpack)-dev-server/client?http://localhost:8080 7.91 kB {0} [built]
...
[28] ./node_modules/timers-browserify/main.js 1.9 kB {0} [built]
+ 15 hidden modules
webpack: Compiled successfully.
打開(kāi)瀏覽器,訪問(wèn): http://localhost:8080,此時(shí)我們熟悉的畫(huà)面又出現(xiàn)了,O(∩_∩)O~~。我們?cè)賴L試修改 app.js 中 msg 內(nèi)容,瀏覽器的內(nèi)容也會(huì)跟著變化,是不是很酷,趕緊動(dòng)手試試吧。
使用 npm 腳本
針對(duì)上面的打包命令 ./node_modules/.bin/webpack 和實(shí)時(shí)開(kāi)發(fā)命令 ./node_modules/.bin/webpack-dev-server,雖然你可以很快的在命令行復(fù)制粘貼輸入,但是第一次還是免不了動(dòng)手輸入。作為一個(gè)懶惰的程序員,怎么能接受敲擊這么多多余的字符呢?正好package.json 文件中 scripts 字段就可以幫助我們解決這個(gè)煩惱。
先來(lái)看下介紹:
scripts 是用來(lái)指定運(yùn)行腳本命令的npm命令行縮寫的,比如 start 指定了運(yùn)行
npm run start時(shí),所要執(zhí)行的相關(guān)命令。
好的,既然明白了它的作用,我們就來(lái)嘗試改寫 package.json 文件,修改 scripts 字段為如下內(nèi)容:
"scripts": {
"dev": "webpack-dev-server",
"build": "webpack"
}
然后,在命令行輸入:
npm run dev
你會(huì)發(fā)現(xiàn)跟執(zhí)行 ./node_modules/.bin/webpack-dev-server 是一樣的效果。
注意:這里在
scripts中指定webpack-dev-server命令是,省去了命令路徑,這是因?yàn)?,npm 在執(zhí)行腳本時(shí),會(huì)默認(rèn)優(yōu)先執(zhí)行當(dāng)前目錄下./node_modules/.bin/中的命令,如果找不到該命令,則會(huì)執(zhí)行全局命令。
同理,執(zhí)行 npm run build 就是打包輸出我們想要的 build.js 文件。
CSS預(yù)處理器
雖然 css 已經(jīng)足夠強(qiáng)大,但是在程序員眼里,它一直是個(gè)很麻煩的東西,它沒(méi)有變量,也沒(méi)有條件語(yǔ)句,只是單純的一行行的描述,寫起來(lái)相當(dāng)麻煩。于是各種 CSS預(yù)處理器 應(yīng)運(yùn)而生,其中我最喜歡的是 SASS,使用 sass 語(yǔ)法編寫我們的樣式文件,會(huì)大大提高我們的開(kāi)發(fā)效率,使得 css 工程化變得容易了很多。
接下來(lái)介紹下,如何集成到我們的項(xiàng)目中。
對(duì)于 webpack 來(lái)說(shuō) 一切皆模塊,所有的文件通過(guò)模塊引入的方式形成依賴關(guān)系,而對(duì)于每個(gè)模塊的引入或預(yù)處理,都是通過(guò) loader 來(lái)實(shí)現(xiàn)了。因?yàn)槲覀兊?sass 語(yǔ)法瀏覽器是無(wú)法識(shí)別的,所以在引入時(shí)需要使用相關(guān) loader 對(duì)其進(jìn)項(xiàng)預(yù)處理,轉(zhuǎn)化為相應(yīng)的 css。雖然 css 瀏覽器可以識(shí)別的,但是 webpack 本質(zhì)上是一個(gè) javascript 應(yīng)用程序的靜態(tài)模塊打包器,一切文件內(nèi)容都將處理為 javascript,然后進(jìn)行后期的處理。所以這里除了需要預(yù)處理 sass 的 loader,還需要加載 css 的 loader,最后還需要通過(guò) style-loader 來(lái)轉(zhuǎn)化為通過(guò) js 的方式動(dòng)態(tài)創(chuàng)建 style 標(biāo)簽到 index.html 中。
知道了這點(diǎn),我們就知道要怎么做了,首先安裝所需的 loader:
# 因?yàn)?`sass-loader` 需要依賴 `node-sass`, 所以這里一并安裝
npm install style-loader css-loader sass-loader node-sass --save-dev
修改 webpack.config.js 配置文件,添加相關(guān) loader 配置:
module.exports = {
//...
module: {
// 這里用來(lái)配置處理不同后綴文件所使用的loader
rules: [
{
test: /\.scss$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader'
},
{
loader: 'sass-loader'
}
]
}
]
}
}
webpack 的 loader 是支持鏈?zhǔn)絺鬟f的,它能夠?qū)Y源使用流水線(pipline)式處理,一組鏈?zhǔn)降?loader 將按照相反順序依次處理,這里的處理流程就是:
sass-loader -> css-loader => style-loader
配置好了,我們現(xiàn)在來(lái)測(cè)試下,在 src 目錄下創(chuàng)建一個(gè) app.scss 文件,內(nèi)容如下:
$red: rgb(218, 42, 42);
h1 {
color: $red;
}
然后在 src/app.js 文件中引入:
require('./app.scss');
var Vue = require('vue');
new Vue({
el: "#app",
template: "<h1>{{ msg }}</h1>",
data () {
return {
msg: 'Hello Vue.js'
}
}
});
此時(shí)再運(yùn)行 npm run dev,你會(huì)發(fā)現(xiàn)我們的 h1 標(biāo)簽顏色變了。通過(guò)審核元素,可以發(fā)現(xiàn) index.html 的 head 標(biāo)簽中新增了一個(gè) style 標(biāo)簽,內(nèi)容就是,app.scss 編譯輸出的內(nèi)容:
h1 {
color: #da2a2a;
}
如果還不清楚 sass 用法的,建議去看看這篇基礎(chǔ)介紹文檔:SASS用法指南
圖片加載
既然說(shuō)到了 css 靜態(tài)資源,自然免不了對(duì)于圖片的加載了。上文說(shuō)過(guò),在 webpack 中,一切皆模塊,圖片當(dāng)然也是以模塊的方式引入的。既然是模塊,自然少不了相關(guān)引入的 loader,這里圖片引入我們使用到的是 url-loader,先安裝下:
npm install url-loader --save-dev
添加 url-loader 配置:
module.exports = {
// ...
module: {
// 這里用來(lái)配置處理不同后綴文件所使用的loader
rules: [
// ...
{
test: /\.(jpe?g|gif|png)$/,
use: 'url-loader'
}
]
}
}
然后再 app.js 中引入:
require('./app.scss');
var Vue = require('vue');
var logoSrc = require('./logo.jpg')
new Vue({
el: "#app",
data () {
return {
msg: 'Hello Vue.js'
}
},
render (h) {
return (
h('div', [
h('img', {
domProps: {
src: logoSrc,
alt: 'logo',
className: 'logo'
}
}),
h('h1', this.msg)
])
)
}
});
這里我們用
render函數(shù)來(lái)自定義渲染我們的節(jié)點(diǎn),它含有默認(rèn)參數(shù)h就是我們 花式渲染目標(biāo)元素 講到的createElement參數(shù)的別名而已,這里為了書(shū)寫簡(jiǎn)單。h函數(shù)的第一個(gè)參數(shù)為dom名稱,第二個(gè)參數(shù)為創(chuàng)建時(shí)配置對(duì)象,通過(guò)domProps來(lái)添加 DOM 相關(guān)的屬性值。這里將我們引入的logoSrc賦值給它的src屬性。
然后再重新運(yùn)行 npm run dev,頁(yè)面中就出現(xiàn)了我們想要的 logo 圖片了。
總結(jié)
知己知彼,百戰(zhàn)不殆,我們只有真正了解了 webpack 的使用技巧,在實(shí)際開(kāi)發(fā)中,我們才會(huì)更加的得心應(yīng)手。不至于被一個(gè)莫名其妙的錯(cuò)誤個(gè)嚇到。程序員有三寶:多學(xué)習(xí),多編寫,多總結(jié),我們的編程技巧才能才會(huì)不斷提高。