[譯] Webpack 4 的故事以及如何用正確的方式去最終配置它【更新版】

果斷就會白給發表於2019-02-11

特別提醒:沒有正確的方式。#justwebpackthings

[譯] Webpack 4 的故事以及如何用正確的方式去最終配置它【更新版】

原圖:www.instagram.com/p/BhPo4pqBy…

這篇博文最後一次更新在 2018 年 12 月 28 日,適用於 Webpack v4.28.0 版本。


2018 年 06 月 23 日更新:我收到了許多關於如何使其工作和如何改進的評論。感謝你們的反饋!我已經盡力的去考慮每一條評論!某種程度上,我也決定在 Github 上建立一個 Webpack 模板專案,你可以使用 Git 來拉取最新的 Webpack 配置檔案。感謝你們的支援!連結:github.com/marharyta/w…


更新:本文是關於 Webpack 和 React.js 搭建系列文章的一部分。在這裡閱讀有關配置 React 開發環境的部分:


感謝各位對我的教程提出大量的反饋。我要很自豪的說,Webpack 前幾天在 Twitter 上推薦了這篇教程,並且它已經得到了一些貢獻者的認可!

[譯] Webpack 4 的故事以及如何用正確的方式去最終配置它【更新版】

[譯] Webpack 4 的故事以及如何用正確的方式去最終配置它【更新版】

謝謝!


網上有上百萬的教程,所以你可能已經看到了上千種配置 Webpack 檔案的方式,而且他們都是可執行的例子。為什麼會這樣?Webpack 本身發展的非常快,很多載入器和外掛都必須跟上。這是這些配置檔案如此不同的一個主要原因:使用同一工具的不同版本組合,可能可以執行,也可能會失敗。

讓我只說一件事情,這是我真誠的意見:許多人已經在抱怨 Webpack 和它的笨重,這在很多方面都是正確的。我不得不說,根據我使用 Gulp 和 Grunt 的經驗,你也會遇到相同型別的錯誤,這意味著當你使用 npm 模組時,某些版本不可避免的會不相容。

迄今為止,Webpack 4 是一個非常流行的模組打包器,它剛剛經歷了一次大規模的更新,提供了許多新功能,如零配置、合理的預設值、效能提升、開箱即用的優化工具。

如果你剛接觸 Webpack,閱讀文件是一個很好的開始。Webpack 有一個非常好的文件,其中解釋了許多部分,因此我會簡單的介紹它們。

零配置:Webpack 4 無需配置檔案,這是 Webpack 4 的新特性。Webpack 是逐步增長的,因此沒必要一開始就做一個可怕的配置。

效能提升:Webpack 4 是迄今為止最快的一版。

合理的預設值:Webpack 4 的主要概念是「 入口、輸出、載入器、外掛 」。我不會詳細介紹這些。載入器和外掛之間的區別非常模糊,這完全取決於庫作者如何去實現它。

核心概念

入口

這應該是你的 .js 檔案。現在您可能會看到一些配置,其中人們在那裡包含 .scss.css 檔案。這是一個重大的 hack,並可能會導致許多意外錯誤。有時你也會看到一個帶有幾個 .js 檔案的條目。雖然有些解決方案允許你這樣做,但我會說它通常會增加更多的複雜性,只有當你真正知道你為什麼這樣做時才能這樣做。

輸出

這是你的 build/dist/wateveryounameit/ 資料夾,其中將存放最終生成的 js 檔案。這是你的最終結果,由模組組成。

載入器

它們主要編譯或轉換你的程式碼,像 postcss-loader 將通過不同的外掛。稍後你將能瞭解它。

外掛

外掛在將程式碼輸出到檔案中的過程中起著至關重要的作用。

快速入門

建立一個新的目錄,並切換到該目錄下:

mkdir webpack-4-tutorial
cd webpack-4-tutorial
複製程式碼

初始化 package.json 檔案:

npm init
複製程式碼

或者

yarn init
複製程式碼

我們需要下載模組 Webpack v4webpack-cli。在你的終端(控制檯)執行它:

npm install webpack webpack-cli --save-dev
複製程式碼

yarn add webpack webpack-cli --dev
複製程式碼

確保你已經安裝了版本 4,如果沒有安裝,你可以在 package.json 中顯式指定它。現在開啟 package.json 然後新增構建指令碼:

