10. vue之webpack打包詳解

盛開的太陽發表於2021-03-03

一、什麼是webpack

webpack官網給出的定義是

本質上,webpack 是一個現代 JavaScript 應用程式的靜態模組打包器(module bundler)。當 webpack 處理應用程式時,
它會遞迴地構建一個依賴關係圖(dependency graph),其中包含應用程式需要的每個模組,然後將所有這些模組打包成一個或多個 bundle。

10. vue之webpack打包詳解

 

 

如上圖: 中間的藍色塊就是webpack. 他會將左邊各種檔案打包成右側html能夠解析的檔案. 

總結:

webpack是一個靜態的打包模組. 
這裡涉及兩個概念: 打包模組

 

1. 什麼是模組?

上一篇文章, 說了什麼是模組化, 詳見: https://www.cnblogs.com/ITPower/p/14466964.html
模組化有很多規範, commonJs規範, AMD規範, CMD規範, ES6規範等
在ES6之前, 要想使用模組化開發,就要藉助其他的工具, 而且開發完成以後, 還需要處理各種依賴,並將其進行整合打包.

webpack可以讓我們進行模組化開發, 他提供了平臺, 並且會幫助我們處理各模組之間的依賴關係.
webpack最終會幫我們將js, css, 圖片, json檔案等打包為合適的格式, 以供瀏覽器使用.
在webpack中上述檔案型別都可以被當做模組來使用.

2. 什麼是打包?

就是將webpack中各種模組資源進行打包合併成一個或多個包. 並且在打包的過程中, 可以對資源進行處理, 如:壓縮圖片, 將scss轉成css, 將ES6語法轉成ES5等可以被html識別的檔案型別.

 

二. webpack打包工具的安裝

webpack打包工具依賴nodejs. nodejs環境依賴各種包, 這些包使用npm進行管理. npm是什麼呢? npm就是用來管理node下的各種包的

接下來看看webpack如何安裝?

第一步: 安裝nodejs

在官網下載nodejs:https://nodejs.org/zh-cn/ 安裝好以後可以檢視nodejs的版本

node -v

我當前的版本是 v12.16.2

預設安裝nodejs的時候, 就會自動安裝npm, 所以, npm不用單獨安裝

第二步: 安裝webpack

我使用的webpack版本是3.6.0, 因為我當前使用的vue的版本是2, vue2依賴的webpack版本是3.6.0

首先檢視本機是否已經安裝了webpack, 使用命令查詢

 webpack --version

如果沒有安裝, 則安裝全域性的webpack

npm install webpack@3.6.0 -g

-g:表示的是global  全域性的意思

webpack需要全域性安裝, 也需要區域性安裝. 

我們在終端或者IDE的terminal中使用webpack都是使用的全域性的webpack,當我們在專案下使用package.json scripts webpacks, 這時候使用的是區域性安裝的.

那什麼是全域性webpack ,什麼是本地webpack呢?

我們通常都會安裝兩個webpack, 一個是全域性的一個是本地的.
全域性的指的是電腦上安裝的webpack包, 所有專案都可以使用
本地webpack是指當前專案的webpack包. 通常全域性webpack版本會比較高, 而我的專案是老專案, 使用的是老版本的
webpack打包的, 這時如果使用全域性的webpack打包就會報錯, 所以, 需要安裝一個和專案匹配的本地的webpack包

 

在這裡, 我們先值安裝全域性的, 後面使用到本地的了, 再來安裝本地的webpack.

 

三. webpack的基本使用

webpack下通常包含兩個資料夾, 一個是src, 一個是dist

  • src下都會有一個main.js, 作為主js檔案.
  • dist存放打包後的檔案

10. vue之webpack打包詳解

 

 

 

在webpack中,我們會使用兩種型別的模板來定義: 分別是commonJs語法, 和ES6語法.

  • 在main.js引用mathUtil.js, 使用commonjs語法
  • 在main.js引用dataUtil.js, 使用ES6語法

 下面, 我們建立一個mathUtil.js 和 dataUtil.js兩個js檔案, 分別使用commonJs語法和ES6語法來建立.

  • - 在main.js引用mathUtil.js, 使用commonJs語法

  • - 在main.js引用dataUtil.js, 使用ES6語法

