Webpack 4 的故事以及如何用正确的方式去最终配置它【更新版】

特别提醒:没有正确的方式。#justwebpackthings

原图: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 开发环境的部分:medium.com/@riittagirl…


感谢各位对我的教程提出大量的反馈。我要很自豪的说,Webpack 前几天在 Twitter 上推荐了这篇教程,并且它已经得到了一些贡献者的认可!

谢谢!


网上有上百万的教程,所以你可能已经看到了上千种配置 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'

[email protected] requires Babel 7.x (the package '@babel/core'). If you'd like to use Babel 6.x ('babel-core'), you should install '[email protected]'.
复制代码

我解决了这个问题,通过执行

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 [email protected]
复制代码

yarn add --dev [email protected]
复制代码

专业提示: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前端后端区块链产品设计人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划官方微博知乎专栏

猜你喜欢

转载自juejin.im/post/5c612ba351882562ea721b39
0条评论
添加一条新回复