"scripts": {
  "dev": "webpack"
}
複製程式碼

嘗試執行它,你很可能會看到一條警告:

WARNING in configuration

The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.

You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/
複製程式碼

Webpack 4 模式

你需要編輯指令碼來包含模式標記:

"scripts": {
  "dev": "webpack --mode development"
}

ERROR in Entry module not found: Error: Can't resolve './src' in '~/webpack-4-quickstart'
複製程式碼

這意味著 Webpack 在尋找 .src/ 資料夾下的 index.js 檔案。這是 Webpack 4 的預設行為,也是它實現零配置的原因。

讓我們去建立帶有 .js 檔案的目錄,如 ./src/index.js,並在那裡放一些程式碼。

console.log("hello, world");
複製程式碼

現在執行 dev 指令碼:

npm run dev

或者

yarn dev
複製程式碼

如果此時你遇到錯誤,請閱讀本小節下面的更新。否則,現在你應該會有一個 ./dist/main.js 目錄。這很好,因為我們知道我們的程式碼被編譯過了。但剛剛發生了什麼?

預設情況下, Webpack 是零配置的,這意味著在你開始使用它時,你無需去配置 webpack.config.js 。因此,它必須去假定一些預設行為,例如它總是會在預設情況下查詢 ./src 資料夾,在其中查詢 index.js 並輸出到 ./dist/main.js 。main.js 是帶有依賴項的編譯後檔案。


2018.12.23 更新

如果你遇到了這個問題:

ERROR in ./node_modules/fsevents/node_modules/node-pre-gyp/lib/publish.js

Module not found: Error: Can't resolve 'aws-sdk' in '/Users/mobr/Documents/workshop/test-webpack-4-setup/node_modules/fsevents/node_modules/node-pre-gyp/lib'
複製程式碼

更多細節描述請參閱這裡,那你最有可能使用一個更成熟的 Webpack v4 版本。

不幸的是,如果不建立 webpack.config.js 檔案,你就無法解決它(我將在本文中後續部分向您展示如何執行此操作)。只需按照我的教程,直到 “轉義你的 .js 程式碼” 部分並複製貼上那裡的配置檔案。你需要下載 webpack-node-externals

npm install webpack-node-externals --save-dev

或者是

yarn add webpack-node-externals --dev
複製程式碼

並且在那裡匯入以下程式碼:

const nodeExternals = require('webpack-node-externals');
...
module.exports = {
    ...
    target: 'node',
    externals: [nodeExternals()],
    ...
};
複製程式碼

從這個模組


在 webpack 中,擁有兩個配置檔案是常見做法,尤其是在大型專案中。通常你會有一個用於開發的檔案和一個用於生產的檔案。在 webpack 4 中,你有 開發生產 兩種模式。這消除了對兩個檔案的需求(對於中型專案)。

"scripts": {
  "dev": "webpack --mode development",
  "build": "webpack --mode production"
}
複製程式碼

如果你密切關注,你應當已經檢查了你的 main.js 檔案,並瞭解到它沒有被縮小。

我將在此示例中使用 dev 指令碼,因為它提供了大量開箱即用的優化,但從現在開始,你可以隨意使用它們中的任何一個。build 和 dev 指令碼之間的核心區別在於它們如何輸出檔案。build 指令碼為生產程式碼建立。dev 指令碼為開發而建立,這意味著它支援熱模組替換、開發伺服器以及許多可以幫助你進行開發工作的東西。

你可以在 npm 指令碼中很輕易地覆蓋預設配置,只需要使用標記:

"scripts": {
  "dev": "webpack --mode development ./src/index.js --output ./dist/main.js",
  "build": "webpack --mode production ./src/index.js --output ./dist/main.js"
}
複製程式碼

這將覆蓋預設選項,而無需配置任何內容。

作為一個練習,你也可以試試這些標記:

  • — watch 標記來啟用監聽模式。它將會監控檔案變化,並且在每次檔案更新時重新編譯。
"scripts": {
  "dev": "webpack --mode development ./src/index.js --output ./dist/main.js --watch",
  "build": "webpack --mode production ./src/index.js --output ./dist/main.js --watch"
}
複製程式碼
  • — entry 標記。與輸出標記完全一樣,但重寫了輸入路徑。

轉譯你的 .js 程式碼

