確認過眼神,你仍是沒有準備秋招的人?時間倉促。自京東6月8號開啓管培生的招聘,就意味着秋招的開始。然而你還在等着秋天的到來?今年形勢應該更爲嚴峻,隨着各大技術(vue,webpack,react,微信小程序)生態愈來愈成熟,這也意味着咱們要更加深刻的去了解他們,掌握他們。好比你寫vue項目,知道vue-cli。寫的項目也無以倫比,可是你是否又會去了解下vue-cli到底發生了什麼?或許這就是面試官要問你的問題:請手寫一個webpack4.0的配置。javascript
機會老是留給有準備的人,要想在這兵荒馬亂的求職季裏出類拔萃,拿下你心中期待已久的offer。那麼你更因該知道不少別人不知道的東西,你的羽翼才能豐滿,才能翱翔於天際。鷹擊長空,靠的不是天生,而是年少時斷崖之險。笨鳥先飛,靠的不是智慧,而是孜孜不倦的努力。css
webpack是一個打包工具,他的宗旨是一切靜態資源便可打包。有人就會問爲何要webpack?webpack是現代前端技術的基石,常規的開發方式,好比jquery,html,css靜態網頁開發已經落後了。如今是MVVM的時代,數據驅動界面。webpack將現代js開發中的各類新型有用的技術,集合打包。webpack的描述鋪天蓋地,我就不浪費你們的時間了。理解下這種圖就知道webpack的生態圈了: html
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'), //定位,輸出文件的目標路徑
filename: '[name].js'
},
module: { //模塊的相關配置
rules: [ //根據文件的後綴提供一個loader,解析規則
{
test: /\.js$/, //es6 => es5
include: [
path.resolve(__dirname, 'src')
],
// exclude:[], 不匹配選項(優先級高於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' //根據文件地址加載文件
}
]
}
]
},
resolve: { //解析模塊的可選項
// modules: [ ]//模塊的查找目錄 配置其餘的css等文件
extensions: [".js", ".json", ".jsx",".less", ".css"], //用到文件的擴展名
alias: { //模快別名列表
utils: path.resolve(__dirname,'src/utils')
}
},
plugins: [ //插進的引用, 壓縮,分離美化
new ExtractTextPlugin('[name].css'), //[name] 默認 也能夠自定義name 聲明使用
new HtmlWebpackPlugin({ //將模板的頭部和尾部添加css和js模板,dist 目錄發佈到服務器上,項目包。能夠直接上線
file: 'index.html', //打造單頁面運用 最後運行的不是這個
template: 'src/index.html' //vue-cli放在跟目錄下
}),
new CopyWebpackPlugin([ //src下其餘的文件直接複製到dist目錄下
{ from:'src/assets/favicon.ico',to: 'favicon.ico' }
]),
new webpack.ProvidePlugin({ //引用框架 jquery lodash工具庫是不少組件會複用的,省去了import
'_': 'lodash' //引用webpack
})
],
devServer: { //服務於webpack-dev-server 內部封裝了一個express
port: '8080',
before(app) {
app.get('/api/test.json', (req, res) => {
res.json({
code: 200,
message: 'Hello World'
})
})
}
}
}
複製代碼
咱們使用npm或yarn來安裝webpack前端
npm install webpack webpack-cli -g
# 或者
yarn global add webpack webpack-cli
複製代碼
爲何webpack會分爲兩個文件呢?在webpack3中,webpack自己和它的cli之前都是在同一個包中,但在第4版中,他們已經將二者分開來更好地管理它們。vue
新建一個webpack的文件夾,在其下新建一個try-webpack(防止init時項目名和安裝包同名)並初始化和配置webpack。java
npm init -y //-y 默認全部的配置
yarn add webpack webpack-cli -D //-D webpack安裝在devDependencies環境中
複製代碼
在上面搭建好的環境項目中,咱們來到package.json裏配置咱們的scripts,讓webpacknode
"scripts": {
"build": "webpack --mode production" //咱們在這裏配置,就可使用npm run build 啓動咱們的webpack
},
"devDependencies": {
"webpack": "^4.16.0",
"webpack-cli": "^3.0.8"
}
複製代碼
配置好咱們webpack的運行環境時,聯想下vue-cli。平時使用vue-cli會自動幫咱們配置並生成項目。咱們在src下進行項目的開發,最後npm run build 打包生成咱們的dist的目錄。不知道你是否還記得,仍是讓咱們進入下一節讓咱們感覺下這其中的正個流程吧。react
在咱們的根項目下try-webpack新建一個src目錄。在src目錄下新建一個index.js文件。在裏面咱們能夠寫任意的代碼,以案例爲主:jquery
const a = 1;webpack
寫完以後咱們在終端運行咱們的命令 npm run build;你就會發現新增了一個dist目錄,裏面存放着webpack打包好的main.js文件。這和咱們在vue-cli裏操做是同樣的。
咱們在開發是通常會打包src下的什麼文件呢?咱們能夠回憶一下,其實vue-cli項目src下不就這幾點嘛:
那麼我將會分這幾點來說解webpack中webpack.config.js的配置,跟着腳步,一步一步的來完成咱們的流程線。
在項目的根目錄try-webpack下新建webpack.config.js文件,以commonJS模塊化機制向外輸出,而且新建一個index.html。
module.exports = {}
配置咱們的入口entry,在vue-cli裏至關於跟目錄下的main.js,咱們的出口output。咱們能夠把webpack理解爲一個工廠,進入至關於把各類各樣的原料放進咱們的工廠了,而後工廠進行一系列的打包操做把打包好的東西,向外輸出,而後就能夠去出售了(上線)。
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'),//定位,輸出文件的目標路徑
filename: '[name].js' //文件名[name].js默認,也可自行配置
},
複製代碼
HTML打包咱們須要安裝引入html-webpack-plugin
yarn add html-webpack-plugin -D //在開發環境中安裝
const HtmlWebpackPlugin = require('html-webpack-plugin') //引入打包咱們的HTML
複製代碼
在module.exports裏配置咱們的plugins(插件):
plugins: [ //插進的引用, 壓縮,分離美化
new HtmlWebpackPlugin({ //將模板的頭部和尾部添加css和js模板,dist 目錄發佈到服務器上,項目包。能夠直接上線
file: 'index.html', //打造單頁面運用 最後運行的不是這個
template: 'src/index.html' //vue-cli放在跟目錄下
}),
],
複製代碼
配置好後,在終端輸入npm run dev後webpack將咱們的html打包好而且自動將咱們的js引進來了。
<body>
<p class="main">Hello World</p>
<script type="text/javascript" src="main.js"></script>
</body>
複製代碼
live-sever咱們的dist目錄,啓動一個8080端口,咱們就能夠看到咱們的Hello World了。這就是咱們上線版的頁面。
在咱們vue-cli裏,咱們可使用css去寫咱們的樣式,也可使用高級stylus,less,sass等預編譯器。這裏就以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
執行完上述命令咱們在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: { //模塊的相關配置
rules: [ //根據文件的後綴提供一個loader,解析規則
{
test: /\.less$/, //正則匹配咱們以.less結尾的文件
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
'css-loader',
'less-loader'
]
})
},
]},
plugins:[
new ExtractTextPlugin('[name].css'), //[name] 默認 也能夠自定義name 聲明使用
]
複製代碼
咱們在執行咱們的npm run build以後並無咱們的css,爲何呢?原來在webpack配置裏css in js。意思是在打包是咱們的css是打包在咱們的js裏的,全部咱們引入了extract-text-webpack-plugin插件將css從裏面剝離出來。不過又一個問題,require的機制?
在咱們打包過程當中,文件的引用require 按照順序來打包,這就是文件依賴的機制。
打包好後咱們在live-server,發現咱們的樣式也上去了,而且css部分分離出來了。
如今隨着es6的普及,愈來愈多的代碼使用es6了,可是不少瀏覽器並不支持es6,好比async/awiat,const。所以須要咱們引用babe來把咱們es6的代碼編譯爲es5。在跟目錄下新建.babelrc,簡單配置下
{"presets": ["env"]}
安裝咱們的babel並在webpack.config.js裏module/rules下進行配置
yarn add babel-loader babel-core abel-preset-env -D //babel基本的三個文件
{
test: /\.js$/, //es6 => es5
include: [
path.resolve(__dirname, 'src')
],
// exclude:[], 不匹配選項(優先級高於test和include)
use: 'babel-loader'
},
複製代碼
在src目錄下新建一個assets文件,裏面放置幾張圖片。安裝file-loader根據文件地址加載文件
yarn add file-loader -D 在webpack.config.js裏module/rules
{
test: /\.(png|jpg|gif)$/, //匹配全部格式的圖片資源
use: [
{
loader: 'file-loader'
}
]
}
複製代碼
在src/index.js裏咱們引入
const format = require('utils/format') // utils ? 沒有相對路徑 回想@ => 別名
在src新建相應的文件。在format.js裏接受一個參數並把它轉成大寫
module.exports = function format(chars) {
return chars.toUpperCase()
}
複製代碼
在webpack中如何配置咱們的別名呢?在vue-cli中咱們常常@一個文件夾,其意思就是在src目錄下,如今咱們去一探究竟。在module下,注意跟rules同級
resolve: { //解析模塊的可選項
// modules: [ ]//模塊的查找目錄 配置其餘的css等文件
extensions: [".js", ".json", ".jsx",".less", ".css"], //用到文件的擴展名
alias: { //模快別名列表
utils: path.resolve(__dirname,'src/utils')
}
},
複製代碼
在vue-cli中咱們啓動監聽npm run dev能夠時時監控咱們src下文件的改動,那他到底發生了什麼呢。在webpack裏其實建立了一個node進程,經過webpack-dev-server其內部封裝了一個node的express模塊,其配置項以下
"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'
})
})
}
} //服務於webpack-dev-server 內部封裝了一個express
複製代碼
webpack裏面博大精深,這只是剛入門。要研究其裏面真正的東西,並不是一朝一夕。tapable、webpack的生命週期等等。若是你想深刻的理解webpack,推薦騰訊ivweb團隊關於webpack的深刻研究。這也是我最近在看的,只有理解更多,你才能飛的更遠。夜深了,時間過的很快。樓主也太困了,停筆於此,望多多包涵。附上我github關於webpack4.0配置的學習demo點這裏。