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

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

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

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


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


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


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

謝謝!react


網上有上百萬的教程,因此你可能已經看到了上千種配置 Webpack 文件的方式,並且他們都是可運行的例子。爲何會這樣?Webpack 自己發展的很是快,不少加載器和插件都必須跟上。這是這些配置文件如此不一樣的一個主要緣由:使用同一工具的不一樣版本組合,可能能夠運行,也可能會失敗。android

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

迄今爲止,Webpack 4 是一個很是流行的模塊打包器,它剛剛經歷了一次大規模的更新,提供了許多新功能,如零配置、合理的默認值、性能提高、開箱即用的優化工具。ios

若是你剛接觸 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 文件夾中。

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

若是咱們不改變咱們的 .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 來編排個人媒體查詢。我也收到了一些消息:

若是你願意,能夠試試 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前端後端區塊鏈產品設計人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章
相關標籤/搜索