現代 JS 程式碼大多是用 ES6 編寫的,然而並不是所有瀏覽器都支援 ES6。 因此,您需要將其 transpile — 一個將您的 ES6 程式碼轉換為 ES5 的奇特詞彙。你可以使用 babel(現在最流行的工具)來處理。 當然,轉譯不僅針對 ES6 程式碼,而且針對許多 JS 實現,如 TypeScript 和 React 等。

npm install babel-core babel-loader babel-preset-env --save-dev

或者

yarn add babel-core babel-loader babel-preset-env --dev
複製程式碼

這是您需要為 babel 建立配置檔案的部分。

nano .babelrc
複製程式碼

把下面的內容貼上過去:

{
"presets": [
  "env"
  ]
}
複製程式碼

我們有兩個選擇來配置 babel-loader :

  • 使用配置檔案 webpack.config.js
  • npm 指令碼使用 --module-bind 引數

從技術上講,你可以使用 Webpack 引入的新標誌來作很多事情,但是為了簡單起見,我更喜歡使用 webpack.config.js

配置檔案

雖然 webpack 將自己宣傳為零配置平臺,但它主要適用於一般預設設定,如入口和輸出。

現在我們將使用以下內容建立 webpack.config.js

// webpack v4

const path = require('path');

// update from 23.12.2018
const nodeExternals = require('webpack-node-externals');

module.exports = {
  entry: { main: './src/index.js' },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'
  },
  target: 'node', // update from 23.12.2018
  externals: [nodeExternals()], // update from 23.12.2018
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      }
    ]
  }
};
複製程式碼

我們也會從 npm 指令碼中移除標記。

"scripts": {
  "build": "webpack --mode production",
  "dev": "webpack --mode development"
},
複製程式碼

現在當我們執行 npm run build 或者 yarn build 時,它應當輸出一個被很好地壓縮的 .js 檔案到 ./dist/main.js 。如果沒有的話,嘗試重新安裝 babel-loader


2018.12.23 更新

如果你遇到 module '@babel/core' conflict,這意味著你的某些預載入的 babel 依賴項不相容。就我而言,我遇到了。

Module build failed: Error: Cannot find module '@babel/core'

babel-loader@8 requires Babel 7.x (the package '@babel/core'). If you'd like to use Babel 6.x ('babel-core'), you should install 'babel-loader@7'.
複製程式碼

我解決了這個問題,通過執行

yarn add @babel/core --dev
複製程式碼

最常見的 webpack 模式是使用它來編譯 React.js 應用程式。雖然確有其事,但我們不會在本教程中專注 React 部分,因為我希望它與框架無關。相反,我將向您展示如何繼續並建立 .html 和 .css 配置。

HTML 和 CSS 的匯入

讓我們首先在 ./dist 資料夾下建立一個小小的 index.html 檔案:

<html>
  <head>
    <link rel="stylesheet" href="style.css">
  </head>
  <body>
    <div>Hello, world!</div>
    <script src="main.js"></script>
  </body>
</html>
複製程式碼

如您所見,我們在這裡匯入 style.css。讓我們配置它!正如我們所說,我們只有一個 Webpack 入口點。那麼我們將 css 放在哪裡?在 ./src 資料夾中建立一個 style.css

div {
  color: red;
}
複製程式碼

別忘了在你的 .js 檔案裡包含它:

import "./style.css";
console.log("hello, world");
複製程式碼

特別提醒:在某些文章中,你會了解到 ExtractTextPlugin 不適用於 webpack 4。它在我的 webpack v4.2 上可以執行,但在我使用 webpack v4.20 時停止執行。它證明了在搭建時我的模組設定很模糊,如果它完全不適合你,你可以切換到 MiniCssExtractPlugin。我將在本文後面部分向您展示如何配置。

為了向後相容,我仍然會展示 ExtractTextPlugin 示例,但是你完全可以刪去它並替換成正在使用 MiniCssExtractPlugin 的部分。

在 Webpack 為您的 css 檔案建立一條新的規則:

// webpack v4
const path = require('path');

// update from 23.12.2018
const nodeExternals = require('webpack-node-externals');

const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
  entry: { main: './src/index.js' },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'
  },
  target: 'node', // update from 23.12.2018
  externals: [nodeExternals()], // update from 23.12.2018  
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /\.css$/,
        use: ExtractTextPlugin.extract(
          {
            fallback: 'style-loader',
            use: ['css-loader']
          })
      }
    ]
  }
};
複製程式碼