專案結構如下:

10. vue之webpack打包詳解

1)  使用commonJs語法

第一步: 在mathUtil.js中export, 使用commonJs模組的寫法 : module.exports ={add, sub}

function add(num1, num2) {
    return num1 + num2
}


function sub(num1, num2) {
    return num1 - num2
}

// 使用commonJs匯出模組
module.exports={add, sub}

這裡使用的是commonJs的語法匯出方法


第二步: 在main.js中引用mathUtil.js中匯出的變數 const {add, sub} = require("檔名")

const{add, sub} = require("./mathUtil.js")

console.log(add(10, 20))
console.log(sub(20, 10))

 

第三步: 使用webpack語句打包 : webpack ./src/main.js ./dist/bundle.js

 

首先進入到當前專案的根目錄下, 然後輸入命令

webpack ./src/main.js ./dist/bundle.js

意思是: 將src目錄下的main.js進行打包, 打包好的檔案放在dist目錄下, 並命名為bundle.js

webpack是自動打包工具, 所以, 我們只需要打包main.js, 他會自動檢查main.js是否引用了其他檔案. 如果有自動將其打包.

10. vue之webpack打包詳解

 

打包以後, 會生成一個bundle.js.  

第四步: 在index.html中引入bundle.js檔案

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./dist/bundle.js" ></script>
</head>
<body>

</body>
</html>

引入以後, 就是普通的html程式碼了, 我們可以向訪問其他html一樣,訪問這個頁面.

 

2) 使用ES6語法

第一步: 在dateUtil.js中匯出, 使用ES6寫法: export {var1, var2}

function priceUnit(price) {
    return "$" + price.toFixed(2)
}

export {priceUnit}

 

第二步: 在main.js中引用dateUtil.js中匯出的變數 import {var1, var2} from "檔案地址"

import {priceUnit} from "./dataUtil"

console.log(priceUnit(25))

 


第三步: 使用webpack語句打包 : webpack ./src/main.js ./dist/bundle.js

webpack ./src/main.js ./dist/bundle.js

第四步: 在index中引用bundle.js檔案

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./dist/bundle.js" ></script>
</head>
<body>

</body>
</html> 

四. webpack配置檔案

1. 如何使用webpack命令直接打包

剛剛我們打包的時候, 使用的是

webpack ./src/main.js ./dist/bundle.js

那麼, 如果在專案下, 可不可以直接使用webpack, 而不用每次都指定檔案呢? 這樣可以方便很多
當然是可以的, 我們需要在專案根目錄下建立一個檔案: webpack.config.js 這個名字是固定的


這個js就是要告訴我們哪裡是webpack的入口, 哪個是webpack的出口

webpack.config.js

module.export={ entry: './src/main.js', output: { path: '/dist', filename: '/bundle.js' } }

 

  • entry用來指定入口, 指定一個路徑
  • output用來指定出口. 需要注意的是: 出口是一個物件, 由兩部分組成: path和filename

 

然後我們在終端輸入webpack打包. 打包會報錯, 報錯資訊提示很明確: 

The provide value "./dist" is not an absolute path!

意思是說path應該是已經絕對路徑. 也就是dist的絕對路徑

 

思考: 我們能直接寫一個絕對路徑麼? 比如: /Users/workspace/vue-study/webpack的配置/src/main.js 這樣可以麼?
這樣肯定不太好, 因為我一旦將檔案文在其他目錄下, 這個地址就變了.

webpack可以幫助我們獲取當前專案的絕對路徑
我們const path = require("path")來獲取相對目錄. 可是當前目錄下沒有path的包, path是node下東西, 需要通過npm init來初始化,

2. 初始化專案npm init

初始化命令

npm init

初始化完成以後, 就會建立一個叫package.json的檔案

通常, 我們需要使用node的東西, 或者單獨依賴node環境的話, 都會執行npm init, 生成package.json

3. 安裝模組

如果package.json裡面依賴其他模組, 需要使用npm install的安裝一下, 然後就會在當前資料夾中安裝一些東西

