1.為什么要使用webpack
現(xiàn)今的很多網(wǎng)頁(yè)其實(shí)可以看做是功能豐富的應(yīng)用,它們擁有著復(fù)雜的JavaScript代碼和一大堆依賴包碉就。為了簡(jiǎn)化開發(fā)的復(fù)雜度,前端社區(qū)涌現(xiàn)出了很多好的實(shí)踐方法。
1.模塊化滴铅,讓我們可以把復(fù)雜的程序細(xì)化為小的文件;
2.Scss,less等CSS預(yù)處理器就乓。
3.轉(zhuǎn)換es6語(yǔ)法的處理器等等汉匙。
這些改進(jìn)確實(shí)大大的提高了我們的開發(fā)效率,但是利用它們開發(fā)的文件往往需要進(jìn)行額外的處理才能讓瀏覽器識(shí)別,而手動(dòng)處理又是非常繁瑣的生蚁,這就為WebPack類的自動(dòng)化工具的出現(xiàn)提供了需求噩翠。
2.什么是webpack
WebPack可以看做是模塊打包機(jī)。
在 webpack 里邦投,所有類型的文件都可以是模塊伤锚,包含我們最常見的 JavaScript,以及 css 文件志衣、圖片屯援、json 文件等等猛们。通過(guò) webpack 的各種加載器,我們可以更有效地管理這些文件狞洋。它做的事情是弯淘,分析你的項(xiàng)目結(jié)構(gòu),找到JavaScript模塊以及其它的一些瀏覽器不能直接運(yùn)行的拓展語(yǔ)言(Scss吉懊,TypeScript等)庐橙,并將其打包為合適的格式以供瀏覽器使用。
3.WebPack和Grunt以及Gulp相比有什么特性
其實(shí)Webpack和另外兩個(gè)并沒(méi)有太多的可比性借嗽,Gulp/Grunt是一種能夠優(yōu)化前端的開發(fā)流程的工具态鳖,而WebPack是一種模塊化的解決方案,模塊化是其他構(gòu)件工具沒(méi)有的淹魄。gulp/grunt能做的郁惜,webpack也可以做。所以Webpack的優(yōu)點(diǎn)(模塊化)使得Webpack可以替代Gulp/Grunt類的工具甲锡。
Grunt和Gulp的工作方式是:在一個(gè)配置文件中兆蕉,指明對(duì)某些文件進(jìn)行類似編譯,組合缤沦,壓縮等任務(wù)的具體步驟虎韵,這個(gè)工具之后可以自動(dòng)替你完成這些任務(wù)。
Webpack的工作方式是:把你的項(xiàng)目當(dāng)做一個(gè)整體缸废,通過(guò)一個(gè)給定的主文件(如:index.js)包蓝,Webpack將從這個(gè)文件開始找到你的項(xiàng)目的所有依賴文件,使用loaders處理它們企量,最后打包為一個(gè)瀏覽器可識(shí)別的JavaScript文件测萎。
4.使用webpack
//全局安裝
npm install -g webpack
//安裝到你的項(xiàng)目目錄
npm install --save-dev webpack
正式使用Webpack前的準(zhǔn)備
1.建立新文件夾(本例命名為testwebpack)
2.在文件夾里面使用npm init 創(chuàng)建package.json
{
"name": "webpackee",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
}
注:name值不能和所安裝的包重名,否則安裝失敗届巩。所以本例用在webpack后面隨便加了兩個(gè)字母ee
3.使用npm install --save-dev命令安裝webpack硅瞧,安裝完成后如下
{
"name": "webpackee",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^2.6.1"
}
}
4.在testwebpack文件中創(chuàng)建兩個(gè)文件夾(src文件夾和public文件夾),
1.src文件夾放原始數(shù)據(jù)和我們將寫的JavaScript模塊恕汇、路由模塊等等
2.public文件夾用來(lái)存放準(zhǔn)備給瀏覽器讀取的數(shù)據(jù)(包括使用webpack生成的打包后的js文件以及一個(gè)index.html文件)
5.創(chuàng)建三個(gè)文件腕唧,index.html 文件放在public文件夾中,兩個(gè)js文件(Greeter.js和main.js)放在src文件夾中瘾英。
index.html文件只有最基礎(chǔ)的html代碼枣接,它唯一的目的就是加載打包后的js文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Webpack Sample Project</title>
</head>
<body>
<div id='root'>
</div>
<script src="bundle.js"></script>
</body>
</html>
greeter.js只包括一個(gè)用來(lái)返回包含問(wèn)候信息的html元素的函數(shù)。
// greeter.js
module.exports = function() {
var greet = document.createElement('div');
greet.textContent = "Hi there and greetings!";
return greet;
};
main.js用來(lái)把Greeter模塊返回的節(jié)點(diǎn)插入頁(yè)面缺谴。
//main.js
var greeter = require('./Greeter.js');
document.getElementById('root').appendChild(greeter());
通過(guò)配置文件來(lái)使用Webpack
1.在testwebpack文件中新建一個(gè)名為webpack.config.js的文件但惶,并在其中進(jìn)行最最簡(jiǎn)單的配置,如下所示,它包含入口文件路徑和存放打包后文件的地方的路徑榆骚。
module.exports = {
entry: __dirname + "/src/main.js",//唯一入口文件
output: {
path: __dirname + "/public",//打包后的文件存放的地方供src引入加載
filename: "bundle.js"http://打包后輸出文件的文件名
}
}
2.通過(guò)webpack 命令將文件打包到public文件夾中
$ webpack
3.也可以在package.json中配置腳本命令取代默認(rèn)的webpack命令片拍。
"scripts": {
"start": "webpack" //配置的地方就是這里啦,相當(dāng)于把npm的start命令指向webpack命令
},
注:npm的start是一個(gè)特殊的腳本名稱妓肢,它的特殊性表現(xiàn)在捌省,在命令行中使用npm start就可以執(zhí)行相關(guān)命令,如果對(duì)應(yīng)的此腳本名稱不是start碉钠,想要在命令行中運(yùn)行時(shí)纲缓,需要這樣用npm run scriptname如npm run build。
5.生成Source Maps(使調(diào)試更容易)
開發(fā)總是離不開調(diào)試喊废,如果可以更加方便的調(diào)試當(dāng)然就能提高開發(fā)效率祝高,不過(guò)網(wǎng)頁(yè)預(yù)覽的代碼一般和開發(fā)的代碼不一樣,比如scss文件網(wǎng)頁(yè)預(yù)覽的為css文件污筷。為了可以直接預(yù)覽scss等文件工闺,方便調(diào)試的Source Maps便出現(xiàn)了。
在webpack的配置文件中配置source maps瓣蛀,需要開啟谷歌的devtool工具陆蟆,f12-setting-Enable JavaScript source maps/Enable CSS source maps.
在本例中,隨便寫錯(cuò)一處代碼惋增,如
// greeter.js
module.exports = function() {
var greet = document.createElement('div');
greet.textContent = "Hi there and greetings!";
return greete;
};
本來(lái)應(yīng)該返回greet,我加了一個(gè)e,肯定會(huì)報(bào)錯(cuò)叠殷。但要是不用source maps,調(diào)試時(shí)候會(huì)顯示如下
上面只能定位到bundle這個(gè)js,不能定位到greeter.js這個(gè)文件,但使用了source maps诈皿,調(diào)試的時(shí)候顯示如下:
點(diǎn)擊greeter.js可直接跳到錯(cuò)誤處林束。
webpack配置source maps可在webpack.config.js添加devtool選項(xiàng)即可
module.exports = {
entry: __dirname + "/src/main.js",//唯一入口文件
output: {
path: __dirname + "/public",//打包后的文件存放的地方供src引入加載
filename: "bundle.js"http://打包后輸出文件的文件名
},
devtool: 'source-map',//配置生成Source Maps,選擇合適的選項(xiàng)
}
具體配置如下:
6.使用webpack構(gòu)建本地服務(wù)器
想不想讓你的瀏覽器監(jiān)測(cè)你的代碼的修改稽亏,并自動(dòng)刷新修改后的結(jié)果壶冒,其實(shí)Webpack提供一個(gè)可選的本地開發(fā)服務(wù)器,這個(gè)本地服務(wù)器基于node.js構(gòu)建截歉,可以實(shí)現(xiàn)你想要的這些功能胖腾,不過(guò)它是一個(gè)單獨(dú)的組件,在webpack中進(jìn)行配置之前需要單獨(dú)安裝它作為項(xiàng)目開發(fā)依賴怎披。
npm install --save-dev webpack-dev-server
然后在腳本命令行添加快捷命令:
{
"name": "webpack",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start":"webpack",
"server": "webpack-dev-server" //啟動(dòng)命令
},
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^2.6.1",
"webpack-dev-server": "^2.4.5"
}
}
在webpack.config.js中配置服務(wù)器
devServer: {
contentBase: "./public", //本地服務(wù)器所加載的頁(yè)面所在的目錄
open : true, //打開瀏覽器
port: 9000 //端口
}
其他配置可以參考官網(wǎng) https://doc.webpack-china.org/configuration/dev-server/
7.Loaders
Loaders是webpack中最讓人激動(dòng)人心的功能之一了胸嘁。通過(guò)使用不同的loader瓶摆,webpack通過(guò)調(diào)用外部的腳本或工具可以對(duì)各種各樣的格式的文件進(jìn)行處理凉逛,比如說(shuō)分析JSON文件并把它轉(zhuǎn)換為JavaScript文件,或者說(shuō)把下一代的JS文件(ES6群井,ES7)轉(zhuǎn)換為現(xiàn)代瀏覽器可以識(shí)別的JS文件状飞。或者說(shuō)對(duì)React的開發(fā)而言,合適的Loaders可以把React的JSX文件轉(zhuǎn)換為JS文件诬辈。
Loaders需要單獨(dú)安裝并且需要在webpack.config.js下的modules關(guān)鍵字下進(jìn)行配置.
注:webpack2.0之前的版本是按如下方式配置的
module: {
loaders: {...}
}
2.0之后的版本是按在rule配置的酵使,不多目前兩種方式都支持,以后會(huì)逐漸用第二種焙糟。
module: {
rules:[]
}
Loaders的配置選項(xiàng)包括以下幾方面:
1.test:接收一個(gè)匹配loaders所處理的文件的拓展名的正則表達(dá)式(必須)口渔,格式為
test: /\.json$/ //匹配json格式文件
2.loader:應(yīng)用loader的名稱(必須),格式為:
module: {
rules:[
{
test: /\.vue$/,
loader: "json-loader"
},
{
test: /\.js$/,
loader: ['babel-loader'],
},
]
}
webpack2以后為了更清晰支持 -loader省略的穿撮。但測(cè)試不能省略
應(yīng)用多個(gè) loader 和選項(xiàng)時(shí)候可以用use屬性(數(shù)組)
module: {
rules: [{
test: /\.vue$/,
use: ['vue-loader']
},
{
test: /\.js$/,
use: ['babel-loader'],
exclude: /node_modules/
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader', 'postcss-loader']
},
{
test: /\.(png|jpg|jpeg|gif|eot|ttf|woff|woff2|svg|svgz)(\?.+)?$/,
use: [{
loader: 'url-loader',
options: {
limit: 10000
}
}]
}
]
},
1.babel
Babel其實(shí)是幾個(gè)模塊化的包缺脉,其核心功能位于稱為babel-core的npm包中。對(duì)于每一個(gè)你需要的功能或拓展悦穿,你都需要安裝單獨(dú)的包(用得最多的是解析Es6的babel-preset-es2015包和解析JSX的babel-preset-react包)
我們先來(lái)一次性安裝這些依賴包
// npm一次性安裝多個(gè)依賴模塊攻礼,模塊之間用空格隔開
npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react
然后在webpack中配置
module: {
rules: [{
test: /\.(png|jpg)$/,
use: 'url-loader?limit=8192&name=images/[hash:8].[name].[ext]'
}, {
test: /\.json$/,
use: ['json-loader']
}, {
test: /\.js$/,
use: ['babel-loader'], //配置babel
}
]
},
然后在和webpack.config.js同級(jí)的目錄中建立 .babelrc 文件,命令如下
touch .babelrc
webpack會(huì)自動(dòng)調(diào)用.babelrc里的babel配置選項(xiàng)栗柒。babelrc里面的內(nèi)容如下:
{
"presets": ["es2015"]
}
現(xiàn)在就可以使用es6語(yǔ)法了礁扮,更改greeter.js文件內(nèi)容
// greeter.js
var img = require('./assets/cat01.png');
var config = require('./config.json');
//es5
// module.exports = function() {
// var greet = document.createElement('div');
// greet.innerHTML = "Hi there and greetings![圖片上傳失敗...(image-e75b6-1519957547350)]" + config.greetText + "";
// return greet;
// };
//es6
function fn() {
let greet = document.createElement('div');
greet.innerHTML = "Hi there and greetings![圖片上傳失敗...(image-a3fe33-1519957547350)]" + config.greetText + "";
return greet;
};
export {fn}; //導(dǎo)出
更改main.js文件內(nèi)容
//main.js
// var greeter = require('./greeter.js'); //es5
import { fn } from './greeter.js' //es6 導(dǎo)入
document.getElementById('root').appendChild(fn());
注:import和export必須配對(duì)使用,不能在greeter里面使用import瞬沦,main里面還使用require導(dǎo)入太伊,同理module.exports和require一起使用
開啟服務(wù)器
即可看到編譯成功。
注:主流瀏覽器支持大部分es6語(yǔ)法(比如本例的import和export)蛙埂,所以不用babel時(shí)候也可以編譯成功倦畅,經(jīng)本地測(cè)試ie10不支持let,所以本例用此命令編譯,ie10瀏覽器不顯示此js返回的內(nèi)容绣的,但使用了babel,ie10就可以看見此js返回的內(nèi)容
8.萬(wàn)物皆模塊
Webpack有一個(gè)不可不說(shuō)的優(yōu)點(diǎn)叠赐,它把所有的文件都可以當(dāng)做模塊處理,包括你的JavaScript代碼屡江,也包括CSS和fonts以及圖片等等等芭概,只有通過(guò)合適的loaders,它們都可以被當(dāng)做模塊被處理惩嘉。
css加載
webpack提供兩個(gè)工具處理樣式表罢洲,css-loader 和 style-loader,二者處理的任務(wù)不同文黎。
css-loader:將css文件打包到j(luò)s文件中惹苗,這樣才可以使用require或者import導(dǎo)入。
style-loader:將js文件中的css渲染到頁(yè)面中耸峭,在head標(biāo)簽里面桩蓉。
先安裝這兩個(gè)loader
//安裝
npm install --save-dev style-loader css-loader
配置
//使用
{
test: /\.css$/,
use: ['style-loader','css-loader'],
}
注:loader的加載順序都是從右向左的,即先加載css-loader,再加載style-loader,不能顛倒劳闹,先加載進(jìn)入js再渲染頁(yè)面院究。顛倒會(huì)報(bào)錯(cuò)
結(jié)果如下
sass使用
先安裝sass-loader和node-sass
npm install --save-dev sass-loader node-sass
因?yàn)閟ass-loader依賴于node-sass洽瞬,所以需要安裝node-sass,不安裝會(huì)報(bào)錯(cuò)业汰。
配置
module: {
rules: [{
test: /\.(png|jpg)$/,
use: 'url-loader?limit=8192&name=images/[hash:8].[name].[ext]'
}, {
test: /\.json$/,
use: ['json-loader']
}, {
test: /\.js$/,
use: ['babel-loader'],
exclude: /node_modules/, // 解析時(shí)排除的文件夾(node_modules里面也有很多js伙窃,但需要排除)
}, {
test: /\.scss$/,
use: ['style-loader','css-loader','sass-loader'],
}
]
},
main.js引入scss文件
import './index.scss'
編譯,sass-loader會(huì)自動(dòng)把scss文件編譯成css样漆,最后style-loader將其插入style里面
打包c(diǎn)ss
使用上面的loader,最后css會(huì)打包在js里面從而渲染在頁(yè)面中为障,但要是不想打包在js中,想把css分離出來(lái)放祟。就需要插件了产场。
安裝extract-text-webpack-plugin插件
npm install --save-dev extract-text-webpack-plugin
在webpack.config.js中先引入后插件然再配置
頁(yè)面頂端定義:
const ExtractTextPlugin = require('extract-text-webpack-plugin');
在loader里面定義
module: {
rules: [{
test: /\.(png|jpg)$/,
use: 'url-loader?limit=8192&name=images/[hash:8].[name].[ext]'
}, {
test: /\.json$/,
use: ['json-loader']
}, {
test: /\.js$/,
use: ['babel-loader'],
exclude: /node_modules/, // 解析時(shí)排除的文件夾(node_modules里面也有很多js,但需要排除)
}, {
test: /\.scss$/,
// use: ['style-loader','css-loader','sass-loader'], //打包進(jìn)js
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: ["css-loader",'sass-loader']
})
}
]
},
配置插件
plugins: [
new ExtractTextPlugin("css/index.css"),
]
注:css/index.css 表示css的路徑舞竿,名字可以隨便取京景,這里取名為index.css。啟動(dòng)服務(wù)器的時(shí)候并不會(huì)在本地生成css文件夾和index.css骗奖,而是在服務(wù)器新生成的html中自動(dòng)插入link標(biāo)簽引入此路徑下的css
本地的頁(yè)面結(jié)構(gòu)如下
開啟服務(wù)器后的預(yù)覽頁(yè)面
現(xiàn)在開始測(cè)試打包
當(dāng)輸入打包命令后确徙,如果在項(xiàng)目中有public文件夾,會(huì)在生成的html添加link連接樣式表执桌,并且生成上面自己的路徑(css/index)鄙皇。如果沒(méi)有public文件夾(文件出口)台谊,會(huì)自動(dòng)生成一個(gè)public文件夾
打包html
默認(rèn)情況下杆故,我們?cè)趐ublic文件夾中新建一個(gè)index.html文件,這樣打包后引入js摩渺。但要是不想在public建頁(yè)面膘壶,在其他文件夾(比如src文件夾)新建頁(yè)面错蝴,打包時(shí)再生成打包后的html。所以
安裝插件
npm install --save-dev html-webpack-plugin
配置
plugins: [
//這里開始寫
new HtmlWebpackPlugin({
template: 'src/index.html', //文件路徑
inject: 'body' //打包之后的js插入文檔的位置 (body表示script標(biāo)簽的位置在body里面的最下面即</body>上面)
}),
]
在src文件夾新建index.html
啟動(dòng)服務(wù)器
同css一樣颓芭,本地頁(yè)面無(wú)js添加顷锰,預(yù)覽頁(yè)面會(huì)自動(dòng)添加js
打包
同css一樣,無(wú)public亡问,生成public文件夾新增index.html,內(nèi)容自動(dòng)添加script標(biāo)簽官紫,有public文件夾,直接新增index.html,內(nèi)容自動(dòng)添加script標(biāo)簽
引入并打包img
安裝url-loader或者file-loader
url-loader和file-loader 都是用于打包文件和圖片州藕,但是這2個(gè)加載器區(qū)別如下
一般限制小圖片轉(zhuǎn) base64 可以用 url-loader束世,其他情況都用 file-loader。
url-loader應(yīng)該是file-loader上加了一層過(guò)濾床玻。本例中使用url-loader,但兩者存在依賴關(guān)系毁涉,需全部安裝才可使用。
安裝
install url-loader file-loader --save-dev
配置
module: {
rules: [
{
test: /\.(png|jpg)$/,
use: 'url-loader?limit=8192&name=images/[hash:8].[name].[ext]'
}
]
}
test 屬性代表可以匹配的圖片類型笨枯,除了 png薪丁、jpg 之外也可以添加 gif 等,以豎線隔開即開馅精。
limit 字段代表圖片打包限制严嗜,指當(dāng)圖片大小小于限制時(shí)會(huì)自動(dòng)轉(zhuǎn)成 base64 碼引用。
name 字段指定了打包后洲敢,在打包根目錄(output.path)下生成名為 images 的文件夾漫玄,并在原圖片名前加上8位 hash 值。
在greeter.js中引用
var imgurl = require('./assets/cat01.png');
然后就可以將字符串進(jìn)行拼接使用了
所有配置
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
entry: __dirname + "/src/main.js", //唯一入口文件
output: {
path: __dirname + "/public", //打包后的文件存放的地方供src引入加載
filename: "bundle.js" //打包后輸出文件的文件名
},
devtool: 'eval-source-map', //配置生成Source Maps压彭,選擇合適的選項(xiàng)
devServer: {
contentBase: "./src", //本地服務(wù)器所加載的頁(yè)面所在的目錄
open: true,
compress: true
// colors: true, //終端中輸出結(jié)果為彩色
// historyApiFallback: true, //不跳轉(zhuǎn)
// inline: true, //實(shí)時(shí)刷新
// port: 9000
},
module: {
rules: [{
test: /\.(png|jpg)$/,
use: 'url-loader?limit=8192&name=images/[hash:8].[name].[ext]'
}, {
test: /\.json$/,
use: ['json-loader']
}, {
test: /\.js$/,
use: ['babel-loader'],
exclude: /node_modules/, // 解析時(shí)排除的文件夾(node_modules里面也有很多js睦优,但需要排除)
}, {
test: /\.scss$/,
// use: ['style-loader','css-loader','sass-loader'],
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: ["css-loader",'sass-loader']
})
}
]
},
plugins: [
//這里開始寫
new HtmlWebpackPlugin({
template: 'src/index.html', //文件路徑
inject: 'body' //打包之后的js插入文檔的位置
}),
new ExtractTextPlugin("css/index.css"),
]
}