在終端(控制檯)執行:

npm install extract-text-webpack-plugin --save-dev
npm install style-loader css-loader --save-dev
複製程式碼

或者

yarn add extract-text-webpack-plugin style-loader css-loader --dev
複製程式碼

我們需要使用文字提取外掛來編譯 .css。如您所見,我們還為 .css 新增了一條新規則。從版本 4 開始,Webpack 4 和這個外掛有一些問題,因此你可能會遇到這個錯誤:

為了修復這個問題,你可以執行

npm install -D extract-text-webpack-plugin@next
複製程式碼

yarn add --dev extract-text-webpack-plugin@next
複製程式碼

專業提示:Google 一下你獲得的錯誤資訊,嘗試在 Github 問題列表查詢類似的問題,或者在 StackOverflow 網站恰當的提一個問題。

在那之後,你的 CSS 程式碼應當會編譯到 ./dist/style.css

此時在 package.json 中,開發依賴清單看起來像這樣:

"devDependencies": {
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.4",
    "babel-preset-env": "^1.6.1",
    "css-loader": "^0.28.11",
    "extract-text-webpack-plugin": "^4.0.0-beta.0",
    "style-loader": "^0.20.3",
    "webpack": "^4.4.1",
    "webpack-cli": "^2.0.12"
 }
複製程式碼

版本可能不同,但這是正常的!

請注意,另一個組合可能無法正常工作,即使像將 webpack-cli v2.0.12 更新為 2.0.13 這樣的改動,也可能會使其無法正常執行。#justwebpackthings

所以現在它應該將 style.css 輸出到 ./dist 資料夾中。

[譯] Webpack 4 的故事以及如何用正確的方式去最終配置它【更新版】

Mini-CSS 外掛

Mini CSS 外掛旨在取代 extract-text 外掛,它為您提供更好的未來相容性。我用 mini-css-extract-plugin 重新構建了我的 Webpack 檔案以編譯 style.css,並且它對我很有用。

npm install mini-css-extract-plugin --save-dev

或者是

yarn add mini-css-extract-plugin --dev
複製程式碼
// webpack v4
const path = require('path');

// update from 23.12.2018
const nodeExternals = require('webpack-node-externals');

// const ExtractTextPlugin = require('extract-text-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  entry: { main: './src/index.js' },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[chunkhash].js'
  },
  target: 'node', // update from 23.12.2018
  externals: [nodeExternals()], // update from 23.12.2018
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /\.css$/,
        use:  [  'style-loader', MiniCssExtractPlugin.loader, 'css-loader']
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'style.css',
    })
  ]
};
複製程式碼

正如尼古拉·沃爾科夫所指出的那樣,可能不再需要 style-loader 了,因為用 MiniCssExtractPlugin.loader 也可以做到同樣的事情。雖然這可能屬實,但我仍然建議留下它作為後備。

Webpack 匹配規則如何工作?

一個關於匹配規則通常如何工作的快速描述:

test: /\.YOUR_FILE_EXTENSION$/,
exclude: /SOMETHING THAT IS THAT EXTENSION BUT SHOULD NOT BE PROCESSED/,
use: {
  loader: "loader for your file extension  or a group of loaders"
}
複製程式碼

我們需要去使用 MiniCssExtractPlugin,因為 Webpack 預設只能解析 .js 格式。MiniCssExtractPlugin 獲取你的 .css ,然後提取它到一個在 ./dist 目錄下的獨立 .css 檔案。

配置對 SCSS 的支援

使用 SASS 和 PostCSS 開發網站是一個很平常的事情,它們非常有用。因此我們首先要包含對 SASS 的支援。讓我們重新命名 ./src/style.css ,然後建立另外的資料夾來存放 .scss 檔案。現在我們需要新增對 .scss 格式的支援。

npm install node-sass sass-loader --save-dev
複製程式碼

或者是

yarn add node-sass sass-loader --dev
複製程式碼

在你的 .js 檔案裡用 ./scss/main.scss 替換 style.css ,更改測試以支援 .scss

// webpack v4
const path = require('path');
// update 23.12.2018
const nodeExternals = require('webpack-node-externals');

