博客 / 詳情

返回

有了這些方法,webpack你也可以自己配

前言

通過上篇文章——弄懂這幾個概念後,我對webpack有了更新的理解 的講解,我們大致瞭解了:

  • 使用webpack過程中出現的一些概念
  • 結合打包過程中出現的概念,淺析了webpack打包流程,讓大家對打包流程有個大致的理解

我們都知道,我們在實際開發過程中,使用webpack無非就是為了最後輸出瀏覽器能運行的cssimgjshtml等前端資源。

那麼,為了更貼近實際,我們這篇文章,就以如何輸出cssimgjshtml等前端資源為目的,學習一下如何配置webpack

學習大綱

這篇文章主要講解以下基礎配置:

  • 處理css、less文件
  • 處理圖片(img)、字體(font)、音樂(audio)等前端資源文件
  • 編譯es6+語法及API
  • 處理html文件

webpack文檔對配置寫的算挺詳細了,所以這裏我也不想複製粘貼又寫一遍,這樣不如大家直接看文檔。

授人以魚不如授人以漁,學習不能硬學,應該要有一些方法跟技巧。因此,我更想在講解配置的過程中,總結一些方法,讓我們更好的理解webpack的配置項。這樣,一些類似的一些配置,我們照葫蘆畫瓢,看文檔就可以配出來。

備註

文章涉及到的案例已經上傳到 github:

  • 為了閲讀方便,文章只貼了相關代碼,建議fork一下,看看完整代碼;或者跟着文章一起邊看邊敲,這樣印象會更深刻一些
  • 創作不易,如果覺得有幫助的話,歡迎star🌟

處理css、less文件

我們先用 learn-03 這個案例來看看webpack如何處理樣式文件。

我們安裝相應的loader解析:

  • less-loader:解析lesscss
  • css-loader:將css解析為webpack能識別的有效模塊
  • style-loader:將解析出來的css插入到<header />
npm install less less-loader css-loader style-loader -D

然後配置一下:

// webpack.config.js
module.exports = {
    ...,
    module: {
        rules: [
            {
                test: /.(css|less)$/, 
                use: [
                    'style-loader',
                    'css-loader',
                    'less-loader',
                ],
            },
        ]
    }
}

loader的解析是逆序執行(或從右到左),因此這個配置會按照(less-loadercss-loaderstyle-loader)以下順序執行:

  1. less解析成css
  2. 再將結果傳給css-loader,解析成webpack認識的有效模塊
  3. 再將結果傳給style-loader,將解析出來的樣式插入到<header />)的順序執行。

lesscss、入口文件代碼為:

// index.less
*{
    margin: 0;
    padding: 0;
}
h1{
    color: red;
    margin-top: 20px;
}

/* index.css */
h2{
    color: green;
}

// index.js
import './assets/index.less';
import './assets/index.css';

輸出:

我們會發現我們寫的樣式處理成功,並且被插入到<head/>中。

總結

我們 上篇文章 説過:

  • 我們通過importrequire進來的資源文件,或我們項目中的每個文件,都可以看作為一個獨立的模塊
  • Loader的作用就是把這些模塊(module)轉換成webpack能夠識別的有效模塊

webpack人性化的暴露了module配置項,就是專門用來配置相關loader,以此解析相應的module。因此,如果我們想解析我們源碼中使用的某些模塊,我們就應該:

  • 先下載相應的loader
  • 直接找到module配置項,根據loader使用方法直接配置

所以,我們按照上面總結的方法跟思想,可以試試自己配置處理一下.scss或者.txt文件


ok,我們成功得到了我們項目需要的樣式(css),接下來我們再看看如何處理圖片(img)等前端資源文件

處理前端資源文件

前端資源文件很多,在這裏,我們粗略的把它們先分成兩類:

  • 常用類:一般就是imgfontvideo等文件
  • 特殊類:.csv.xml等文件