npm install
  • const path = require("path")這裡的path就是node給我們生成的, 我們可以直接使用.

然後我們的output中path就可以這麼寫: 

path.resovle(__dirname, "dist")
  • _dirname是一個全域性變數, resolve是一個函式, 可以將兩個部分的內容拼在一塊, 這樣生成以後就是一個絕對路徑

4. 使用npm run來啟動專案

下面來看一下package.json

{
  "name": "meet",
  "version": "1.0.0",
  "description": "剛剛我們打包的時候, 使用的是webpack ./src/main.js ./dist/bundle.js 那麼, 如果在專案下, 可不可以直接使用webpack, 而不用每次都指定檔案呢? 可以的, 我們需要在專案根目錄下建立一個檔案, webpack.config.js 這個名字是固定的 這個js就是要告訴我們哪個是webpac的入口, 哪個是webpack的出口 通過module.export={     entry: './src/main.js',     output: {         path: '/dist',         filename: '/bundle.js'     } } 來告訴我們入口和出口在哪裡. entry用來指定入口, 指定一個路徑 output用來指定出口. 出口是一個物件",
  "main": "webpack.config.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

通常我們啟動項的時候會使用npm run serve啟動專案, npm run build構建專案. 當執行這個命令的時候, 就會去package.json中的script標籤中找build命令和serve命令.

執行npm run build讓其執行webpack打包就可以在script中增加"build":"webpack"

{
  "name": "meet",
  "version": "1.0.0",
  "description": "剛剛我們打包的時候, 使用的是webpack ./src/main.js ./dist/bundle.js 那麼, 如果在專案下, 可不可以直接使用webpack, 而不用每次都指定檔案呢? 可以的, 我們需要在專案根目錄下建立一個檔案, webpack.config.js 這個名字是固定的 這個js就是要告訴我們哪個是webpac的入口, 哪個是webpack的出口 通過module.export={     entry: './src/main.js',     output: {         path: '/dist',         filename: '/bundle.js'     } } 來告訴我們入口和出口在哪裡. entry用來指定入口, 指定一個路徑 output用來指定出口. 出口是一個物件",
  "main": "webpack.config.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack"
  },
  "author": "",
  "license": "ISC"
}

 

然後就可以使用npm run webpack來打包了. 但是這裡打包是全域性打包. 因為我們之前只安裝了一個全域性的webpack.
但如果專案使用的版本和全域性的不一樣, 怎麼辦呢? 我們還可以使用區域性的wenpack打包.

5. 全域性webpack和區域性webpack有什麼區別呢?

我們通常都會安裝兩個webpack,

  • 一個是全域性的
  • 一個是本地的.

全域性的指的是電腦上安裝的webpack包, 所有專案都可以使用
本地webpack是指當前專案的webpack包.

通常全域性webpack版本會比較高, 而我的專案是老專案, 使用的是老版本的
webpack打包的, 這時如果使用全域性的webpack打包就會報錯, 所以, 需要安裝一個和專案匹配的本地的webpack包

6. 安裝本地webpack命令

npm install webpack@3.6.0 --save-dev
  • --save-dev: 這個引數的含義表示開發時依賴.

這裡有兩個概念:

  • 1. 開發時依賴
  • 2. 執行時依賴

對於打包來說, 我們只有在開發環境才會打包, 開發好以後要上線了會將其構建成html程式碼, 放到伺服器上執行,
放到伺服器以後, 就不需要打包了, 所以, 打包只需要在開發時使用, 是一個開發時依賴

本地webpack安裝好以後, 會在package.json中看到devDependencies屬性, 這就是開發時依賴

本地webpack安裝好以後, 使用npm run build進行打包. 那是使用的全域性webpack打包的還是本地webpack打包的呢?
本地安裝好webpack以後會多出一個資料夾node_modules, 這裡是預設在本地裝的包, 其中有一個是webpack, 使用這裡面的webpack
就表示使用的區域性webpack打包. 而當我們在終端, 或者ide的terminal中執行webpack命令都是全域性的


