博客 / 詳情

返回

帶着這種思想,我快速高效的學會了webpack“開發環境配置”

前言

我們在使用webpack時,經常會看到類似以下結構:

build
├── webpack.common.js
└── webpack.dev.js
└── webpack.prod.js

很多時候,webpack的配置我們基本複製粘貼過來的,沒有想過為什麼我們要把配置文件拆解成這麼多。因此,當我們自己去學習配置webpack時,我們經常會出現以下等問題:

  • 開發環境構建速度慢
  • 打包後頁面空白
  • 資源找不到

其實這些問題,都源於我們:

  • 不理解webpack構建開發環境、生產環境,兩種環境配置的思想差異
  • 對兩種環境輸出的文件目錄,腦海中沒有一個清晰的理解

所以本文還是跟以前一樣,不會一味的把配置複製過來,而是希望總結相關方法,讓大家更好學會配置。

前期準備

由於講的是配置,所以希望你對webpack有一些基礎。如果你只是剛學習webpack,建議先閲讀一下前兩篇文章,尤其是第二篇

  1. 弄懂這幾個概念後,我對webpack有了更新的理解:學習使用webpack時涉及到的一些概念,讓我們對webpack整體有個大致的瞭解
  2. 有了這些方法,webpack你也可以自己配:總結配置webpack時的一些方法。通過這些方法,我們可以很好的理解webpack的一些基礎配置該如何配置

學習大綱

這篇文章主要講解:

  • webpack開發環境配置的核心思想
  • 根據核心思想,完成一個開發環境配置
  • 解析devServer配置項一些容易混淆的點
  • 總結webpack開發環境配置核心

備註

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

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

開發環境核心思想

在上文我們提到,我們在使用webpack時,經常會看到類似以下目錄:

build
├── webpack.common.js
└── webpack.dev.js
└── webpack.prod.js

為什麼我們需要把配置文件拆解成這麼多,那麼繁瑣呢?

我們先回顧一下,在我們在實際開發中,為了項目能夠穩定安全上線,我們一般會分好幾個環境:

  • 開發環境:在本地進行開發,調試的環境
  • 測試環境:我們在本地開發完成後,將代碼部署到我們的測試服務器,進行測試
  • 生產環境:測試通過,將代碼部署到正式服務器,正式上線
有些更嚴格的測試,還會有預生產環境等

我們的配置應該對環境具有針對性,因此不同的環境,我們的配置當然不能千篇一律。

目的

我們要先清楚開發環境根本的目的是什麼。

開發環境的根本目的,就是在開發過程中,能快速定位到問題,更快能看到效果調試,提高開發效率。

尤其作為前端,離不開跟視覺打交道。我們巴不得Ctrl+S後,立馬出效果,方便我們快速調試。試想一下,如果每次寫完一個效果,要等上幾秒鐘才能看到,這會不會把我們逼瘋?

思想

因此,為了能讓我們儘快看到效果調試,減少webpack的編譯過程,開發環境,配置應該一切從簡

  • 對樣式,我們不需要分離,直接用style-loader插入到<head />
  • jsimgmediafont等前端資源文件,不需要分包
  • 開啓source map,方便定位問題
  • 使用webpack提供的devServer配置項,進行本地開發
  • 不要壓縮代碼
  • 不用沒必要的loaderplugins
  • ...

開發環境配置,也因人而異,以上是我的做法。但是我們要記得,開發環境,配置應該一切從簡,為了讓我們能夠更快看到效果,提高開發效率

開發環境配置

初體驗

通過前一篇文章的講解,相信大家對webpack的基礎配置:

  • 處理css、less、前端資源等文件
  • 編譯es6+語法及api
  • 處理html文件

已經掌握了相關的配置方法,並且我們還總結了一份基礎的配置,不太清楚的同學可以看一下先,這個基礎配置還是蠻重要的。

ok,那我們先用 learn-08 這個案例來體驗一下如何進行本地開發調試。為了儘量貼近我們現實中開發的項目,案例裏會:

  • html裏面引用圖片
  • 使用less裏面引用圖片
  • js裏使用es6+,動態加載圖片
  • 使用devServer配置項
為了閲讀方便,具體的源碼就不放文章了,大家可以去 github 看

然後進行以下步驟:

  1. 為了語義化,我們把webpack配置文件命名為webpack.dev.js
  2. 使用命令行啓動webpack——npm start

    "scripts": {
     "start": "webpack server --config ./webpack.dev.js"
    }

運行結果:

devserve.png