這些資源只要import或者require進我們的源碼,那麼它一樣也是模塊。既然是模塊,我們就需要安裝相應的loader進行解析,然後在module配置項配置。

wepack5之前,對於常用類的資源,我們一般需要安裝以下loader來解析:

  • raw-loader:將文件解析成字符串
  • file-loader:將import/require()進來的文件,解析為一個完整引用的url,並將文件發送到輸出目錄中
  • url-loader:可以把文件轉成base64

我們經常用到的是file-loaderurl-loader這兩個。因為常用類資源,經常以url形式引入到我們項目中;或者為了減少http請求,直接轉換成base64

但是webpack5後,webpack已經內置上述幾個loader的功能,所以我們可以不用再安裝以上的loader了;我們可以直接使用webpack自帶的 asset module。

webpack5之後內置的資源模塊:

  • asset/source:等同於raw-loader
  • asset/resource: 等同於file-loader
  • asset/inline:等同於url-loader
  • asset:比較靈活,同時擁有asset/resourceasset/inline的功能。如果設置了文件大小限制,文件沒有超出這個大小的話,會轉為base64;如果沒設置大小限制,則功能跟file-loader一樣
這是我十分愛webpack5的原因,因為我們不要安裝那麼多亂七八糟的loader

我們用 learn-04 這個案例,看看怎麼使用資源模塊來解析我們的前端資源。

我們把上一章解析樣式的配置一起加進來,在lessjs中分別使用圖片資源。

我們有兩個圖片:

  • preview.gif:大小為349kb
  • ecj-cli.png:大小為4kb
// webpack.config.js
module.exports = {
    ...,
    module: {
        rules: [
            {
                test: /.(css|less)$/, 
                use: [
                    'style-loader',
                    'css-loader',
                    'less-loader',
                ],
            },
            {
                test: /\.(png|svg|jpg|jpeg|gif)$/i,
                type: 'asset',
                parser: {
                    dataUrlCondition: {
                      maxSize: 1024 * 10 // 當圖片 < 10kb 轉成base64
                    }
                },
                generator: {
                    filename: '[name][ext]' // 設置輸出的文件名字
                }
            }
        ]
    }
}

入口文件:

// index.js
import './assets/index.less';

const img = new Image();
img.src = require('./assets/ecj-cli.png');
img.width = 500;
document.querySelector('#js_logo').append(img);

樣式:

.bg_logo{
    width: (1434/3px);
    height: (1212/3px);
    background-image: url('./preview.gif');
    background-size: 100%;
}

輸出結果:

compile_resource

我們會發現樣式跟js都處理圖片成功:

  • preview.gif大於10kb,所以沒有被轉為base64,而是返回了一個完整的引用路徑(相當於file-loader的功能)
  • ejc-cli.png小於10kb的則被轉為了base64(相當於url-loader的功能)。

上面的gif圖,是我開發的一個在日常項目中十分實用的命令行工具 ejc-cli 。它可以將對接人員收集的Excel數據,按一定格式轉成我們代碼所需要的json數據。它十分方便我們開發維護數據,並且還有跟其他人員對接數據。

感興趣的朋友可以看看 👉🏻 瞭解 ejc-cli

總結

通過import或者require進我們源碼的資源,一樣是一種模塊。所以需要下載相應的loader,然後到module配置項進行配置。

對於常用類資源(imgfontvideoaudio等等):

  • 因為常用,所以webpack5把處理它們的功能內置了,這樣我們不用額外安裝loader,我們直接使用asset module來管理
  • 我們一般都使用asset/resourceasset/inlineasset這幾個模塊來管理常用類資源。因為我們常用類的資源,經常會在我們項目中引入使用,我們需要把它們解析成引入完整的url,或者為了減少http請求,直接轉換成base64

對於特殊類資源(.csv.xml等等):

  • 我們可以理解為,因為不常用,所以webpack沒有把它們的功能內置
  • 因此,我們需要安裝相應的loader來解析。例如我們想解析.csv文件,我們需要安裝csv-loader來解析