const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  entry: { main: './src/index.js' },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'
  },
  target: "node", // update 23.12.2018
  externals: [nodeExternals()], // update 23.12.2018
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /\.scss$/,
        use: [
          "style-loader",
          MiniCssExtractPlugin.loader,
          "css-loader",
          "sass-loader"
        ]
      }
    ]
  } ...
複製程式碼

HTML 模板

現在讓我們建立 .html 檔案模板。新增 index.html./src ,保持完全相同的結構。

<html>
  <head>
    <link rel="stylesheet" href="style.css">
  </head>
  <body>
    <div>Hello, world!</div>
    <script src="main.js"></script>
  </body>
</html>
複製程式碼

為了作為一個模板去使用這個檔案,我們將需要對它使用 html 外掛。

npm install html-webpack-plugin --save-dev
複製程式碼

或者

yarn add html-webpack-plugin --dev
複製程式碼

把它新增到你的 Webpack 檔案:

// webpack v4
const path = require('path');
// update 23.12.2018
const nodeExternals = require('webpack-node-externals');

const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: { main: './src/index.js' },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'
  },
  target: "node", // update 23.12.2018
  externals: [nodeExternals()], // update 23.12.2018

  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /\.scss$/,
        use: [
          "style-loader",
          MiniCssExtractPlugin.loader,
          "css-loader",
          "sass-loader"
        ]
      }
    ]
  },
  plugins: [ 
    new MiniCssExtractPlugin({
      filename: "style.css"
    }),
    new HtmlWebpackPlugin({
      inject: false,
      hash: true,
      template: './src/index.html',
      filename: 'index.html'
    })
  ]
};
複製程式碼

現在,./src/index.html 中的檔案是最終 index.html 檔案的模板。要檢查一切是否正常,請刪除 ./dist 資料夾中的每個檔案和資料夾本身。

rm -rf ./dist
npm run dev
複製程式碼

或者是

yarn dev
複製程式碼

你會看到 ./dist 資料夾是自行建立的,包含三個檔案:index.html,style.css,main.js。

快取和雜湊

開發中最常見的問題之一是實現快取。瞭解它的工作原理非常重要,因為您希望使用者始終擁有最新版本的程式碼。

由於這篇博文主要是關於 webpack 配置的,因此我們不會專注於快取如何工作。我只想說解決快取問題最常用的方法之一是向資原始檔新增 雜湊值 ,例如 style.cssscript.js你可以在這裡閱讀相關內容。 需要雜湊來指導我們的瀏覽器只請求更改的檔案。

Webpack 4 具有通過 chunkhash 實現的預構建功能。它可以通過以下方式完成:

// webpack v4
const path = require('path');

// update 23.12.2018
const nodeExternals = require("webpack-node-externals");

const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: { main: './src/index.js' },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[chunkhash].js'
  },
  target: "node",
  externals: [nodeExternals()],
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /\.scss$/,
        use: [
            "style-loader",
            MiniCssExtractPlugin.loader,
            "css-loader",
            "sass-loader"
          ]
       }
    ]
  },
  plugins: [ 
    new MiniCssExtractPlugin({
     filename: "style.[contenthash].css"
    }),

    new HtmlWebpackPlugin({
      inject: false,
      hash: true,
      template: './src/index.html',
      filename: 'index.html'
    })
  ]
};
複製程式碼

在您的 ./src/index.html 檔案中新增

<html>
  <head>
    <link rel="stylesheet" href="<%=htmlWebpackPlugin.files.chunks.main.css %>">
  </head>
  <body>
    <div>Hello, world!</div>
    <script src="<%= htmlWebpackPlugin.files.chunks.main.entry %>"></script>
  </body>
</html>
複製程式碼

這樣的語法將會為您的 HTML 模版注入帶有雜湊值的檔案。這是下面問題被解決後實現的新功能:

我們將使用在 HTML 模板中描述的 htmlWebpackPlugin.files.chunks.main。檢視我們在 ./dist 下的檔案 index.html

[譯] Webpack 4 的故事以及如何用正確的方式去最終配置它【更新版】

[譯] Webpack 4 的故事以及如何用正確的方式去最終配置它【更新版】

如果我們不改變我們的 .js.css 檔案中任何東西,執行

npm run dev
複製程式碼

不論您執行多少次,執行前後兩個檔案中的雜湊值均會彼此相同。

CSS Hash 問題以及解決方案