我們會發現:

  • 文件編譯處理完成後,不會輸出任何文件
  • 此時開啓了一個內部服務器(http://192.168.0.196:8080/)。如果我們的手機與電腦用的同個網絡,用手機訪問這個鏈接,就能看到效果了。這對調試H5開發是十分高效的(這主要歸功於deveServer配置項,後文會有講解)
  • 我們修改代碼後,頁面會實時更新

以上幾乎是我們想要的高效開發效果。

分析

初步體驗完後,我們根據上文總結的開發環境配置思想,來看看對開發環境該如何配置:

  • 解析樣式不需要分離出css文件,我們直接將解析出來的樣式插入到<header />中:

    module: {
      rules: [
          {
              test: /.(css|less)$/, 
              use: [
                  'style-loader',
                  'css-loader',
                  'less-loader'
              ]
          },
      ]
    },
  • jsimgmediafont等前端資源文件,不需要分包:

    output: {
      path: path.resolve(__dirname, './dist'),
      filename: '[name]-[chunkhash:5].js',
    },
    module: {
      rules: [
          {
              test: /\.(png|svg|jpg|jpeg|gif)$/i,
              type: 'asset',
              parser: {
                  dataUrlCondition: {
                      maxSize: 1024 * 3 // When the image size is < 3kb 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'
              }
          }
      ]
    },
  • 開啓source map,方便定位問題;並且不壓縮代碼:

    {
      mode: 'development',
      devtool: 'inline-cheap-module-source-map'
    }
  • 使用webpack提供的devServer進行本地開發:

    devServer: {
      static: {
          directory: path.join(__dirname, 'static'),
      },
    },
  • 沒有安裝其他多餘的plugin,因為要解析html,所以只安裝瞭解析htmlplugin

    plugins: [
      new HtmlWebpackPlugin({
          filename: path.resolve(__dirname, './dist/[name].html'),
          template: path.resolve(__dirname, './src/index.html'),
          title: 'webpack.dev.config',
      })
    ],

    我們對比一下基礎配置,會發現開發環境配置跟基礎配置幾乎沒差別,只是多使用了devServer配置項,來開啓本地服務器調試:

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

module.exports = {
+   mode: 'development',
+   devtool: 'inline-cheap-module-source-map',
    entry: {
        index: './src/index.js'
    },
    output: {
        path: path.resolve(__dirname, './dist'),
        filename: '[name]-[chunkhash:5].js',
    },
    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 * 3 // When the image size is < 3kb it will be converted to base64
                    }
                },
                generator: {
                    filename: '[name]-[contenthash:5][ext][query]' // 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.dev.config',
        })
    ],
+   devServer: {
+       static: {
+           directory: path.join(__dirname, 'static'),
+       },
+   }
}

devServer

還記得我們之前的案例,是怎麼運行我們的代碼的嗎?我們都是打包完以後,用自帶的編輯器(vscode)運行查看結果的。要是我們平時開發是這麼低效的話,那估計項目不用上線了。

因此webpack提供了一個十分人性化的配置項——devServer

想使用這個配置項,我們需要先npm i webpack-dev-server -D安裝webpack-dev-server依賴

從這麼語義化的名字就知道,它肯定是開發環境下,可以提供某種服務的配置。

這個服務就是,這將會開啓一個本地服務,將我們配置的webpack,實時編譯,保存在內存中,這樣可以方便調試我們的代碼,這很好的滿足了我們本地開發需要高效的目的。

因此這個配置項,只用於我們開發環境配置

devServer.static

文檔解釋:告訴服務器從哪裏提供內容。只有在你希望提供靜態文件時才需要這樣做

錯誤理解

devServe配置項,其實文檔已經寫的挺詳細了,這裏講一個可能容易混淆的配置項——devServe.static

很多人使用webpack,都是複製粘貼,所以經常會看到下面這種配置:

output: {
    path: path.resolve(__dirname, './dist'),
}
devServer: {
    static: {
      directory: path.join(__dirname, 'dist'),
    }
}

因為我們設置的打包後輸出的文件夾一般都是distdevServe.static配置項指定要提供的靜態文件目錄也是dist。所以,我們自然而然會以為,此時webpack開啓的本地服務器訪問的內容就是dist文件夾裏面的內容。

因此,我們會得出錯誤的結論:devServe.static的作用就是,設置webpack開啓的本地服務器時,訪問的目錄。