按照上面總結的方法,可以試試自己配置處理一下video或者font等文件


好,到目前,我們已經得到了cssimg。我們接下來看看,如何通過webpack處理得到我們的js

編譯es6+

時至今日,js發展迅速,為了提高開發效率和代碼質量,每年都會有一些新的語法或者新的API出現。

例如,在語法方面出現了:

  • 箭頭函數:()=>
  • 類語法糖:class People {}
  • 解構賦值:const [x, y] = [1, 2];
  • ...

API方面又有:

  • Promise
  • Array.prototype.includes()
  • Object.keys()
  • ...

但是這些新的內容在一些低版本瀏覽器上是不支持的,所以我們需要通過webpack來將我們的es6+編譯成這些低版本瀏覽器能支持的版本。

我們先用 learn-05 這個案例,看看我們怎麼配置webpack編譯es6+

我們安裝相關依賴:

...
"devDependencies": {
    "@babel/core": "^7.22.8",
    "@babel/plugin-transform-runtime": "^7.22.7",
    "@babel/preset-env": "^7.22.7",
    "babel-loader": "^9.1.3",
    "webpack": "^5.88.1",
    "webpack-cli": "^5.1.4"
},
"dependencies": {
    "core-js": "^3.31.1"
},

入口文件。使用了classPromise()=>{}es6+語法及API

// index.js
class People {
    constructor(name) {
        this.name = name;
    }
    sayHi() {
        return Promise.resolve(this.name);
    }
}
const Lee = new People('Lee');
Lee.sayHi().then(name => console.log(`Hi, I am ${name}.`));

配置webpack

// webpack.config.js
module.exports = {
    ...,
    module: {
        rules: [
            {
                test: /\.m?js$/,
                exclude: /(node_modules|bower_components)/,
                use: {
                    loader: 'babel-loader'
                }
            }
        ]
    }
}

配置Babel。在項目根目錄新建babel.config.js文件:

// babel.config.js
const presets = [
    [
        '@babel/preset-env',
        {
            useBuiltIns: 'usage',
            corejs: {
                version: require('core-js/package.json').version,
                proposals: true
            }
        }
    ]
];
const plugins = [
    '@babel/plugin-transform-runtime',
];
module.exports = {presets, plugins}

設置要兼容的目標瀏覽器。在package.json添加browserslist字段:

"browserslist": [
    "ie 11"
]

ie 11運行的結果:

compile_es6

我們會發現:

  • 我們寫的es6+ie 11運行成功
  • Promise這個es6+ API,也被添加到了ie 11

説明我們編譯的es6+是成功的。

關於Babel

在上面配置中,大家會發現,如果我們想用webpack編譯es6+,我們還需要在根目錄添加babel.config.js文件,步驟比處理其他模塊要複雜麻煩的多。這是因為,編譯es6+的核心,是需要Babel來配合的Babel是編譯es6+的一個工具。

由於本篇文章主要是講解webpack,所以在這裏,我們對Babel就大概提一下。以下是Babel常用的一些配置。

  • 如果我們開發的項目是應用程序大型的項目,我們可以這麼配置:

    const presets = [
        [
            '@babel/preset-env',
            {
                modules: false,
                useBuiltIns: 'entry', // or useBuiltIns: 'usage',
                corejs: {
                    version: '3.27.2',
                    proposals: true
                }
            }
        ]
    ];
    const plugins = [
        '@babel/plugin-transform-runtime'
    ];
    module.exports = {plugins, presets};
    
    // index.js
    // If use useBuiltIns: 'entry'
    import 'core-js/stable'
  • 如果我們是想開發一個第三方庫,我們可以這麼配置:

    // Babel配置
    const presets = [
        [
            '@babel/preset-env',
            {
                modules: false
            }
        ]
    ];
    const plugins = [
        [
            '@babel/plugin-transform-runtime',
            {
                corejs: {
                    version: 3,
                    proposals: true
                }
            }
        ]
    ];
    module.exports = {plugins, presets};