2018.12.28 更新

如果你使用針對 CSS 的 webpack 4 版本的 ExtractTextPlugin,可能會存在這個問題。如果你使用 MiniCssExtractPlugin,這個問題將不會發生,但閱讀它是有益的!


雖然我們在這裡做了一些工作,但它還不完美。如果我們更改 .scss 檔案中的某些程式碼怎麼辦?繼續下去,在那裡更改一些 scss 並再次執行 dev 指令碼。現在不生成新的檔案雜湊。如果我們將一個新的 console.log 新增到我們的 .js 檔案中,如下所示:

import "./style.css";
console.log("hello, world");
console.log("Hello, world 2");
複製程式碼

如果再次執行 dev 指令碼,您將看到兩個檔案中的雜湊值均已更新。

這個問題是已知的,甚至在 StackOverflow 上都有相關問題:

現在如何去修復那個問題?

在嘗試了很多聲稱可以解決這個問題的外掛之後,我終於找到了兩種型別的解決方案。

解決方案 1

可能還存在一些衝突,所以現在我們試試 mini-css-extract plugin

解決方案 2

.css 提取外掛上用 [hash] 替換 [chunkhash]。這是上述問題的解決方案之一。這似乎與 Webpack 4.3 產生了衝突,後者引入了Webpack 自己[contenthash] 變數。結合使用此外掛:webpack-md5-hash (請參閱下文)。

現在讓我們測試一下 .js 檔案:兩個檔案的雜湊值都改變了。

JS Hash 的問題以及解決方案

如果您已經在使用 MiniCssExtractPlugin,則會出現相反的問題:每次更改 SCSS 中的某些內容時,.js 檔案和 .css 輸出檔案雜湊值都會更改。

解決方案:

使用這個外掛:webpack-md5-hash。如果對 main.scss 檔案進行更改並執行 dev 指令碼,則只應使用新雜湊生成新的 style.css ,而不是兩者。

// webpack v4
const path = require('path');
// update 23.12.2018
const nodeExternals = require("webpack-node-externals");

const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const WebpackMd5Hash = require("webpack-md5-hash");

module.exports = {
  entry: { main: './src/index.js' },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[chunkhash].js'
  },
  target: "node", // update 23.12.2018
  externals: [nodeExternals()], // update 23.12.2018
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /\.scss$/,
        use: ExtractTextPlugin.extract(
          {
            fallback: 'style-loader',
            use: ['css-loader', 'sass-loader']
          })
      }
    ]
  },
  plugins: [ 
    new MiniCssExtractPlugin({
      filename: "style.[contenthash].css"
    }),
    new HtmlWebpackPlugin({
      inject: false,
      hash: true,
      template: "./src/index.html",
      filename: "index.html"
    }),
    new WebpackMd5Hash()
  ]
};
複製程式碼

現在,當我編輯 main.scss 時,會生成 style.css 的新雜湊。當我編輯 css 時只有 css 的雜湊更改,當我編輯 ./src/script.js 時,只有script.js 的雜湊更改!

整合 PostCSS

為了優雅的輸出 .css ,我們可以在頂部新增 PostCSS。

PostCSS 為您提供 autoprefixer、cssnano 和其他漂亮和方便的東西。 我會每天展示我正在使用的內容。我們需要 postcss-loader。我們還將安裝 autoprefixer,因為我們稍後會需要它。

更新於:2019.2.11

校對者注: 最新版的 postcss-loader(v3.0.0 版本以上)是自帶支援 autoprefixer 的,所以我們不需要安裝 autoprefixer。

具體請參閱:postcss-preset-env 包含 autoprefixer,因此如果您已經使用了預設配置,則無需單獨新增 autoprefixer。

npm install postcss-loader --save-dev
npm i -D autoprefixer

或者

yarn add postcss-loader autoprefixer --dev
複製程式碼

特別提醒:您不必為了使用 PostCSS 而使用 Webpack,Webpack 有一個相當不錯的 post-css-cli 外掛,允許你在 npm 指令碼中使用。

在需要相關外掛的地方建立 postcss.config.js ,貼上

module.exports = {
    plugins: [
      require('autoprefixer')
    ]
}
複製程式碼

我們的 webpack.config.js 現在看起來應該是這樣:

// webpack v4
const path = require('path');
// update 23.12.2018
const nodeExternals = require("webpack-node-externals");