如果想要使用區域性webpack打包, 可以使用npm run build. 這時就是去package.json的script指令碼中找build命令了.

package.json中指令碼命令執行的順序:

  • 首先, 在本地的路徑中找命令
  • 然後, 本地沒有, 再去全域性中找命令

在這裡首先回去本地找有沒有這個命令, 如果沒有就去全域性找

 

 五.使用webpack打包css檔案

webpack主要是用來打包的, 我們之前都是打包了js程式碼檔案, 那如果還有css, 圖片, 或者一些高階轉換,如將ES6轉換成ES5,將scss, less轉成css, 將.vue檔案轉換成js檔案怎麼辦呢?

webpack單獨是不能完成轉換的,需要藉助loader.

1. 什麼是紹loader?

webpack 可以使用 loader 來預處理檔案。這允許你打包除 JavaScript 之外的任何靜態資源。

loader是webpack中一個非常核心的概念, loader有很多種, 不同的內容需要使用不同的loader來載入.

2. loader的使用

我們首先來建立一個css檔案, 然後將css檔案引入到專案中

第一步: 建立main.css檔案

body{
    background-color: #085e7d;
}

第二步: 將main.css檔案引入到main.js中

require("./css/main.css")

這是使用commonJs的寫法引入的. 引入css以後, 不需要任何返回值, 所以, 我們可以不用寫成  "let 變數名 = require(檔案路徑)"

第三步: 執行npm run build, 會報異常

10. vue之webpack打包詳解

 

 這個異常的意思是, 缺少合適的loader. 因為我們引入了css, 但是還沒有引入解析css的loader.

css需要兩個loader :

  • 一個是css-loader
  • 另一個是style-loader

css-loader: 只負責載入css檔案, style-loader: 負責將樣式載入到Dom中

第四步: 通過npm安裝loader

我們的目標是安裝loader, 可以去官網找到對應的loader. css檔案對應的loader.

官網地址: www.webpackjs.com

10. vue之webpack打包詳解

 

 找到css-loader的用法

10. vue之webpack打包詳解

 

 

安裝命令

npm install --save-dev css-loader 

第五步: 在webpack.config.js中的modules關鍵字下配置

  module: {
        rules: [    
            {
                test: /\.css$/,
                use: ['css-loader']
            }

        ]
    }

 

第六步: 安裝style-loader

安裝方法和css是一樣的.  可以通過查詢官網找到方法

安裝style-loader命令

npm install --save-dev style-loader    

然後在將style-loader放在css-loader的前面

module: {
    rules: [
        {
            test: /\.css$/,
            // css-loader: 只負責載入css檔案
            // style-loader: 負責將樣式載入到Dom中
            // 注意: 使用loader載入的時候, 是從右向左載入的. 所以, 先載入css-loader, 在載入style-loader
            use: ['style-loader','css-loader' ]
        }

    ]
}

 

為什麼需要將style-loader放在前面呢? 

其實在解析css的過程中, 先用到的是css-loader, 然後使用到的是style-loader. 但是webpack.config.js在解析的時候, 是從右往左解析的. 

第七步: 打包

npm run build

打包以後報錯: 

css (node:93638) UnhandledPromiseRejectionWarning: TypeError: this.getResolve is not a function

遇到這個問題, 說明版本不合適, 我們使用的webpack是3.6.0的版本, 打包的時候, 我們需要重新制定一下css-loader和style-loader的版本號

開啟package.json, 找到devDependencies

"devDependencies": {
    "css-loader": "^2.1.1",
    "style-loader": "^2.0.0",
    "webpack": "^3.6.0",
  }

指定css-loader和style-loader的版本號分別是2.1.1和2.0.0

再次打包, 成功!
 

 六. webpack打包less檔案

 其實我們知道如何打包css檔案了, 那麼打包less檔案方法是類似的 

第一步: 定義一個less檔案

我們定義一個less檔案, 起個名字common.less

@fontsize: 24px;
@fontcolor: #5112b8;

body {
  font-size: @fontsize;
  color: @fontcolor;
}

第二步: 將less檔案import引入到main.js中

require("./css/special.less")

 

