確認(rèn)過眼神,你還是沒有準(zhǔn)備秋招的人?時間倉促。自京東6月8號開啟管培生的招聘,就意味著秋招的開始。然而你還在等著秋天的到來?今年形勢應(yīng)該更為嚴(yán)峻,隨著各大技術(shù)(vue,webpack,react,微信小程序)生態(tài)越來越成熟,這也意味著我們要更加深入的去了解他們,掌握他們。比如你寫vue項(xiàng)目,知道vue-cli。寫的項(xiàng)目也無以倫比,但是你是否又會去了解下vue-cli到底發(fā)生了什么?或許這就是面試官要問你的問題:請手寫一個webpack4.0的配置。
前言
機(jī)會總是留給有準(zhǔn)備的人,要想在這兵荒馬亂的求職季里出類拔萃,拿下你心中期待已久的offer。那么你更因該知道很多別人不知道的東西,你的羽翼才能豐滿,才能翱翔于天際。鷹擊長空,靠的不是天生,而是年少時斷崖之險(xiǎn)。笨鳥先飛,靠的不是智慧,而是孜孜不倦的努力。
webpack詳解
webpack是一個打包工具,他的宗旨是一切靜態(tài)資源即可打包。有人就會問為什么要webpack?webpack是現(xiàn)代前端技術(shù)的基石,常規(guī)的開發(fā)方式,比如jquery,html,css靜態(tài)網(wǎng)頁開發(fā)已經(jīng)落后了。現(xiàn)在是MVVM的時代,數(shù)據(jù)驅(qū)動界面。webpack將現(xiàn)代js開發(fā)中的各種新型有用的技術(shù),集合打包。webpack的描述鋪天蓋地,我就不浪費(fèi)大家的時間了。理解下這種圖就知道webpack的生態(tài)圈了:
webpack4.0的配置
const path = require('path'); //引入node的path模塊
const webpack = require('webpack'); //引入的webpack,使用lodash
const HtmlWebpackPlugin = require('html-webpack-plugin') //將html打包
const ExtractTextPlugin = require('extract-text-webpack-plugin') //打包的css拆分,將一部分抽離出來?
const CopyWebpackPlugin = require('copy-webpack-plugin')
// console.log(path.resolve(__dirname,'dist')); //物理地址拼接
module.exports = {
? ? entry: './src/index.js', //入口文件? 在vue-cli main.js
? ? output: { //webpack如何輸出
? ? ? ? path: path.resolve(__dirname, 'dist'), //定位,輸出文件的目標(biāo)路徑
? ? ? ? filename: '[name].js'
},
module: { //模塊的相關(guān)配置
? ? ? ? rules: [ //根據(jù)文件的后綴提供一個loader,解析規(guī)則
{
? ? ? ? ? ? ? ? test: /.js$/, //es6 => es5
? ? ? ? ? ? ? ? include: [
? ? ? ? ? ? ? ? ? ? path.resolve(__dirname, 'src')
],
// exclude:[], 不匹配選項(xiàng)(優(yōu)先級高于test和include)
use: 'babel-loader'
},
{
? ? ? ? ? ? ? ? test: /.less$/,
use: ExtractTextPlugin.extract({
? ? ? ? ? ? ? ? ? ? fallback: 'style-loader',
use: [
'css-loader',
'less-loader'
]
})
},
{ //圖片loader
? ? ? ? ? ? ? ? test: /.(png|jpg|gif)$/,
use: [
{
? ? ? ? ? ? ? ? ? ? ? ? loader: 'file-loader' //根據(jù)文件地址加載文件
}
]
}
]
},
? ? resolve: { //解析模塊的可選項(xiàng)?
// modules: [ ]//模塊的查找目錄 配置其他的css等文件
? ? ? ? extensions: [".js", ".json", ".jsx",".less", ".css"], //用到文件的擴(kuò)展名
alias: { //模快別名列表
? ? ? ? ? ? utils: path.resolve(__dirname,'src/utils')
}
},
? ? plugins: [ //插進(jìn)的引用, 壓縮,分離美化
new ExtractTextPlugin('[name].css'), //[name] 默認(rèn)? 也可以自定義name? 聲明使用
new HtmlWebpackPlugin({ //將模板的頭部和尾部添加css和js模板,dist 目錄發(fā)布到服務(wù)器上,項(xiàng)目包。可以直接上線
? ? ? ? ? ? file: 'index.html', //打造單頁面運(yùn)用 最后運(yùn)行的不是這個
template: 'src/index.html' //vue-cli放在跟目錄下
}),
new CopyWebpackPlugin([ //src下其他的文件直接復(fù)制到dist目錄下
{ from:'src/assets/favicon.ico',to: 'favicon.ico' }
]),
new webpack.ProvidePlugin({ //引用框架 jquery? lodash工具庫是很多組件會復(fù)用的,省去了import
'_': 'lodash' //引用webpack
})
],
? ? devServer: { //服務(wù)于webpack-dev-server? 內(nèi)部封裝了一個express
? ? ? ? port: '8080',
? ? ? ? before(app) {
? ? ? ? ? ? app.get('/api/test.json', (req, res) => {
? ? ? ? ? ? ? ? res.json({
? ? ? ? ? ? ? ? ? ? code: 200,
? ? ? ? ? ? ? ? ? ? message: 'Hello World'
})
})
}
}
}
一、前端環(huán)境搭建
我們使用npm或yarn來安裝webpack。
npm install webpack webpack-cli -g
# 或者
yarn global add webpack webpack-cli
為什么webpack會分為兩個文件呢?在webpack3中,webpack本身和它的cli以前都是在同一個包中,但在第4版中,他們已經(jīng)將兩者分開來更好地管理它們。
新建一個webpack的文件夾,在其下新建一個try-webpack(防止init時項(xiàng)目名和安裝包同名)并初始化和配置webpack。
npm init -y? //-y 默認(rèn)所有的配置
yarn add webpack webpack-cli -D? //-D webpack安裝在devDependencies環(huán)境中
二、部署webpack
在上面搭建好的環(huán)境項(xiàng)目中,我們來到package.json里配置我們的scripts。
"scripts": {
"build": "webpack --mode production" //我們在這里配置,就可以使用npm run build 啟動我們的webpack
},
"devDependencies": {
"webpack": "^4.16.0",
"webpack-cli": "^3.0.8"
}
配置好我們webpack的運(yùn)行環(huán)境時,聯(lián)想下vue-cli。平時使用vue-cli會自動幫我們配置并生成項(xiàng)目。我們在src下進(jìn)行項(xiàng)目的開發(fā),最后npm run build 打包生成我們的dist的目錄。不知道你是否還記得,還是讓我們進(jìn)入下一節(jié)讓我們感受下這其中的正個流程吧。
三、npm run build 發(fā)生了什么
在我們的根項(xiàng)目下try-webpack新建一個src目錄。在src目錄下新建一個index.js文件。在里面我們可以寫任意的代碼,以案例為主:
const a = 1;
寫完之后我們在終端運(yùn)行我們的命令: npm run build ,你就會發(fā)現(xiàn)新增了一個dist目錄,里面存放著webpack打包好的main.js文件。這和我們在vue-cli里操作是一樣的。
四、webpackp配置流程篇
我們在開發(fā)是一般會打包src下的什么文件呢?我們可以回憶一下,其實(shí)vue-cli項(xiàng)目src下不就這幾點(diǎn)嘛:
發(fā)布時需要的html,css,js
css預(yù)編譯器stylus,less,sass
es6的高級語法
圖片資源.png,.gif,.ico,.jpg
文件間的require
別名@等修飾符
那么我將會分這幾點(diǎn)來講解webpack中webpack.config.js的配置,跟著腳步,一步一步的來完成我們的流程線。
??Html在webpack中的配置
在項(xiàng)目的根目錄try-webpack下新建webpack.config.js文件,以commonJS模塊化機(jī)制向外輸出,并且新建一個index.html。
module.exports = {}
配置我們的入口entry,在vue-cli里相當(dāng)于跟目錄下的main.js,我們的出口output。我們可以把webpack理解為一個工廠,進(jìn)入相當(dāng)于把各種各樣的原料放進(jìn)我們的工廠了,然后工廠進(jìn)行一系列的打包操作把打包好的東西,向外輸出,然后就可以去出售了(上線)。
const path = require('path'); //引入我們的node模塊里的path
//測試下 console.log(path.resolve(__dirname,'dist')); //物理地址拼接
module.exports = {
? ? entry: './src/index.js', //入口文件? 在vue-cli main.js
? ? output: { //webpack如何向外輸出
? ? ? ? path: path.resolve(__dirname, 'dist'),//定位,輸出文件的目標(biāo)路徑
? ? ? ? filename: '[name].js' //文件名[name].js默認(rèn),也可自行配置
},
HTML打包我們需要安裝引入html-webpack-plugin
yarn add html-webpack-plugin -D //在開發(fā)環(huán)境中安裝
const HtmlWebpackPlugin = require('html-webpack-plugin') //引入打包我們的HTML
在module.exports里配置我們的plugins(插件):
plugins: [ //插進(jìn)的引用, 壓縮,分離美化
new HtmlWebpackPlugin({ //將模板的頭部和尾部添加css和js模板,dist 目錄發(fā)布到服務(wù)器上,項(xiàng)目包。可以直接上線
? ? ? ? ? ? file: 'index.html', //打造單頁面運(yùn)用 最后運(yùn)行的不是這個
template: 'src/index.html' //vue-cli放在跟目錄下
}),
],
配置好后,在終端輸入npm run dev后webpack將我們的html打包好并且自動將我們的js引進(jìn)來了。
Hello World
live-sever我們的dist目錄,啟動一個8080端口,我們就可以看到我們的Hello World了。這就是我們上線版的頁面。
??css在webpack中的配置
在我們vue-cli里,我們可以使用css去寫我們的樣式,也可以使用高級stylus,less,sass等預(yù)編譯器。這里就以less為例,看看webpack怎么將他打包成一個css。
.main {
? color: red;
}
在src目錄下新建我們的style.less文件,在配置之前我們需要npm我們的css-loader和sass-loader,sass:
yarn add css-loader less less-loader style-loader-D
執(zhí)行完上述命令我們在packge.json里可以看到我們的配置文件:
"devDependencies": {
"css-loader": "^1.0.0",
"html-webpack-plugin": "^3.2.0",
"sass": "^1.9.0",
"sass-loader": "^7.0.3",
"webpack": "^4.16.0",
"webpack-cli": "^3.0.8"
}
安裝好后,我們開始配置webpack.config.js文件。這里申明一下,我們的css在dist目錄下需要和我們的HTML分離,這是還需引入我們的extract-text-webpack-plugin,先然我們安裝下:
yarn add extract-text-webpack-plugin-D
這里有一個坑,extract-text-webpack-plugin在4.0并不支持這樣的安裝,大家可自行chrome。于是我們選擇換一種方式,選擇4.00-beta.0版本的:
yarn add extract-text-webpack-plugin@last-D
來到我們的module.exports里,完成moudel的配置:
const ExtractTextPlugin = require('extract-text-webpack-plugin') //打包的css拆分,將一部分抽離出來?
module: { //模塊的相關(guān)配置
? ? ? ? rules: [ //根據(jù)文件的后綴提供一個loader,解析規(guī)則
{
? ? ? ? ? ? ? ? test: /.less$/, //正則匹配我們以.less結(jié)尾的文件
use: ExtractTextPlugin.extract({
? ? ? ? ? ? ? ? ? ? fallback: 'style-loader',
use: [
'css-loader',
'less-loader'
]
})
},
]},
? ? plugins:[
new ExtractTextPlugin('[name].css'), //[name] 默認(rèn)? 也可以自定義name? 聲明使用
]
我們在執(zhí)行我們的 npm run build 之后并沒有我們的css,為什么呢?原來在webpack配置里css in js。意思是在打包是我們的css是打包在我們的js里的,所有我們引入了extract-text-webpack-plugin插件將css從里面剝離出來。不過又一個問題,require的機(jī)制?
在我們打包過程中,文件的引用require 按照順序來打包,這就是文件依賴的機(jī)制。
打包好后我們在live-server,發(fā)現(xiàn)我們的樣式也上去了,并且css部分分離出來了。
??js在webpack中的配置
現(xiàn)在隨著es6的普及,越來越多的代碼使用es6了,但是很多瀏覽器并不支持es6,比如async/awiat,const。因此需要我們引用babe來把我們es6的代碼編譯為es5。在跟目錄下新建.babelrc,簡單配置下:
{"presets": ["env"]}
安裝我們的babel并在webpack.config.js里module/rules下進(jìn)行配置:
yarn add babel-loader babel-core? abel-preset-env -D? //babel基本的三個文件
{
? ? test: /.js$/, //es6 => es5
? ? include: [
? ? ? ? path.resolve(__dirname, 'src')
],
// exclude:[], 不匹配選項(xiàng)(優(yōu)先級高于test和include)
use: 'babel-loader'
},
??圖片資源在webpack中的配置
在src目錄下新建一個assets文件,里面放置幾張圖片。安裝file-loader根據(jù)文件地址加載文件:
yarn add file-loader -D
在webpack.config.js里module/rules:
{
? ? test: /.(png|jpg|gif)$/, //匹配所有格式的圖片資源
use: [
{
? ? ? ? ? ? loader: 'file-loader'
}
]
}
??別名(@)在webpack中的配置
在src/index.js里我們引入:
const format = require('utils/format') // utils ?? 沒有相對路徑? 回想@? => 別名
在src新建相應(yīng)的文件。在format.js里接受一個參數(shù)并把它轉(zhuǎn)成大寫
module.exports = function format(chars) {
return chars.toUpperCase()
}
在webpack中如何配置我們的別名呢?在vue-cli中我們經(jīng)常@一個文件夾,其意思就是在src目錄下,現(xiàn)在我們?nèi)ヒ惶骄烤埂T趍odule下,注意跟rules同級。
resolve: { //解析模塊的可選項(xiàng)?
// modules: [ ]//模塊的查找目錄 配置其他的css等文件
? ? ? ? extensions: [".js", ".json", ".jsx",".less", ".css"], //用到文件的擴(kuò)展名
alias: { //模快別名列表
? ? ? ? ? ? utils: path.resolve(__dirname,'src/utils')
}
},
??其他一些靜態(tài)資源在webpack中的配置
src下其他的文件直接復(fù)制到dist目錄下,并不是每個文件都需要打包處理的,很多資源可能直接就可以復(fù)制過去。使用我們的 CopyWebpackPlugin插件
引用框架 jquery lodash工具庫是很多組件會復(fù)用的,省去了import。使用webpack.ProvidePlugin插件
五、npm run dev 發(fā)生了什么
在vue-cli中我們啟動監(jiān)聽npm run dev可以時時監(jiān)控我們src下文件的改動,那他到底發(fā)生了什么呢。在webpack里其實(shí)創(chuàng)建了一個node進(jìn)程,通過webpack-dev-server其內(nèi)部封裝了一個node的express模塊,其配置項(xiàng)如下:
"scripts": { //在package.json里聲明下使用腳本 npm run dev
"build": "webpack --mode production",
"start": "webpack-dev-server --mode development"
},
devServer: { //在webpack.config.js里配置port
? ? ? ? port: '8080',
? ? ? ? before(app) {
? ? ? ? ? ? app.get('/api/test.json', (req, res) => {
? ? ? ? ? ? ? ? res.json({
? ? ? ? ? ? ? ? ? ? code: 200,
? ? ? ? ? ? ? ? ? ? message: 'Hello World'
})
})
}
} //服務(wù)于webpack-dev-server? 內(nèi)部封裝了一個express
寄語
webpack里面博大精深,這只是剛?cè)腴T。要研究其里面真正的東西,并非一朝一夕。tapable、webpack的生命周期等等。如果你想深入的理解webpack,推薦騰訊ivweb團(tuán)隊(duì)關(guān)于webpack的深入研究。這也是我最近在看的,只有理解更多,你才能飛的更遠(yuǎn)。夜深了,時間過的很快。樓主也太困了,停筆于此,望多多包涵。
編輯:千鋒HTML5
作者:WsmDyj