文章目錄
-
- 安裝
-
- 為什麼需要安裝局部webpack
- 使用
-
- 準備工作
- 基本使用
- 配置
-
- 入口和出口
- webpack映射
- loader
-
- 打包css檔案
- 打包scss檔案
- 打包圖檔資源
-
- file-loader
- 修改檔案名稱
- ES6 轉 ES5
- webpack 中的 Vue 使用
-
- 編寫Vue代碼
-
- 抽取template
- vue-loader
- 元件化開發Vue
-
- 導入元件省略擴充名
- webpack中的插件
-
- loader和plugin差別
- plugin的使用過程:
-
- 添加版權插件
- HTML打包插件
- js壓縮插件
- 搭建本地伺服器
- 配置檔案的抽離
安裝
- 安裝webpack前要先安裝Node.js
- 全局安裝webpack:
(這裡先指定3.6.0版本,因為vue cli2依賴該版本,可以進行手動配置,便于學習)npm install [email protected] -g
- 局部安裝webpack:進入到項目根目錄,輸入
npm install [email protected] --save-dev
為什麼需要安裝局部webpack
因為一個項目往往依賴特定的webpack版本,全局的版本可能很這個項目的webpack版本不一緻,導出打包出現問題
是以通常一個項目,都有自己局部的webpack
執行局部webpack打包:
node_modules/.bin/webpack
使用
準備工作
- 建立src檔案,建立兩個互相依賴的js檔案
- 建立dist檔案,儲存打包後的檔案
- 建立index.html檔案(根目錄下)
基本使用
在終端進入到項目根目錄,輸入指令:
webpack ./src/main.js ./dist/bundle.js
該指令的意思是将main.js在該項目内所依賴的所有js檔案打包到dist目錄下的bundle檔案
如果報錯禁止運作腳本,則需要配置powershell
配置
入口和出口
我們每次使用webpack的指令都需要寫上入口和出口作為參數,非常麻煩,是以我們要建立一個webpack配置檔案:webpack.config.js,在該檔案配制好入口和出口後,下一次隻需輸入
webpack
即可打包
絕對路徑需要依賴node的path包,一般隻要依賴于node環境的項目,都需要建立package.json檔案,該檔案是告訴關于項目一些資訊以及管理node包,使用
npm init
指令建立
如果項目有依賴一些node的包,使用
npm install
會根據package.json自動安裝所需要的包
// 用于擷取絕對路徑,需要依賴node的path包,node全局中是包含該包的,是以不需單獨建包
const path = require('path')
module.exports = {
// 入口:可以是字元串/數組/對象,這裡我們入口隻有一個,是以寫一個字元串即可
entry: './src/main.js',
// 出口:通常是一個對象,裡面至少包含兩個重要屬性:path和filename
output: {
//__dirname:擷取目前檔案所在絕對路徑
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
}
}
webpack映射
我們在真正的開發中一般使用
npm run build
來建構我們的項目,因為使用
webpack
指令時後面可能會跟很長的内容,我們想讓這個長指令可以由其他指令代替
webpack映射還有一個好處,我們在任何終端執行webpack的時候都會執行全局webpack,但是我們使用映射的指令會優先執行局部webpack(本地),因為package.json中的scripts的腳本在執行時,會先尋找本地的node_modules/.bin路徑中對應的指令,如果沒找到,再去全局中尋找
打開package.json檔案,在scripts對象内添加"build"屬性
"scripts": {
// 此時執行npm run build指令将轉換為webpack指令
"build": "webpack"
},
loader
前面示範了如何打包js檔案,但是如果我們想要打包css、vue、ts等檔案時,需要先給webpack擴充對應的loader,這裡以css為例示範
進入https://www.webpackjs.com/loaders/,找到對應的css的loader,按照文檔操作
- 安裝
- css-loader:
npm install --save-dev css-loader
- style-loader:
npm install style-loader --save-dev
- 進入webpack.config.js配置檔案,在
對象中添加module.exports
對象module
module: {
rules: [
{
test: /\.css$/,
// css-loader:隻負責加載,但不負責解析,也不負責與html檔案連接配接
// style-loader:将子產品的導出作為樣式添加到 DOM 中
// webpack在使用多個loader時,是從右向左讀取,我們要先加載css,在添加樣式,是以要将css-loader放到右邊
use: [ 'style-loader', 'css-loader' ]
}
]
}
打包css檔案
安裝并配置完css的loader,我們就可以開始打包了
我們使用webpack打封包件時,隻會打包入口js檔案所依賴的檔案,不被它依賴的檔案不會被打包;是以我們将css等檔案添加為入口js的依賴就能帶着css檔案一起打包了
// 依賴css檔案
require('./css/normal.css')
打包scss檔案
如果我們希望在項目中使用scss、less、stylu來寫樣式,webpack是否可以幫助我們處理呢?我們這裡以scss為例,其他也是一樣的
注意:我們使用Live Sass Compiler插件會實時将scss檔案轉換為css檔案,這些css檔案可以作為我們開發時調整樣式使用,在webpack打包時隻打包scss檔案即可
步驟:
- 建立一個scss檔案,然後放在css檔案夾中
- 在入口js檔案依賴該scss檔案:
require('./css/special.scss')
- 執行指令:
npm install sass-loader node-sass webpack --save-dev
- 進入webpack.config.js檔案,我們在配置css的loader的時候已經添加了module對象,是以直接在module對象的rules數組裡添加一個新的對象元素
- 執行
,如果報錯getResolve is not a function,則是因為scss安裝的版本過高,需解除安裝重裝其他版本npm run build
// 在webpack.config.js中配置loader
{
test: /\.scss$/,
use: [{
loader: "style-loader" // 将 JS 字元串生成為 style 節點
}, {
loader: "css-loader" // 将 CSS 轉化成 CommonJS 子產品
}, {
loader: "sass-loader" // 将 Sass 編譯成 CSS
}]
}
打包圖檔資源
我們在images檔案夾加入兩張圖檔:一張小于8kb的圖檔和一張大于8kb的圖檔,待會兒我們會針對這兩張不同大小的圖檔進行不同的處理
我們已經将normal.css檔案作為main.js的依賴了,是以我們在該css檔案中設定背景圖檔也會作為main.js的依賴;但我們需要為圖檔單獨添加loader
步驟:
- 在項目根目錄執行指令:
npm install --save-dev url-loader
- 進入webpack.config.js檔案,在已經建立好的module對象裡的rules數組添加一個新的對象元素
{
// 設定比對的圖檔格式
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
// 限制圖檔大小,圖檔超出limit會用file-loader來打包,需安裝file-loader
// 圖檔小于limit時,會将圖檔url位址編譯成base64格式字元串
limit: 8192
}
}
]
}
file-loader
當我們使用的圖檔超出了url-loader配置的大小範圍,則不會再以url-loader來進行加載,而是以file-loader來加載
如果沒有安裝file-loader則會報錯
- 安裝file-loader:
,無需對file-loader專門進行配置npm install --save-dev file-loader
當我們使用file-loader加載圖檔後,發現在dist檔案夾下生成了一個以hash值命名的圖檔,也就是我們的源圖檔;但在網頁中該圖檔并沒有顯示,因為webpack打包後的檔案url路徑預設是根目錄,而不是dist目錄,是以需要修改預設url路徑
- 進入webpack.config.js檔案,在output對象中添加
屬性,以後任何涉及到url的路徑,都會在前面拼接一個publicPath
dist/
output: {
publicPath: 'dist/'
},
注意:此時我們的index.html在項目根目錄,是以通路資源的時候需要添加
dist/
路徑;到後期我們也會将index.html打包到dist目錄下,到時候需要将
publicPath
屬性删掉
修改檔案名稱
使用file-loader打封包件時會在dist檔案夾生成一個32位hash值命名的檔案,目的是防止檔案名重複
但是在真實開發中我們希望将所有的圖檔放在dist下的images檔案夾下,附帶圖檔原來的名稱,同時也要防止重複
是以我們需要在webpack.config.js檔案中進行配置:
{
// 1. 找到url-loader的配置項
test: /\.(png|jpg|gif)$/,
use: [{
loader: 'url-loader',
options: {
limit: 10000,
// 2. 在options中添加name屬性
name: 'images/[name].[hash:8].[ext]'
}
}]
}
images/[name].[hash:8].[ext]
:表示生成的檔案會在dist的images檔案夾下并以原來的名字+8位哈希值+原字尾命名,如:
歐陽娜娜.d96873f5.jpg
ES6 轉 ES5
webpack在打包我們的js檔案的時候并沒有完全的将ES6文法轉換為ES5,是以我們需要借助babel來幫我們轉換
步驟:
- 安裝babel:
npm install --save-dev [email protected] babel-core babel-preset-es2015
- 進入webpack.config.js檔案,在已經建立好的module對象裡的rules數組添加一個新的對象元素來配置babel-loader
{
test: /\.js$/,
// 排除掉node_modules檔案夾
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['es2015']
}
}
}
webpack 中的 Vue 使用
- 安裝Vue:
npm install vue --save
- 在main.js檔案中導入Vue:
import Vue form 'vue'
- 這裡直接寫
即可,如果不加相對路徑,會預設去node_modules檔案夾中導入,而我們的Vue就安裝在此檔案夾from vue
- 并且node_modules會執行
,是以我們直接export default Vue
即可import Vue
- 此時我們編寫一段Vue代碼,打包并運作,發現報錯using the runtime-only,我們Vue在構件時預設建構runtime-only版本,該版本不允許出現
,而我們的<template>
其實就是Vue執行個體的template,是以會報錯<div id="app">
- 修改vue建構版本:進入webpack.config.js檔案,在module.exports對象中添加一條屬性:
resolve: {
alias: {
// 下次import Vue from 'vue'的時候會來這裡看'vue'是否指向了具體的檔案,這裡指向了vue.esm.js
'vue$': 'vue/dist/vue.esm.js'
}
}
- 重新打包
編寫Vue代碼
假設我們執行個體化了一個Vue對象:
const app = new Vue({
el:'#app',
data:{
msg:'我是一條msg'
}
})
我們以前想要輸出msg的時候會這樣寫:
<div id="app">
{{msg}}
</div>
在真實開發中我們的
<div id="app"> </div>
裡面不會寫任何内容,我們會寫在Vue對象的
template
屬性中,用反單引号包裹:
new Vue({
el:'#app',
template:`
<div>
<button @click="click">我是template</button>
<h2>{{message}}</h2>
</div>
`,
data:{
message:'我是一條message'
},
methods:{
click() {
console.log('我被點選了')
}
}
})
這樣在編譯程式的時候,
template
會找到id為app的DOM元素,并将其覆寫替換為
template
中的代碼
抽取template
前面我們将
<template>
代碼和它所需要的
message
資料和
click()
方法都寫到了Vue對象中,顯得非常備援,是以我們要将它們抽取成一個單獨的元件
// 建立APP元件:
const APP = {
template:`
<div>
<button @click="click">我是template</button>
<h2>{{message}}</h2>
</div>
`,
data() {
return {
message:'我是一條message'
}
},
methods: {
click() {
console.log('我被點選了')
}
}
}
// 現在的Vue對象:
new Vue({
el:'#app',
template:``,
data:{
},
methods:{
}
})
我們想要使用該元件,則需要在Vue對象中注冊它,然後直接在
template
屬性中使用它即可,因為
template
中的内容會覆寫替換掉id為app的DOM元素
new Vue({
el:'#app',
// 将APP元件中的内容覆寫替換id為app的DOM元素,注意元件的單标簽形式 斜杠在右邊
template:'<APP/>',
// 注冊APP元件
components:{
APP
}
})
雖然我們将該元件抽取了出來,但是main.js作為程式入口,不應該儲存這些元件代碼,而且當元件過多時代碼顯得更加混亂,是以我們要為該元件建立一個單獨的js檔案單獨儲存
在src目錄下建立一個vue檔案夾,再建立一個APP.js檔案,在該js檔案裡面專門書寫該APP元件,并導出該元件供其他檔案引用:
export default {
template: `
<div>
<button>我是template</button>
<h2>{{message}}</h2>
</div>
`,
data() {
return {
message: '給我一個吻'
}
}
}
導出了該元件,我們就可以在main.js檔案中導入使用了:
import APP from './vue/APP'
// 直接在Vue對象中使用APP元件
new Vue({
el: '#app',
// APP元件的内容會替換到id為app的DOM元素上
template: '<APP/>',
components: {
APP
}
})
雖然我們用APP.js單獨儲存該APP元件,但是該元件的模闆和js代碼沒有進行分離,是以用js檔案儲存元件是不合适的,要使用 .vue檔案
我們要在vue檔案夾下建立APP.vue檔案,vue格式檔案包含了三部分:
-
:書寫元件标簽<template>
-
:書寫js代碼<script>
-
:書寫樣式<style>
我們将以前的APP.js檔案中的代碼按照分類放入vue格式的檔案中:
<template>
<div>
<button>我是template</button>
<h2>{{message}}</h2>
</div>
</template>
<script>
export default {
data() {
return {
message: "給我一個吻"
};
},
};
</script>
<style>
</style>
是不是感覺條理清晰了很多,而且我們可以為
<template>
内的标簽添加樣式,寫在下面的
<style>
标簽中即可
删除以前導入的js檔案,修改為:
import APP from './vue/APP.vue'
vue-loader
我們webpack加載css、scss都需要下載下傳對應的loader,加載vue也不例外:
- 安裝:
npm install vue-loader vue-template-compiler --save-dev
- 配置:進入webpack.config.js檔案,在module對象的rules數組裡添加一個新的對象元素:
{
test: /\.vue$/,
use: ['vue-loader']
}
此時我們執行webpack打包會報錯,因為我們的vue-loader版本過高,我們可以配置為較低的版本來解決此問題
進入package.json,将
vue-loader
的值改為
^13.0.0
,這個
^
的意思是會将版本修改為大于13.0的版本但小于14.0版本中的一個,然後執行
npm install
會自動安裝該版本
- 重新打包
元件化開發Vue
下面我們來感受一下什麼是真正的元件化開發
- 我們在vue檔案夾下再建立一個Cpn.vue,在
标簽内書寫一些内容,最後的代碼如下:<template>
<template>
<div>
<h2>我是Cpn裡的文字</h2>
<h2>我是Cpn裡的文字</h2>
<h2>我是Cpn裡的文字</h2>
</div>
</template>
<script>
export default {};
</script>
<style>
</style>
- 打開之前的APP.vue檔案,在
标簽中導入剛才建立的Cpn元件:<script>
import Cpn from './Cpn.vue'
- 注冊剛導入的Cpn元件
- 在APP的
中使用Cpn元件<template>
此時的APP.vue整體代碼如下:
<template>
<div>
<button>我是template</button>
<h2 class="title">{{message}}</h2>
<!-- 使用導入的Cpn元件 -->
<Cpn />
<Cpn />
</div>
</template>
<script>
// 導入Cpn元件
import Cpn from "./Cpn.vue";
export default {
data() {
return {
message: "給我一個吻",
};
},
// 注冊一下剛導入的Cpn元件
components: {
Cpn,
},
};
</script>
<style scoped>
.title {
color: green;
}
</style>
以後我們的開發模式都是這樣寫元件的,到時候我們的應用程式就是一個元件樹
以現在的代碼為例,main.js引入了APP元件,APP元件就是根元件,而根元件又引入了Cpn元件,Cpn元件以後又引入了其他元件,每個元件都是一個獨立的檔案
導入元件省略擴充名
進入webpack.config.js檔案,在resolve對象中添加:
// 導入js和vue字尾的檔案時不需在寫擴充名,這兩個必須同時添加
extensions: ['.vue', '.js']
webpack中的插件
webpack中的插件(plugin),就是對webpack現有功能的各種擴充,比如打包優化,檔案壓縮等等
loader和plugin差別
- loader主要用于轉換某些類型的子產品,它是一個轉換器
- plugin是插件,它是對webpack本身的擴充,是一個擴充器
plugin的使用過程:
- 通過npm安裝需要使用的plugins(某些webpack已經内置的插件不需要安裝)
- 在webpack.config.js中的plugins中配置插件
添加版權插件
我們先來使用一個最簡單的插件,為打包的檔案添加版權聲明
該插件名字叫BannerPlugin,屬于webpack自帶的插件
- 進入webpack.config.js,由于該插件內建到了webpack包中,是以我們要導入webpack包
- 在module.exports對象中添加plugins數組
- 配置BannerPlugin
const webpack = require('webpack')
module.exports = {
...
plugins: [
new webpack.BannerPlugin('最終版權歸我所有~')
]
}
HTML打包插件
目前,我們的index.html檔案是存放在項目的根目錄下的
在真實釋出項目時,釋出的是dist檔案夾中的内容,是以我們需要将index.html檔案打包到dist檔案夾中,這個時候就可以使用HtmlWebpackPlugin插件
該插件的作用:
- 自動生成一個index.html檔案(可以指定模闆來生成)
- 将打包的js檔案,自動通過script标簽插入到body中
使用步驟:
- 安裝插件:
,最高版本會報錯,建議安裝3.0版本npm install html-webpack-plugin --save-dev
- 引入插件:在webpack.config.js中輸入:
const HtmlWenpackPlugin = require('html-webpack-plugin')
- 在plugins數組中添加:
new HtmlWebpackPlugin()
現在重新打包就能在dist檔案夾生成我們的index.html檔案了,但是還存在兩個問題:
- 我們之前學習的時候給file-loader的src路徑添加了
,現在我們的html檔案已經被打包到該路徑了,是以不再需要dist/
- 我們希望自動生成index.html的時候添加一個
标簽<div id="app"> </div>
解決:
- 進入webpack.config.js,将
對象中的output
屬性删掉publicPath: 'dist/'
- 将根目錄下的index.html檔案作為打包html檔案時的模闆:進入webpack.config.js檔案,在plugins數組中的配置中添加:
new HtmlWebpackPlugin({
// 以目前配置檔案所在目錄下的index.html為模闆
template: 'index.html'
})
js壓縮插件
- 安裝:
npm install [email protected] --save-dev
- 修改webpack.config.js檔案:
// 引入插件
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
...
plugins:[
new UglifyJsPlugin()
]
}
搭建本地伺服器
之前我們每次調試一點代碼都要重新打包,很不友善
webpack提供了一個可選的本地開發伺服器,這個本地伺服器基于node.js搭建,内部使用express架構,可以實作我們想要的讓浏覽器自動重新整理顯示我們修改後的結果
- 安裝
npm install --save-dev [email protected]
- 在webpack.config.js檔案中配置devServer
devServer也是作為webpack中的一個選項,選項本身可以配置如下屬性:
-
:為哪一個檔案夾提供本地服務,預設是根檔案夾,我們這裡要填寫./distcontentBase
-
:端口号port
-
:頁面實時重新整理inline
-
:在SPA頁面中,依賴HTML5的history模式historyApiFallback
// 在webpack.config.js檔案中配置
module.exports = {
...
devServer: {
contentBase: './dist',
inline: true
}
}
如果直接在控制台輸入
webpack-dev-server
來運作的話會執行全局webpack,是以我們可以在package.json的scripts對象中添加腳本:
"dev": "webpack-dev-server --open"
,(添加–open,在開啟服務時會自動打開浏覽器)
這樣我們隻需要在終端輸入
npm run dev
,就可以在本地webpack運作我們的服務了,我們修改src目錄下的檔案代碼時,浏覽器就會自動重新整理
想要終止服務,在終端按下
ctrl+c
選擇退出
總結:我們通過
webpack-dev-server
搭建了一個本地服務,之後我們的測試都是在本地服務中進行測試,等全部測試完畢之後,就可以執行
npm run build
進行真正的打包,再把打包後的dist檔案夾放到伺服器進行部署
配置檔案的抽離
在webpack.config.js中,有一些配置是在開發環境中不需要的,如js壓縮插件;有一些配置是生産環境不需要的,如devserver
我們希望将配置檔案分為三份,分别為公共配置、開發配置、生産配置。在程式開發時,執行公共配置和開發配置;在程式上線後,執行公共配置和生産配置,是以還需要檔案合并工具
步驟:
- 安裝檔案合并工具:
,推薦安裝4.0版本,高版本會報錯,參考https://blog.csdn.net/sinat_37503265/article/details/107216055npm install webpack-merge --save-dev
- 在根目錄建立build檔案夾用來儲存配置檔案
- 建立base.config.js,dev.config.js,prod.config.js三個配置檔案
- 将我們以前的webpack.config.js中的配置項按照分類分别放到這三個檔案中
- 合并檔案,這裡以合并公共配置和生産配置為例,打開生産環境配置檔案:
// 導入js壓縮插件
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
// 導入webpack-merge插件
const webpackMerge = require('webpack-merge')
// 導入base.config.js
const baseConfig = require('./base.config')
// exports導出的時候,将base.config和prod.config一起導出
module.exports = webpackMerge(baseConfig, {
// 原來prod.config中的代碼
plugins: [
new UglifyJsPlugin()
],
})
- 修改預設配置檔案,修改package.json檔案中的
和build
腳本,添加dev
字段--config
{
...
"scripts": {
"build": "webpack --config ./build/prod.config.js",
"dev": "webpack-dev-server --open --config ./build/dev.config.js"
},
}
- 修改webpack打包目錄,進入base.config.js,修改path:
module.exports = {
output: {
path: path.resolve(__dirname, '../dist')
},
}