1.什么是webpack?
從本質(zhì)上來講梨撞,webpack是一個現(xiàn)代的Javascript應用的靜態(tài)模塊化打包工具。
這里的關(guān)鍵點就是模塊和打包
1.1前端模塊化
(1)在這之前大家已經(jīng)知道了在前端開發(fā)中為什么要進行模塊化開發(fā),目前使用的前端模塊化方案有:AMD学歧、CMD勾效、CommonJs、ES6嵌器。
(2)在ES6之前我們要想進行模塊化開發(fā)肛真,必須借助于其他的工具,讓我們可以進行模塊化開發(fā)爽航。并且在模塊化開發(fā)完成后蚓让,我們還需要處理各種模塊之間的依賴關(guān)系,并且將他們進行整合打包讥珍。
(3)而webpack其中一個核心就是讓我們可以進行模塊化開發(fā)历极,并且會幫助我們處理模塊之間的依賴關(guān)系。
(4)在這里不僅僅是Javascript文件衷佃,我們的css趟卸、圖片、json文件等再webpack中都可以被當做模塊來使用氏义,這就是webpack模塊化的概念锄列。
1.2打包
(1)打包這個概念比較好理解了,就是利用webpack將各種資源進行打包合并為一個或者多個包(bundle)惯悠。在打包過程中邻邮,還可以對資源進行處理,比如壓圖片克婶,將scss轉(zhuǎn)成css筒严,將ES6語法轉(zhuǎn)成ES5語法丹泉,將TypeScript轉(zhuǎn)成Javascript等等操作。
(2)在這里我們會想到鸭蛙,gulp也可以進行資源的打包嘀掸,那么它和webpack有什么區(qū)別呢?
*webpack和grunt/gulp對比
(1)grunt/gulp的核心是Task
我們可以配置一系列的task规惰,并且定義task需要處理的事務(例如ES6轉(zhuǎn)ES5睬塌,ts轉(zhuǎn)化,圖片壓縮歇万,scss轉(zhuǎn)成css)揩晴,之后讓grunt/gulp來執(zhí)行這些task,而且讓整個流程自動化贪磺,所以grunt/gulp也被稱為前端自動化任務管理工具
(2)什么時候用grunt/gulp呢硫兰?
如果你的項目模塊依賴非常簡單,或者是沒有用到模塊化的概念寒锚,只需要進行簡單的合并和壓縮劫映,就使用grunt/gulp即可。但是如果整個項目使用了模塊化管理刹前,而且相互之間依賴非常強泳赋,我們就可以使用更加強大的webpack了。
(3)所以webpack和grunt/gulp有什么不同呢喇喉?
* grunt/gulp更強調(diào)的是前端流程的自動化祖今,模塊化不是它的核心。
* webpack更加強調(diào)模塊化開發(fā)管理拣技,而文件壓縮合并千诬,預處理等功能,是他附帶的功能膏斤。
2.webpack的安裝
* webpack為了可以正常運行必須依賴node環(huán)境徐绑。node自帶了包管理工具(npm)。
執(zhí)行指令:npm install webpack@3.6.0 -g 進行全局安裝莫辨。這里指定了下載3.6.0的版本傲茄。
(1)為什么全局安裝后還需要局部安裝呢?
在終端直接執(zhí)行webpack命令衔掸,使用的是全局安裝的webpack烫幕,但是當我們在package.json中定義了script時俺抽,其中包含了webpack命令敞映,那么使用的是局部的webpack。
3.webpack的基本使用
(1)在webpack打包中一般目錄結(jié)構(gòu):
src(源碼):用于存放我們的源文件
? ? ? ? main.js: 項目的入口文件(這里有時候也可以命名為index.js)磷斧。
? ? ? ? aaa.js定義了一些函數(shù)振愿,可以在其他地方引用捷犹,并且使用。
dist(distribution發(fā)布):用于存放之后打包的文件冕末。
index.html:瀏覽器打開展示的首頁html萍歉。
package.json:通過npm init 生成的,npm包管理的文件档桃。
(2)在src文件下我們寫的東西都可通過模塊化的方式去實現(xiàn)(AMD/CMD/CommonJs/ES6都可以)枪孩。
用CommonJs模塊化進行模塊化開發(fā)
CommonJs方式導出:module.exports = {}??
在入口文件main.js導入:const {add , mul} = require('./aaa.js');
用ES6的模塊化進行模塊開發(fā)
ES6方式導出:export const name = '庫里';
? ? ? ? ? ? ? ? ? ? ? ? ? ?export const age = 18;
在入口文件main.js中導入: import {name, age} from './info.js'
這個時候只需要用webpack打包一下,它會自動的幫我們處理模塊之間相互之間的依賴藻肄,處理完成后它會生成一個最終的js文件(bundle.js)蔑舞,我們在引用的時候只需要用最終生成的那個js文件就可以了。
4.webpack.config.js和package.json的配置
(1)配置webpack.config.js文件:
const path = require('path');? // 這里需要用到node里面的path模塊嘹屯,這里用到的是node里面的相關(guān)的包(執(zhí)行npm init攻询,生成一個package.json文件,這個文件是告訴我們項目中的一些相關(guān)信息的)州弟。
* 當package.json中依賴相關(guān)東西的話钧栖,我們需要執(zhí)行npm install,會根據(jù)里面所有的依賴幫助我們安裝一些所需要的東西婆翔。
module.exports= {
? ? entry: ' ./src/main.js ',? // 入口文件
? ? output: {? // 出口文件
? ? ? ? path: path.resolve(_dirname, 'dist'),? // 這里要動態(tài)獲取一個絕對路徑拯杠,這里引用到了一個path模塊中的resolve函數(shù),用來對我們兩個路徑拼接(_dirname這里對這個上下文變量進行拼接)啃奴。
? ? ? ? filename: ' bundle.js '
????}
}
當我們在webpack.config.js中進行了以上配置后阴挣,我們就可以在終端直接執(zhí)行webpack命令實現(xiàn)對項目的打包。
(2)如何用npm run build 命令替代webpack命令執(zhí)行打包效果纺腊?
這里還需要把二者進行一個映射:
打開package.json畔咧,對文件中scripts進行配置
"scripts": {
? ? "build": webpack
}
* 開發(fā)時依賴(這就是在本地安裝webpack要加--save-dev的原因,因為webpack只有在開發(fā)時需要揖膜,打包上傳到服務器后就沒用了)
*運行時依賴
前面有說到除了全局安裝一個webpack之外誓沸,我們還要在本地安裝一個webpack。執(zhí)行npm install webpack@3.6.0 --save-dev壹粟。
* 在終端中敲命令時拜隧,用到的webpack都是全局的,但是當我們在package.json中定義scripts腳本時趁仙,然后執(zhí)行npm run build洪添,此時用到的就是本地的webpack。
5.什么是loader雀费?
laoder在webpack中是一個非常核心的概念干奢。在開發(fā)中我們不僅僅有基本的js代碼處理,也需要加載css盏袄、圖片ES6的轉(zhuǎn)化忿峻,以及將.vue文件轉(zhuǎn)成js文件等等薄啥,對于webpack本身的能力來說,對于這些轉(zhuǎn)化是不支持的逛尚,這時候就需要用到loader解決垄惧。
loader使用過程:
(1)通過npm安裝需要使用的loader
(2)在webpack.config.js中的modules關(guān)鍵字下面進行配置
5.1webpack中css文件的配置
安裝style-loader: npm install style-loader --save-dev
* 注意:style-loader要放在css-loader前面,為什么呢绰寞?因為webpack在讀取使用loader的過程中到逊,是按照從右向左順序讀取的。負責將樣式添加到DOM中
安裝css-loader: npm install css-loader --save-dev? ?
* 這里如果只引入css-loader會發(fā)現(xiàn)樣式?jīng)]有生效滤钱,這是因為css-loader只負責加載css文件蕾管,但是并不負責將css具體樣式嵌入到文檔中,這個時候我們還需要引入一個style-laoder菩暗。
在webpack.config.js中進行配置(具體參考wabpack的官方文檔:https://www.webpackjs.com/)
module: {
? ? rules: [
? ? ? ? {
? ? ? ? ? ? test: /\.css$/,
? ? ? ? ? ? use: [ ' style-loader ' , ' css-loader ' ]
? ? ? ? }
? ? ]
}
5.2less文件處理
安裝less-loader: npm install less-loader less --save-dev
* 通過less加載對應的less文件掰曾,下載同時還會下載一個less的包,可以對less文件的相關(guān)代碼進行一個解析停团。
webpack.config.js中配置如下:
module: {
? ? rules: [
? ? ? ? {
? ? ? ? ? ? test: /\.css$/,
? ? ? ? ? ? use: [ ' style-loader ' , ' css-loader ' , 'less-loader']? ?// 這里也可以用對象的形式比如:loader:'style-loader'
? ? ? ? }
? ? ]
}
5.3webpack圖片文件的處理
安裝url-loader: npm install --save-dev url-loader
* 當我們需要加載比limit大的圖片時旷坦,我們需要下載file-loader。
安裝file-loader: npm install --save-dev file-loader
webpack.config.js中配置如下:
module: {
? ? rules: [
? ? ? ? {
? ? ? ? ? ? test: /\.(png|jpg|jpeg|gif)$/,
? ? ? ? ? ? use: [
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? loader: 'url-loader',
? ? ? ? ? ? ? ? ? ? options: {
? ? ? ? ? ? ? ? ? ? ? ? limit: 8192
? ? ? ? ? ? ? ? ? ? ? ? * 當加載的圖片小于limit時佑稠,會將圖片編譯成base64字符串形式秒梅。
? ? ? ? ? ? ? ? ? ? ? ? * 當加載的圖片大于limit時,需要使用file-loader模塊進行加載舌胶。
????????????????????}
????????????????}
????????????]
? ? ? ? }
? ? ]
}
* 我們發(fā)現(xiàn)捆蜀,在圖片打包的時候webpack自動幫助我們生成了一個非常長的名字,這是一個32位的hash值幔嫂,目的就是防止名字重復辆它,但是實際開發(fā)中我們對名字也有一定的要求,比如講所有的圖片放在一個文件夾中履恩,跟上原來圖片的名稱锰茉,同時還要防止重復。
所以我們可以在options中添加上如下選項:
img: 文件要打包到的文件夾
name: 獲取圖片原來的名字切心,放在該位置飒筑。
hash:8? 為了防止圖片名稱沖突,依然使用hash绽昏,但是只保留8位數(shù)协屡。
ext: 使用圖片原來的擴展名
例子: name: 'img/[name].[hash:8].[ext]';
5.4 ES6轉(zhuǎn)ES5的babel
安裝babel-loader: npm install --save-dev babel-loader@7 babel-core babel-preset-es2015
*在webpack中,ES6轉(zhuǎn)ES5需要使用對應的loader全谤,這時候就需要下載babel-loader
webpack.config.js中配置如下:
module:?{
? ? rules: [
? ? ? ? {
? ? ? ? ? ? test: /\.js$/,
????????????exclude: /(node_modules|bower_components)/, // 排除
? ? ? ? ? ? use: [
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? loader: 'babel-loader',
? ? ? ? ? ? ? ? ? ? options: {
????????????????????????presets: ['@babel/preset-env']
????????????????????}
????????????????}
????????????]
? ? ? ? }
? ? ]
}
5.5 webpack中vue配置過程
runtime-only // 這種版本代碼中不可以有任何的templete
runtime-compiler // 這種版本代碼中可以有template肤晓,因為有compiler可以用于編譯template
過程:
(1)安裝vue: npm install --save vue
(2)引入 import Vue from 'vue'
(3)由于vue版本不太對(runtime-only/runtime-complier),通過alias(別名)解決版本錯誤。
vue對應loader安裝: npm install vue-loader vue-template-compiler --save-dev
webpack.config.js中配置如下:
module: {
? ? rules: [
? ? ? ? {
? ? ? ? ? ? test: /\.vue$/,
? ? ? ? ? ? use: [
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? loader: 'vue-loader',
4? ? ? ? ? ? ? }
????????????]
? ? ? ? }
? ? ]
}
* package.json中的內(nèi)容修改后都要執(zhí)行一下npm install重新做一下安裝
5.6 el和template的區(qū)別
* 當你定義了一個template屬性材原,此時又有el屬性掛載沸久,這時候template定義的東西會替換掉el屬性所掛載的所有代碼
6. webpack-認識plugin(插件)
* plugin是插件的意思季眷,通常用于對現(xiàn)有的框架進行擴展余蟹。
*webpack中的插件,就是對webpack現(xiàn)有的功能進行各種擴展子刮,比如打包優(yōu)化威酒,文件壓縮等等。
*loader和plugin的區(qū)別: loader用于轉(zhuǎn)換某些類型的模塊它是一個轉(zhuǎn)換器挺峡。plugin是插件葵孤,它是對webpack本身的擴展,是一個擴展器橱赠。
*plugin使用過程:
通過npm安裝需要使用的plugin尤仍,在webpack.config.js中配置插件。
(1)BannerPlugin的使用,添加版權(quán)信息
plugins: [
? ? new wabpack.BannerPlugin('最終版權(quán)歸我所有')
]
(2)HtmlWebpackPlugin的使用
* 把根目錄下的index.html打包到dist文件中
* 這個插件可以自動生成一個index.html文件(可以指定模板來生成)狭姨,將打包的js文件宰啦,自動通過script標簽插入到body中
安裝:npm install html-webpack-plugin --save-dev
配置webpack.config.js:
const HtmlWebpackPlugin = require('html-webpack-plugin');? // 導入
plugins: [
? ? new wabpack.BannerPlugin('最終版權(quán)歸我所有'),
? ? new HtmlWebpackPlugin({
? ? ????template: 'index.html',? // 這里是可以指定模板的饼拍,指定某一個模板作為dist文件中生成的html文件的模板赡模。
????})
]
(3)UglifyjsWebpackPlugin的使用
* 對打包的js文件進行丑化壓縮的插件
* 我們使用一個第三方的插件uglifyjs-webpack-plugin,并且版本號指定1.1.1,和cli2保持一致
安裝: npm install uglifyjs-webpack-plugin@1.1.1 --save-dev
配置webpack.config.js:
const UglifyjsWebpackPlugin = require('html-webpack-plugin');? // 導入
plugins: [
? ? new wabpack.BannerPlugin('最終版權(quán)歸我所有')师抄,
? ? new HtmlWebpackPlugin(),
? ? new UglifyjsWebpackPlugin(),
]
7.搭建本地服務器
* webpack提供了一個可選的本地開發(fā)服務器漓柑,這個本地服務器基于nodejs搭建,內(nèi)部使用express框架叨吮,可以實現(xiàn)我們想要的讓瀏覽器自動刷新顯示我們修改后的結(jié)果辆布。
它是一個單獨的模塊,在webpack中使用它需要先安裝:
npm install --save-dev weback-dev-server@2.9.1
devserver也是作為webpack中的一個選項茶鉴,選項本身可以設置以下屬性:
contentBase: 為哪一個文件夾提供本地服務谚殊,默認是根文件夾,我們這里要填寫./dist
port: 端口號
inline: 頁面實時刷新
historyApiFallback: 在SPA頁面中蛤铜,依賴HTML5的history模式
配置webpack.config.js:
devServer: {
? ? contentBase: './dist',
? ? inline: true
}
開發(fā)時執(zhí)行腳本可以在package.json中加入'dev': 'weback-dev-server? --open',這時候執(zhí)行npm run dev就可以啟動本地服務器,加入--open可以實現(xiàn)執(zhí)行命令自動打開瀏覽器嫩絮。
* 開發(fā)階段不要加入UglifyjsWebpackPlugin插件,在發(fā)布階段再加入,因為丑化了js文件后围肥,調(diào)試階段不好閱讀
8.webpack配置文件的分離
* 有的配置是需要打包時候使用剿干,比如說丑化js等等,有的配置是需要本地開發(fā)時候使用穆刻,比如說配置本地服務器置尔。這里就需要把webpack配置進行一個分離,根據(jù)開發(fā)時候的配置和發(fā)布時候的配置氢伟。
這時候需要把以前的webpack.config.js分成三個不同的js榜轿,這三個不同的js放在根目錄下的build文件夾中分別是:
base.config.js :? 里面存放的是一些公共的配置
prod.config.js :生產(chǎn)環(huán)境的一些配置
dev.config.js : 開發(fā)環(huán)境的一些配置
這么分的思路就是我們把開發(fā)和生產(chǎn)環(huán)境的配置實現(xiàn)一個分離幽歼,這時候需要安裝一個webpack-merge的模塊,它的作用是把base和prod谬盐,base和dev甸私,分別合并,這樣就實現(xiàn)了開發(fā)和生產(chǎn)環(huán)境配置的分離飞傀。
安裝: npm install webpack-merge --save-dev
prod和base合并:
在prod.config.js中:
const baseConfig = require('./base.config.js');
module.exports = { baseConfig皇型,{
? ? plugins: [
? ??????new UglifyjsWebpackPlugin(),
????]
})
在dev.config.js中:
const baseConfig = require('./base.config.js');
module.exports = { baseConfig,{
????devServer: {
? ? ????contentBase: './dist',
? ????? inline: true
????}
})
但是這時候你要是執(zhí)行npm run build是會報錯的砸烦,因為我們現(xiàn)在已經(jīng)把webpack.config.js刪了弃鸦,這時候我們就需要在package.json中指定一下用哪個配置文件:
"scripts": {
? ? "build": ‘webpack --config ./build/prod.config.js',
? ? "dev": 'webpack-dev-server --open --config ./build/dev.config.js'
}
這時候就可以正常打包了,但是此時打包完成的dist文件是加到了build文件夾中幢痘,這個是因為我們在base.config.js中出口output拼接的目錄路徑錯誤唬格,修改一下目錄就可以了。