如果你想對Babel已經有個瞭解,但處於懵懵懂懂的狀態;又或者你想學習Babel,可以看看我之前寫的關於Babel的專欄 👉🏻 Babel專欄。

相信我,看完你一定會有所收穫。

總結

  • js一樣是import或者require進我們的源碼,那麼它也是模塊。所以我們也要下載對應的loaderbabel-loader)並且在module配置項配置它。
  • 此外,我們除了配置babel-loader,最重要的是還需要配置Babelbabel.config.js)。

所以,如果想要“編譯es6+”,我們除了要配置webapck,最重要的是我們還要配置babel.config.js如果你不想只是一味的複製粘貼Babel配置,你還必須得學習Babel相關知識。


還記得我們使用webpack的目的嗎?輸出瀏覽器能運行的cssimgjshtml等前端資源。

OK,到目前我們已經通過webpack處理了cssimgjs。我們再來看看如何通過webpack處理得到我們的html

處理html文件

在上面的例子中,我們想在瀏覽器看效果,我們需要:

  • 在根目錄新建一個html文件
  • 在新建的html文件中,手動引入打包出來的資源文件

這個過程太麻煩了,有沒有一種辦法,我們只用提供一個html模板文件,然後通過webpack編譯後,它自動幫我們把打包後的文件都引入好。這樣,我們打包完直接運行html就能在瀏覽器看效果就好了呢?

webpack這麼人性化的東西,當然是有的。

我們先用 learn-06 這裏例子看看如何利用webpack達到我們上述的效果。

安裝相關插件:

npm i html-webpack-plugin -D

這次webpack配置來點不一樣的:
我們設置打包後的js儲存目錄為js文件夾;為打包後的js名字增加5個長度的hash值。

// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');

module.exports = {
    entry: {
        index: './src/index.js'
    },
    output: {
        path: path.resolve(__dirname, './dist'),
        filename: './js/[name]-[chunkhash:5].js',
        clean: true
    },
    
    plugins: [
        new HtmlWebpackPlugin({
            filename: path.resolve(__dirname, './dist/[name].html'),
            template: path.resolve(__dirname, './index.html'),
            title: 'HtmlWebpackPlugin',
        })
    ],
}

打包後的文件結構為:

dist
├── index.html
└── js
    └── index-efbfd.js

打包後的html如下:

compile_html

我們會發現:

  • 我們的htmljs都被打包輸出到dist文件夾下,這十分方便我們部署(之前我們是在根目錄下新建index.html,因此打包後dist文件夾內只有imgjs等文件)
  • 打包後的html會幫我們自動引入好我們打包後的js文件

分析

從上面的例子我們可以看出,想要webpack處理html文件,我們是需要在webpack提供的plugins配置項來配置的。可能有些人會疑惑html也是一個模塊,為什麼是在plugins配置,而不是在module裏面配置?我們來分析一下。

我們項目所有文件當然可以看作是一個模塊,但是module裏面配置還是在plugins裏面配置,取決於我們對這些模塊的使用目的。一般我們在自己的源碼中使用到這個模塊,則需要相應的Loader來解析

在上文講解如何處理imgjs時,我們的目的是為了在源碼中解析這些文件

  • img,我們需要將它轉化成base64
  • js,我們需要將es6+的東西編譯成es5及以下

並且,我們的文件都是通過import或是require()的方式,引入到我們的項目中,因此這時候當然需要相應的Loader來轉換這些模塊。

但是在處理html文件時,我們的目的並不是為了要解析html,我們只是想讓打包出來的html自動引用我們的jsimg,這更像是使用自動引入的功能;而且,我們也沒有把我們的html引入進我們的項目,因此我們當然不需要相應的Loader來解析。

還記得我們 上篇文章 我們講解過:Loader用於轉化模塊,Plugin則用來加強webpack打包編譯時的功能。