第三步: 安裝less元件, 應該安裝哪些元件呢? 可以看https://cn.vuejs.org/v2/guide/

查詢官網: www.webpackjs.com

10. vue之webpack打包詳解

 

 

安裝元件命令

npm install --save-dev less-loader less

新增規則

module.exports = {
    ...
    module: {
        rules: [{
            test: /\.less$/,
            use: [{
                loader: "style-loader" // creates style nodes from JS strings
            }, {
                loader: "css-loader" // translates CSS into CommonJS
            }, {
                loader: "less-loader" // compiles Less to CSS
            }]
        }]
    }
};

 

注意: 順序不能改變


第四步: 重新打包.

npm run build

 

 七. webpack打包圖片檔案

下面來看看webapck是如何打包圖片的

第一步: 在css中引入一個圖片檔案

比如: 我引入了一個背景圖

10. vue之webpack打包詳解

 

 

 

然後將圖片作為背景引入到main.css中

body{
    background: url("../img/123.jpeg");
}

第二步: 將main.css檔案通過import引入到main.js中

require("./css/main.less")

 我們知道webpack是自動打包工具, 在打包main.js的時候, 他會看裡面都引入了哪些內容. 他發現引入了main.css, 就是去自動載入並解析css對應的模組. 在css中引入了圖片, 就會去自動載入並解析圖片對應的模組. 

第三步: 安裝解析圖片的元件

查詢官網: www.webpackjs.com

我們看到background是通過url引入的, 首先需要url-loader模組. 

安裝元件命令

npm install --save-dev url-loader 

新增規則

{
    test: /\.(png|jpg|gif|jpeg)$/,
    use: [ {
        loader: 'url-loader',
        options: {
            limit: 8000,
        }
    }]
}

我們發現這次引入的時候有一個options引數, 這個引數限制了圖片的大小. 

注意: 

  • 當載入的圖片, 小於limit時, 會將圖片編譯成base64字串形式. --- 不需要檔案, 因為他是一個base64字串
  • 當載入的圖片, 大於limit是, 需要使用file-loader模組來載入. --- 當檔案來處理, 就需要打包成檔案, 需要file-loader

當以檔案的形式載入的時候, 需要指定一個打包路徑. 否則載入的檔案目錄是根目錄, 結果會找不到檔案, 因為我們的檔案最終打包到dist下面了.

 

module.exports={
    // 入口
    entry: "./src/main.js",
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: "bundle.js",
        publicPath:"dist/"
    }
...
}

我們可以在output位置增加publicPath:"dist/" 以後, 所有的路徑類的檔案在打包編譯的時候, 都會打包到這個路徑下面

八. webpack打包--將ES6打包成ES5 

 為什麼需要將es6打包成es5呢? 因為上述方式的webpack打包後, 並沒有將ES6的語法轉換成ES5的, 比如:

10. vue之webpack打包詳解

 

 這會有什麼問題呢?

有些瀏覽器可能不認識. 因為不是所有的瀏覽器都相容ES6, 但基本所有的瀏覽器都相容ES5的語法. 因此我們需要將ES6的語法轉換成ES5的語法

 方法和上面是一樣的.

 第一步: 安裝元件

打包ES6到ES5需要的元件是bebal

查詢官網需要安裝哪些元件: www.webpackjs.com

10. vue之webpack打包詳解

 

 安裝命令:

npm install --save-dev babel-loader@7 babel-core babel-preset-es2015

我們這裡安裝的是babel-loader的7的版本. babel-preset的版本是es2015

 第二步: 配置babel-loader元件

module: {
  rules: [
    {
      test: /\.js$/,
      exclude: /(node_modules|bower_components)/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['es2015']
        }
      }
    }
  ]
}

這個配置裡面指定了exclude, 排除哪些目錄: 這裡排除了node_modules目錄, 因為這個目錄下的檔案我們不需要打包. 是node編譯需要的內容. 

presets屬性,用來指定將es6轉換成es5需要的版本. 我們這裡直接填es2015就可以了.

第三步: 打包

npm run build

這次在去看bundle.js檔案, 裡面就沒有es6的語法了

 

相關文章