# 什么是webpack?*
問題:為什么在 vue 中使用 npm run build 命令就可以把開發(fā)環(huán)境中的文件進(jìn)行合并?
答案:無論是 vue 還是 react、angular,使用 cli 創(chuàng)建出來的項(xiàng)目,都自動的把結(jié)構(gòu)做好了,內(nèi)部的 webpack 也都配置好了,項(xiàng)目開發(fā)完畢后,只需要執(zhí)行 build 命令,就能夠把 src 下的文件進(jìn)行打包,這個(gè)打包功能都是由 webpack 完成的,這個(gè)配置無需我們自己操作,vue、react、angular 內(nèi)部已經(jīng)整合完畢,只需要直接使用命令即可。
**如果想手動的一步一步的配置 webpack,那么可以根據(jù)下面的文檔進(jìn)行操作。**
webpack是資源加載/打包工具
```
project1/
? ? src/
? ? dist/
```
說白了,就是把開發(fā)環(huán)境src目錄中的文件,打包到生產(chǎn)環(huán)境dist目錄下。
- 在安裝一個(gè)要打包到生產(chǎn)環(huán)境的安裝包時(shí),應(yīng)使用 npm i -S,完整寫法為 npm install --save lodash
- 如果安裝一個(gè)用于開發(fā)環(huán)境的安裝包,應(yīng)使用 npm i -D,完整寫法為 npm install --save-dev lodash
> 打包指把src下那些碎片化的文件,合并到一起,生成到dist下。
> 部署指把dist目錄當(dāng)成網(wǎng)站根目錄,供別人訪問。
# 如何使用webpack?
全局安裝
```bash
npm i -g webpack webpack-cli
```
查看版本號
```bash
webpack -v? ? ? # 4.29.6
webpack-cli -v? # 3.3.0
```
創(chuàng)建項(xiàng)目目錄
```bash
mkdir project1 && cd project1
```
初始化項(xiàng)目
```bash
npm init
```
>? npm init -y (-y參數(shù)的作用是創(chuàng)建package.json時(shí)都安裝默認(rèn)的來)
局部安裝
```bash
npm i -D webpack webpack-cli
```
創(chuàng)建目錄結(jié)構(gòu)、文件和內(nèi)容:
```
project1/
package.json
src/
index.js
```
src/index.js 中的代碼:
- 在安裝一個(gè)要打包到生產(chǎn)環(huán)境的安裝包時(shí),會打包到線上去并且在線上環(huán)境能用到的,應(yīng)使用 npm i -S,完整寫法為 npm install --save lodash
- 如果安裝一個(gè)用于開發(fā)環(huán)境的安裝包,只需要在開發(fā)的時(shí)候編譯就好,線上并不需用的到,應(yīng)使用 npm i -D,完整寫法為 npm install --save-dev lodash
```javascript?
// lodash 是一個(gè)js工具庫,用來操作 object、array、number... 更方便了
import _ from 'lodash'; // npm install --save lodash
function component(){
? ? var element = document.createElement('div')
? ? element.innerHTML = _.join(['Hello', 'webpack'], ' ')
? ? return element;
}
document.body.appendChild( component() )
```
創(chuàng)建目錄結(jié)構(gòu)、文件和內(nèi)容:
```
project1/
package.json
dist/
index.html
```
dist/index.html 中的代碼:
- main.js 文件目前還不存在
- 需要通過webpack把src/index.js文件及其依賴文件lodash打包到一起
```html
<!DOCTYPE html>
<html lang="en">
<head>
? ? <meta charset="UTF-8">
? ? <meta name="viewport" content="width=device-width, initial-scale=1.0">
? ? <meta http-equiv="X-UA-Compatible" content="ie=edge">
? ? <title>Document</title>
</head>
<body>
</body>
</html>? ? ? ?
<script src="main.js"></script>
```
在命令行中執(zhí)行:
```bash
npx webpack
```
執(zhí)行 npx webpack,會將我們的腳本作為入口起點(diǎn),然后輸出為 main.js
> Node 8.2+ 提供了 npx 命令,可以運(yùn)行在初始安裝的 webpack包(package)的webpack二進(jìn)制文件
然后就可以瀏覽dist/index.html網(wǎng)頁了
# 配置文件
在項(xiàng)目根目錄下建立webpack.config.js文件
```
project1/
webpack.config.js
```
編寫代碼,配置打包內(nèi)容。
```javascript
// 在 webpack 中使用 require 引入自帶的path模塊 (CommomJS規(guī)范)
const path = require('path')
module.exports = {
? ? entry: './src/index.js',
? ? output: {
? ? ? ? filename: 'index.js',
? ? ? ? path: path.resolve(__dirname, 'dist')
? ? }
}
```
> entry描述的是入口;output描述的是出口。
命令行執(zhí)行:
```bash
npx webpack --config webpack.config.js
```
說明:根據(jù)配置頁進(jìn)行打包,入口為src/index.js,根據(jù)入口頁的相關(guān)依賴,合并到dist/index.js中。
也可以直接執(zhí)行:
```bash
webpack
```
兩個(gè)命令是等效的
# NPM腳本
考慮到用 CLI 這種方法來運(yùn)行本地的 webpack 不是特別方便,我們可以設(shè)置快捷方式。
在 package.json 文件的 scripts 對象中,增加 build 腳本,當(dāng)執(zhí)行 build 腳本時(shí),實(shí)際執(zhí)行的是 webpack 命令。
```
"scripts":{
? ? "abc" : "npx webpack --config webpack.config.js",
? ? "build": "webpack"
}
```
使用 npm run build 命令,代替之前使用的 webpack 命令。
```bash
npm run build? # npm run abc
```
# 資源管理
加載當(dāng)前項(xiàng)目所用到的其他資源
- 加載 CSS
- 加載圖片
- 加載字體
# 加載 CSS
下載在js中解析css的模塊,我們要把js和css打包到一起。
```bash
npm install -D style-loader css-loader
```
webpack.config.js 配置規(guī)則
```javascript
module.exports = {
? ? entry: ......
? ? output: {} .....
? ? module: {
? ? ? ? rules:[
? ? ? ? ? ? { test:/\.css$/, use:['style-loader', 'css-loader'] }
? ? ? ? ]
? ? }
}
```
module.rules表示使用webpack打包模塊時(shí)所定義的打包規(guī)則。
webpack打包時(shí),如果碰到的是.css結(jié)尾的文件,使用style-loader和css-loader處理。
- style-loader:將 JS 字符串生成為 style 節(jié)點(diǎn)
- css-loader:將 CSS 轉(zhuǎn)換為 CommonJS 模塊
src/style.css
```css
.hello { color:red }
```
src/index.js
```javascript
import './style.css'
function component(){
? ? // ........
? ? element.classList.add('hello')
}
```
命令行中執(zhí)行:
```bash
npm run build
```
如果想使用 scss 文件,需要安裝
> npm config set sass-binary-site http://npm.taobao.org/mirrors/node-sass
```
npm install sass-loader node-sass --save-dev
```
然后規(guī)則中配置:
```
{ test:/\.scss$/, use:['style-loader', 'css-loader', 'sass-loader'] }
```
# 加載圖片
CSS 和 JS 中的圖片如何處理?
需要安裝:
```
npm install --save-dev file-loader
```
然后在 webpack.config.js 頁面中配置規(guī)則:
```
{ test:/\.(png|svg|jpg|gif)$/, use:['file-loader'] }
```
創(chuàng)建文件及編寫代碼
```
src/
? ? images/
? ? ? ? 1.jpg
? ? ? ? 2.jpg
index.js
import img from './images/1.jpg'
var myImg = new Image();
myImg.src = img;
document.body.appendChild( myImg );
style.scss
background: url(images/2.jpg)
```
命令行執(zhí)行:
```
npm run build
```
兩張圖片會被復(fù)制到 dist 目錄下面,網(wǎng)頁能正常使用,如果想配置圖片輸出后的路徑,可以:
```
use:[{
? ? loader:'file-loader',
? ? options:{
? ? ? ? name:'[name].[ext]',
? ? ? ? outputPath:'images'
? ? }
}]
```
# 加載字體
字體這種資源需要用到 file-loader 或 url-loader
```
npm i -D url-loader
```
規(guī)則配置:(二選一)
- file-loader會保存單獨(dú)的字體文件
```
{ test: /\.(woff|woff2|eot|ttf|otf)$/, use: ['file-loader'] }
```
- url-loader會和js合并到一起
```
{ test: /\.(woff|woff2|eot|ttf|otf)$/, use: ['url-loader'] }
```
style.css 或 style.scss
```
@font-face{
? ? font-family: abc;
? ? src: url(./fonts/經(jīng)典毛筆字體.ttf) format("truetype");
}
div{ font-family:"abc" }
```
命令行
```
npm run build
```
# 多入口多出口
PC端項(xiàng)目中可能有很多個(gè)入口,比如 index.html,比如 main.html 等,瀏覽器中都可以直接訪問。
> 移動端項(xiàng)目SPA都是單頁面應(yīng)用,用一個(gè)入口就可以了,如果是傳統(tǒng)的PC端,那么需要用到很多入口頁面。
dist/index.html
```html
<script src="index.js"></script>
```
dist/main.html
```html
<script src="main.js"></script>
```
在瀏覽器中分別訪問這兩個(gè)文件,這兩個(gè)文件分別依賴的js文件,都是獨(dú)立的,這就是多入口多出口。
wepack.config.js
```javascript
entry:{
? ? index:'./src/index.js',
? ? main:'./src/main.js'
},
output:{
? ? filename:'[name].js',
? ? path:path.resolve(__dirname, 'dist')
}
```
entry描述的是入口,表示有兩個(gè)入口 ,一個(gè)名字叫做index,一個(gè)名字叫做main。
output描述的是出口,filename描述的是打包后文件的名字,[name]是關(guān)鍵字表示entry入口文件名,path表示合并后文件所在位置。
命令行:
```bash
npm run build
```
就能夠根據(jù)entry的配置打包出2個(gè)js文件了
# 插件
安裝:
```bash
npm install --save-dev html-webpack-plugin
```
webpack.config.js
```javascript
const HtmlWebpackPlugin = require('html-webpack-plugin')
entry: { ... },
plugins: [ new HtmlWebpackPlugin({title:'標(biāo)題欄內(nèi)容'}) ],
output: { ... }
```
HtmlWebpackPlugin 的作用就是在 dist 目錄下生成 index.html 文件,
我們現(xiàn)在的項(xiàng)目中存在 dist/index.html 所以命令執(zhí)行后,會將之前的文件覆蓋了,
如果項(xiàng)目中不存在 dist/index.html,那么 HtmlWebpackPlugin 也能夠根據(jù)默認(rèn)的配置把這個(gè) index 文件創(chuàng)建出來。
# 清理dist目錄
每次執(zhí)行webpack編譯時(shí),最好先把之前的內(nèi)容清理干凈,然后重新生成。
```bash
npm install clean-webpack-plugin --save-dev
```
webpack.config.js
```javascript
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
plugins:[
? ? new CleanWebpackPlugin(),
? ? new HtmlWebpackPlugin...
]
```
# 錯(cuò)誤調(diào)試
webpack 是把很多個(gè)文件捆綁到一起,那么如果有段代碼出錯(cuò)了,怎么定位錯(cuò)誤?
src/print.js
把 console.log 改為 console.error 模擬一個(gè)錯(cuò)誤出來,執(zhí)行 npm run build 重新生成捆綁后的文件,瀏覽器運(yùn)行。
瀏覽器的控制臺中會報(bào)錯(cuò),因?yàn)槲覀冊L問的是生產(chǎn)環(huán)境下的代碼,所以報(bào)的是生產(chǎn)環(huán)境下的錯(cuò)誤,所以不好定位錯(cuò)誤。
webpack.config.js
```javascript
entry:{ ... },
devtool: 'inline-source-map'
```
加上 devtool 配置后,就能夠定位到錯(cuò)誤了,但要記得這僅僅是為了調(diào)試,生產(chǎn)時(shí)要關(guān)閉。
# 自動編譯和自動刷新
每次修改文件后,都需要手動 npm run build 這太麻煩了,所以可以安裝
```
npm install --save-dev webpack-dev-server
```
webpack.config.js
```javascript
devtool: 'inline-source-amp',
devServer: { contentBase: './dist' }? ? //把dist看作是一個(gè)根目錄去運(yùn)行
```
package.json
```javascript
"scripts":{
? ? "start" : "webpack-dev-server --open"
}
```
命令行運(yùn)行
```bash
npm start
```
然后直接修改 src 下的文件,在瀏覽器中瀏覽 dist 下的文件,看效果。
# 別名
可以把長的文件名配置短的別名,這樣描述依賴文件時(shí)會方便一些。
```javascript
output: {
? ? filename: '[name].bundle.js',
? ? path: path.resolve(__dirname, 'dist')
},
resolve:{
? ? alias: {
? ? ? '@': path.resolve('src'),
? ? ? '#': path.resolve('src/images'),
? ? ? 'fa': path.resolve('src/fonts/font-awesome-4.7.0/css'),
? ? }
},
```
使用別名
```javascript
import printMe from '@/print.js'
import img from '#/1.jpg';
import 'fa/font-awesome.min.css'
```
> 不能用$當(dāng)別名,修改webpack.config.js后要重新npm start
# 代理
解決跨域問題的一種方案
```javascript
devServer: {
? ? contentBase: './dist',? ??
? ? proxy:{
? ? ? ? "/api": {
? ? ? ? ? ? target: "http://www.wyyijiaqin.com",
? ? ? ? ? ? pathRewrite: { '^/api': '' },
? ? ? ? ? ? //secure: false,
? ? ? ? ? ? changeOrigin: true,
? ? ? ? }
? ? }
},
```
> 啟動 devServer ,該代理才有作用。
# 打包時(shí),代碼是否壓縮?
mode屬性可以定義打包時(shí)代碼是否壓縮。
- development 不壓縮代碼
- production 壓縮代碼,默認(rèn)
```javascript
output: {
? ? filename: '[name].bundle.js',
? ? path: path.resolve(__dirname, 'dist')
},
mode: "development"
```
# post-css
```bash
cnpm i postcss-loader -D
cnpm i autoprefixer -D? # 處理css瀏覽器兼容
```
這個(gè)模塊是用來處理css兼容的,會自動給css加上瀏覽器前綴,如-ms- -webkit- 等
**style/index.css**
```css
span{
? ? background: red;
? ? color:white;
? ? display: flex;
? ? flex: 1;
? ? transform: translate(-50%, -50%)
}
```
**index.js**
```javascript
import './style/index.css';
```
**webpack.config.js**
```
{
? ? test: /\.css$/,
? ? use: ['style-loader', 'css-loader', {
? ? ? ? loader: 'postcss-loader',
? ? ? ? options:{
? ? ? ? ? ? plugins: [
? ? ? ? ? ? ? ? require('autoprefixer')("last 100 versions")
? ? ? ? ? ? ]
? ? ? ? }
? ? }]
}
```
> require('autoprefixer')("last 100 versions") 參數(shù)改了就會出錯(cuò)。
語義:如果碰到css文件,先用style-loader和css-loader 處理,然后用postcss-loader處理,使用require引入autoprefixer模塊,處理css兼容
# 多個(gè) config 文件入口
配置獨(dú)立的 config 文件
比如我希望開發(fā)環(huán)境中,使用map,即出錯(cuò)時(shí),能夠看到錯(cuò)誤內(nèi)容,而生產(chǎn)環(huán)境下,出錯(cuò)時(shí),不希望看到出錯(cuò)的具體內(nèi)容,而且生產(chǎn)環(huán)境下的map還影響了文件的體積,所以應(yīng)該去掉。
```bash
npm install --save-dev webpack-merge
```
**通用配置 common.js**
```javascript
const path = require('path');
module.exports = {
? ? entry: {
? ? ? ? index: './src/index.js'
? ? },
? ? output: {
? ? ? ? filename: '[name].js',
? ? ? ? path: path.resolve(__dirname, 'dist')
? ? }
};
```
**開發(fā)環(huán)境的配置 dev.js**
```
const merge = require('webpack-merge');
const common = require('./common.js');
module.exports = merge(common, {
? ? devtool: 'inline-source-map',
? ? devServer: {
? ? ? ? contentBase: './dist'
? ? }
});
```
**生產(chǎn)環(huán)境的配置 prod.js**
```
const merge = require('webpack-merge');
const common = require('./common.js');
module.exports = merge(common, {
});
```
**package.json**
```
"scripts": {
? ? "start": "webpack-dev-server --open --config dev.js",
? ? "build": "webpack --config prod.js"
}
```
執(zhí)行 npm start 相當(dāng)于開啟了開發(fā)環(huán)境的服務(wù),如果出錯(cuò)了,檢查是不是某類文件類型的合并規(guī)則沒有被定義。
執(zhí)行 npm run build 表示根據(jù)開發(fā)環(huán)境中的文件,合并成生產(chǎn)環(huán)境下的文件。