但是,我們可以看看上文的 dev.config.js,我們設置打包後輸出的文件夾名稱是distdevServe.static設置的目錄是static。如果按照我們上文錯誤的理解,由於兩個文件夾設置不同,此時我們服務器應該是404或者空白頁面才對,但是我們依舊可以跑起我們的服務。

這説明devServe.static的作用,並不是設置webpack開啓的本地服務器時,訪問打包輸出文件夾的目錄。

正確理解

分析

我們繼續看 learn-08 這個案例(static文件夾裏面存放了logo.png圖片)。

我們之前想在js裏面引用相關圖片,我們一般會這麼做:

// index.js
const img = new Image();
img.src = require('Your image path');

我們一般是將圖片根據相對路徑require進來,此時圖片相當於是一個模塊(Module),因此這樣圖片會經過webpack編譯打包(添加hash或者轉成base64),最後寫入到我們設置的最終目錄(output.path)。

但是當我們設置了:

devServer: {
    static: {
      directory: path.join(__dirname, 'static'),
    }
}

開啓本地服務器後,會有這一句提示:

Content not from webpack is served from 'your path/static' directory

首先,這説明我們設置的static這個目錄,是不會經過webpack處理打包的,所以在這個文件夾裏面的資源,是不會被webpack解析編譯的,因此它也不會加上hash或轉成base64

我們再來看看 learn-08 的index.js是如何使用static裏的資源的:

// index.js
loadImage('./logo.png').then(img => {
    console.log('I am from index.js');
    img.width = 120;
    document.querySelector('#js_content .img_content').append(img);
});

我們會看到,我們是直接使用./的方式引入圖片,説明webpack開啓的本地服務器,會將我們設置的static的目錄內容映射到根目錄下。

用過vue-cli的同學應該能很好體會到,這其實就是vue-cli裏面public文件夾的功能

我們可以用以下方式訪問設置的devServer.static.directory文件夾裏的內容:

  • 一般情況下devServer.static.directory會被映射到根目錄,所以我們用http://[devServer.host]:[devServer.port]/[devServer.static.directory]訪問
  • 如果想改變訪問的路徑,可以增加devServer.static.publicPath配置。此時可以用http://[devServer.host]:[devServer.port]/[devServer.static.publicPath]/[devServer.static.directory]訪問

總結

經過上面的分析講解,我們可以得出對devServer.static正確的理解應該是:

  • 它是設置一個存放,不經過webpack編譯的靜態資源目錄(我們可以例如圖片,第三方資源等),所以它不會被加上hash或者被轉成base64;它是一個目錄
  • 開啓webpack本地服務器時,它一般會被映射到我們的項目的根目錄下(可以通過devServe.static.publicPath修改訪問目錄)
  • 由於它不經過webpack編譯打包,所以,我們最後一般會用copy-webpack-plugin,將devServer.static.directory複製到output.path根目錄下
  • 它的功能就很像是vue-cli裏面的public文件夾,我們開發的時候,可以通過./或者../訪問到那個資源(具體看目錄關係)

核心

好,通過上面對開發環境配置跟devServer的講解,我們可以知道:

  • 開發環境配置一切從簡,所以imgjs等資源會直接映射在根目錄下(css被插入到<head />裏了)
  • 開發環境webpack開啓本地服務器後,也會將devServer.static.directory映射在根目錄下

所以運行開發環境配置後,我們的結構目錄大致如下:

dist
├── ecj-cli-b6fa8.png
├── index-c466b.js
├── index.html
└── logo.png

配置因人而異,最重要的是,我們配置完開發環境,生產環境後,對編譯打包輸出內容,目錄,腦海中有一個很好地結構認識,這是非常重要的

這個目錄結構也請大家牢記,後面的文章會用到

我們可以通過以下方法查看開發環境的結構目錄:

  • devServer.devMiddleware.writeToDisk: true
  • http://[devServer.host]:[devServer.port]/webpack-dev-server
  • 谷歌瀏覽器F12 -> Sources

最後

  • 本篇文章學習了開發環境如何配置,下篇文章將會講解配置生產環境前一些準備,讓後續我們更好的學習生產環境配置
  • 感興趣的同學,可以關注一下這個 👉 專欄
  • 文章涉及到的案例已經上傳到 github,真的歡迎starfork學習

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

user avatar lanlanjintianhenhappy 頭像 peter-wilson 頭像 tigerandflower 頭像 sunhengzhe 頭像 tingzhong666 頭像 liyl1993 頭像 joytime 頭像 codeoop 頭像 cipchk 頭像 beilee 頭像 william_wang_5f4c69a02c77b 頭像 mofaboshi 頭像
40 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.