在此處我們處理html文件,目的更多側重的是想要讓打包出來的html自動引用我們的jsimg這個功能。因此我們需要在plugins配置項來配置,增強webpack打包編譯時的功能。

同理,假設我們想要在項目中解析某個html文件(在我們項目中,import html from './x.html'),那我們就得安裝相應的loaderhtml-loader),並且在module配置項目中配置。

總結

module還是plugins配置項裏配置,取決於我們對這些模塊的使用目的。


至此,我們已經成功通過配置webpack拿到了一個項目中需要的cssimgjshtml;這也相當於學會了webpack的一些基本配置。

大家可以通過上面總結的一些方法,自己完成對sassfontvideo等資源的處理,加深一下印象。

學習總結

通過上面對一些配置項的講解,我們可以有以下總結:

  • 想要解析css,需要安裝相應的loader,並且在module裏配置
  • 想要解析imgfontvideo等常用類資源,我們不用安裝loaderwebpack已經內置解析他們的功能)。我們一般在module配置項裏,使用asset/resourceasset/inlineasset這三個內置模塊來解析
  • 想要解析js,我們除了要安裝相應的loaderbabel-loader),在module配置項裏配置,最重要的是我們還要學習Babel的相關知識(感興趣可以看看我的 👉 Babel專欄)
  • 想要解析html文件,我們需要在plugins配置項裏配置html-webpack-plugin插件
  • module還是plugins配置項裏配置,取決於我們對這些模塊的使用目的

通過上面的學習,我們整理一下,輸出一個完整的webpack基礎配置,讓大家加深印象:

const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');

module.exports = {
    entry: {
        index: './src/index.js'
    },
    output: {
        path: path.resolve(__dirname, './dist'),
        filename: './js/[name]-[chunkhash:5].js',
        clean: true
    },
    module: {
        rules: [
            {
                test: /.(css|less)$/, 
                use: [
                    'style-loader',
                    'css-loader',
                    'less-loader',
                ],
            },
            {
                test: /\.(png|svg|jpg|jpeg|gif)$/i,
                type: 'asset',
                parser: {
                    dataUrlCondition: {
                        maxSize: 1024 * 10 // When the image size is < 10kb it will be converted to base64
                    }
                },
                generator: {
                    filename: '[name]-[hash:5][ext]' // Set the name of the output file
                }
            },
            {
                test: /\.m?js$/,
                exclude: /(node_modules|bower_components)/,
                use: {
                    loader: 'babel-loader'
                }
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            filename: path.resolve(__dirname, './dist/[name].html'),
            template: path.resolve(__dirname, './src/index.html'),
            title: 'Webpack Basic Configuration',
        })
    ],
}

完整的基礎配置在 learn-07 ,建議大家看看完整版,這裏只貼了webpack.config.js

最後

  • 希望這篇文章的一些方法總結,學習目的能讓大家更好的學會如何配置webapck
  • 後面的文章將會深入配置。現實項目中,大多分開發環境、生產環境,因此我們將學習如何針對開發環境、生產環境不同的環境,進行不同webpack的配置,這更貼近我們現實項目。如果感興趣的話可以關注一下這個 👉 專欄
  • 文章涉及到的Babel知識,如果你感興趣,想學習,也可以看看 👉 Babel專欄
  • 文章涉及到的案例已經上傳到 github,歡迎starfork學習

最後的最後,如果大家覺得文章有幫助到,創作不易,還請大家多點贊收藏評論,如果有異同點,歡迎評論討論。

user avatar xiangjiaochihuanggua 頭像 jidongdehai_co4lxh 頭像 yaofly 頭像 ivyzhang 頭像 chongdianqishi 頭像 susouth 頭像 jianqiangdepaobuxie 頭像 gaoming13 頭像 201926 頭像 yilezhiming 頭像 light_5cfbb652e97ce 頭像 fehaha 頭像
30 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.