const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const WebpackMd5Hash = require("webpack-md5-hash");

module.exports = {
  entry: { main: './src/index.js' },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[chunkhash].js'
  },
  target: "node",
  externals: [nodeExternals()],
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /\.scss$/,
        use:  [  'style-loader', MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader']
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'style.[contenthash].css',
    }),
    new HtmlWebpackPlugin({
      inject: false,
      hash: true,
      template: './src/index.html',
      filename: 'index.html'
    }),
    new WebpackMd5Hash()
  ]
};
複製程式碼

請注意我們用於 .scss 的外掛順序

use:  ['style-loader', MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader']
複製程式碼

載入器將從後向前應用外掛。

您可以通過向 .scss 檔案新增更多程式碼並檢查輸出來測試 autoprefixer。還有一種方法可以通過在 .browserslistrc 檔案中指定要支援的瀏覽器來修復輸出。

我將引導您到 www.postcss.parts/ 探索可用於 PostCSS 的外掛,例如:

我將使用 cssnano 來縮小我的輸出檔案,使用 css-mqpacker 來編排我的媒體查詢。我也收到了一些訊息:

[譯] Webpack 4 的故事以及如何用正確的方式去最終配置它【更新版】

如果你願意,可以試試 cleancss

版本控制

為了保證你的依賴在對的位置,我推薦使用 yarn 來替代 npm 安裝模組。長話短說,yarn 會鎖定每一個包,並且當你重灌模組時,你將不會遇到許多意想不到的不相容情況。

保持配置乾淨整潔

我們可以嘗試匯入 clean-webpack-plugin,在重新生成檔案之前清理 ./dist 資料夾。

// webpack v4
const path = require('path');
// update 23.12.2018
const nodeExternals = require("webpack-node-externals");

const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const WebpackMd5Hash = require("webpack-md5-hash");
const CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = {
  entry: { main: './src/index.js' },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[chunkhash].js'
  },
  target: "node",
  externals: [nodeExternals()],

  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /\.scss$/,
        use:  [  'style-loader', 
                 MiniCssExtractPlugin.loader, 
                 'css-loader', 
                 'postcss-loader', 
                 'sass-loader']
      }
    ]
  },
  plugins: [ 
    new CleanWebpackPlugin('dist', {} ),
    new MiniCssExtractPlugin({
      filename: 'style.[contenthash].css',
    }),
    new HtmlWebpackPlugin({
      inject: false,
      hash: true,
      template: './src/index.html',
      filename: 'index.html'
    }),
    new WebpackMd5Hash()
  ]
};
複製程式碼

現在我們的配置乾淨整潔,我們可以保持下去!

在這裡,我為您提供了我的配置檔案以及逐步配置它的方法。注意:由於許多 npm 依賴項可能會在您閱讀此內容時發生更改,因此相同的配置可能對您無效!我懇請您將錯誤留在下面的評論中,以便我以後編輯。今天是 2018.04.05。


本文的最新版本是 2018.12.28

帶有最新版本外掛的 package.json 具有以下結構:

{
 "name": "webpack-test",
 "version": "1.0.0",
 "description": "",
 "main": "index.js",
 "scripts": {
 "build": "webpack --mode production",
 "dev": "webpack --mode development"
 },
 "author": "",
 "license": "ISC",
 "devDependencies": {
   "@babel/core": "^7.2.2",
   "autoprefixer": "^9.4.3",
   "babel-core": "^6.26.3",
   "babel-loader": "^8.0.4",
   "babel-preset-env": "^1.7.0",
   "css-loader": "^2.0.2",
   "html-webpack-plugin": "^3.2.0",
   "mini-css-extract-plugin": "^0.5.0",
   "node-sass": "^4.11.0",
   "postcss-loader": "^3.0.0",
   "sass-loader": "^7.1.0",
   "style-loader": "^0.23.1",
   "webpack": "4.28",
   "webpack-cli": "^3.1.2"
},

 "dependencies": {
   "clean-webpack-plugin": "^1.0.0",
   "webpack-md5-hash": "^0.0.6",
   "webpack-node-externals": "^1.7.2"
 }
}
複製程式碼

在這裡閱讀下一篇關於使用 React 配置開發環境的部分:如何利用 Webpack 4 提升你的 React.js 開發效率

如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章