深入了解 Webpack 4

程序员翻译

原文:Webpack 4 Tutorial: from 0 Conf to Production Mode

Webpack 4 发布了!这个流行的模块打包工具获得了大量更新。

Webpack 4,有什么最新的特性?大规模的性能改进,零配置和合理的默认设置。

这是一篇新鲜出炉的 webpack 4 教程文章。

零配置的模块打包工具 webpack 4

webpack 非常强大且拥有许多独特的特性,其中有一个难点,就是它的配置文件。
为中大型项目提供 webpack 配置理所当然,缺少了它你将无法运行项目。但是,对于小项目而言,webpack 的配置有点烦人,特别是当你只想要运行一些小的示例应用程序时。
所以这也是为什么 Parcel 能够获得如此多关注的原因。
这里着重提一点:webpack 4 默认不需要配置文件!
让我们开始试试看吧。

webpack 4:从零配置开始

本地创建一个目录

mkdir webpack-4-quickstart && cd $_

初始化 package.json 文件

npm init -y

接着安装 webpack 4 和 webpack-cli

npm i webpack --save-devnpm i webpack-cli --save-dev

打开 package.json文件,添加下面的启动脚本,添加完成后记得保存

"scripts": { "build": "webpack"}

接下来尝试运行下面的命令:

npm run build

我们看看发生了什么:

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

上面这个 Error 说的是,webpack 4 在 ./src目录中找不到入口起点。如果你不明白这些错误的含义,可以查看我先前的文章switching from Gulp to webpack
简单来说:入口起点就是 webpack 用来构建你 Javascript 包的一个起始文件。
在以前的 webpack 版本中,必须要在 webpack.config.js 配置文件中定义入口起点。
从 webpack 4 开始,不再需要定义这个入口起点,它会自动以 ./src/index.js 作为入口起点。
要体验这些新功能很简单,接下来让我们创建 ./src/index.js 文件并写入下面的内容:

console.log(I'm a silly entry point);

然后再一次运行打包命令:

npm run build

你会在项目中看到一个打包后文件 ~/webpack-4-quickstart/dist/main.js
额,等等,你一定会问,不需要再同时指定输出文件(output file)了吗?是的,连这个也不需要了。
在 webpack 4 中,既不需要定义入口文件也不需要定义输出文件。
webpack 的主要优势在于代码分割。但请相信我,零配置工具可以加快你的速度。
综上所述,webpack 4 不需要配置文件
它会默认以你项目中的 ./src/index.js 文件为入口文件,此外,它会在 ./dist/ 中输出打包后的文件。
在下一节中,我们将看到 webpack 4 的另一个不错的功能:生产和开发模式。

生产和开发模式

拥有 2 个配置文件是 webpack 开发中的常见模式。
一个典型的项目可能有:

  • 一个开发环境的配置文件,用来定义 webpack 开发服务器和一些其他设置项
  • 一个生产环境的配置文件,用来定义 UglifyJSPlugin,sourcemaps 等等这些

虽然较大的项目可能仍然需要以上 2 个文件,但在 webpack 4 中,你可以在没有一行配置的情况下完成上面的需求。
那么,如何来做呢?
webpack 4 提到了生产开发模式。
事实上,如果你在前面运行 npm run build 命令时,稍加注意就会留意到在终端里有这样一段输出:
67
The ‘mode’ option has not been set. Set ‘mode’ option to ‘development’ or ‘production’ to enable defaults for this environment.
上面这句话是什么意思呢?让我们接着看。
打开 package.json 文件,添加如下配置:

"scripts": { "dev": "webpack --mode development", "build": "webpack --mode production"}

然后运行:

npm run dev

并看看./dist/main.js 文件。你看到了什么?是的,我知道,和之前一样大的一个无聊的打包文件。
那么你再试着运行这个命令:

npm run build

并看看./dist/main.js。现在你看到了什么?一个更小的打包文件!
是的,生产模式可以开箱即用地进行各种优化。例如 压缩, 作用域提升等等。
而开发模式只是针对速度进行了优化,仅提供了一种不压缩的打包文件。

覆盖默认的入口/输出

我喜欢 webpack 4 的零配置,但是如何覆盖默认入口和输出呢?只需要在 package.json 文件中定义即可。
示例如下:

"scripts": { "dev": "webpack --mode development ./foo/src/js/index.js --output ./foo/main.js", "build": "webpack --mode production ./foo/src/js/index.js --output ./foo/main.js"}

使用 Babel 7 转换 ES6

现代 Javascript 主要是用 ES6 编写的。
但并不是每个浏览器都知道如何处理 ES6,我们需要某种转换。转换的行为是为了让旧的浏览器能够理解处理 ES6 代码。
webpack 不知道如何进行转换但是它有 loaders:你可以将它们视为转换器。
babel-loader 是用于将 ES6 及以上版本转换成 ES5 的 webpack loader。
为了使用这些转换器(loader),我们需要先安装它们。

  • babel core

  • babel loader

  • babel preset env

    npm i @babel/core babel-loader @babel/preset-env --save-dev

接下来,通过在项目文件夹中创建名为 .babelrc 的新文件来配置 Babel:

{ "presets": [ "@babel/preset-env" ]}

此时我们有 2 个地方都可以配置 babel-loader:

  • 使用 webpack 的配置文件
  • 在 npm scripts 中添加 --module-bind

是的,我知道你在想什么。webpack 4 标榜自己为零配置打包工具。为什么还要再次配置这些配置文件?
webpack 4 中零配置的概念适用于:

  • 入口起点
  • 输出
  • 生产和开发模式

这就足够了。但是对于在 webpack 4 中使用加载器,你仍然需要创建配置文件。
我问过 Sean 这件事。webpack 4 中的加载器是否与 webpack 3 相同?有没有计划为像 babel-loader 这样的普通 loader 提供 0 配置?
这是他给我的回复:
“For the future (after v4, maybe 4.x or 5.0), we have already started the exploration of how a preset or addon system will help define this. What we don’t want: To try and shove a bunch of things into core as defaults What we do want: Allow other to extend”
现在你仍然需要依赖 webpack.config.js。让我们接下来来看看…

搭配配置文件使用 babel-loader

创建一个名为 webpack.config.js 的新文件并配置加载器:

module.exports = { module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: { loader: "babel-loader" } } ] }};

这里无需指定入口点,除非是你要自定义入口点。
接着打开 ./src/index.js 文件,写入一些 ES6 代码:

const arr = [1, 2, 3];const iAmJavascriptES6 = () => console.log(...arr);window.iAmJavascriptES6 = iAmJavascriptES6;

运行打包命令:

npm run build

现在我们可以看一下 ./dist/main.js 文件,查看转换后的代码。

无需配置文件使用 babel-loader

还有另一种方法可以使用 webpack loaders。
--module-bind 标志允许你从命令行指定 loaders。这个标志不仅版本 4 有,版本 3 就已存在。
要在没有配置文件的情况下使用 babel-loader,请在 package.json 中配置你的 npm 脚本,如下所示:

"scripts": { "dev": "webpack --mode development --module-bind js=babel-loader", "build": "webpack --mode production --module-bind js=babel-loader" }

在 React 中使用 webpack 4

安装 React:

npm i react react-dom --save-dev

接着添加babel-preset-react

npm i @babel/preset-react --save-dev

.babelrc 中配置 preset:

{ "presets": ["@babel/preset-env", "@babel/preset-react"]}

打开 webpack.config.js 文件,配置 loader,如下所示:

module.exports = { module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, use: { loader: "babel-loader" } } ] }};

如需要测试,你可以在 ./src/App.js 中创建一个 React 组件:

import React from "react";import ReactDOM from "react-dom";const App = () => { return ( <div> <p>React here!</p> </div> );};export default App;ReactDOM.render(<App />, document.getElementById("app"));

然后在 ./src/index.js 中引入该组件:

import App from "./App";

再次运行打包命令。

HTML 插件

webpack 中处理 HTML 的插件是:html-webpack-plugin、html-loader,运行下面的命令安装这 2 个插件:

npm i html-webpack-plugin html-loader --save-dev

接着,更新 webpack 的配置文件webpack.config.js

const HtmlWebPackPlugin = require("html-webpack-plugin");module.exports = {  module: {    rules: [      {        test: /\.js$/,        exclude: /node_modules/,        use: {          loader: "babel-loader"        }      },      {        test: /\.html$/,        use: [          {            loader: "html-loader",            options: { minimize: true }          }        ]      }    ]  },  plugins: [    new HtmlWebPackPlugin({      template: "./src/index.html",      filename: "./index.html"    })  ]};

然后,在src目录下创建入口 html 文件:../src/index.hmtl

&lt;!DOCTYPE html&gt;&lt;html lang="en"&gt;&lt;head&gt;    &lt;meta charset="utf-8"&gt;    &lt;title&gt;webpack 4 quickstart&lt;/title&gt;&lt;/head&gt;&lt;body&gt;    &lt;div id="app"&gt;    &lt;/div&gt;&lt;/body&gt;&lt;/html&gt;</

运行打包命令后,我们可以查看./dist目录,应该可以看到生成的 index.html 文件。在浏览器中打开./dist/index.html,你也应该可以看到 React 组件正常显示了。

在 Vue 中使用 webpack 4

我真的很喜欢 Vue,因为它是许多项目的开发首选。
如果要在 webpack 项目中使用 Vue,可以使用以下命令安装库:

npm i vue --save-dev

接着用下面的 vue 实例替换 src/index.js 中的内容:

import Vue from "vue";const app = new Vue({  el: "#app",  data: {    message: "Hello Vue!"  }});

接下来配置 webpack.config.js 以加载 Vue 包:

resolve: {  alias: {    vue$: "vue/dist/vue.esm.js"  }}

现在,你可以运行构建命令,并将你的 Vue 实例注入到 HTML 文件中。

提取 CSS 到一个单独的文件中

webpack 自身是不知道如何将 CSS 提取打包到文件中的。
webpack 4.0 以前,可以通过 extract-text-webpack-plugin 插件,把 CSS 样式从 JS 文件中提取到单独的 CSS 文件中。但不幸的是,这个插件与 webpack 4 不太匹配。
Michael Ciniawsky 给的说法是这样的:

extract-text-webpack-plugin reached a point where maintaining it become too much of a burden and it’s not the first time upgrading a major webpack version was complicated and cumbersome due to issues with it

webpack 4.0 以后,mini-css-extract-plugin 这个插件可以解决上面的问题。

提示: 确保 webpack 版本升级至 4.2.0。否则 mini-css-extract-plugin 插件无法正常工作

运行命令安装所需插件:

npm i mini-css-extract-plugin css-loader --save-dev

接着创建一个 CSS 文件 main.css 用来测试打包后的效果。

/* *//* CREATE THIS FILE IN ./src/main.css *//* */body {    line-height: 2;}

配置 webpack.config.js 文件的 plugin 和 loader:

const HtmlWebPackPlugin = require("html-webpack-plugin");const MiniCssExtractPlugin = require("mini-css-extract-plugin");module.exports = {  module: {    rules: [      {        test: /\.js$/,        exclude: /node_modules/,        use: {          loader: "babel-loader"        }      },      {        test: /\.html$/,        use: [          {            loader: "html-loader",            options: { minimize: true }          }        ]      },      {        test: /\.css$/,        use: [MiniCssExtractPlugin.loader, "css-loader"]      }    ]  },  plugins: [    new HtmlWebPackPlugin({      template: "./src/index.html",      filename: "./index.html"    }),    new MiniCssExtractPlugin({      filename: "[name].css",      chunkFilename: "[id].css"    })  ]};

再在我们前面创建的入口文件 ./src/index.js 中导入 CSS 文件 main.css

//// PATH OF THIS FILE: ./src/index.js//import style from "./main.css";

运行打包命令:

npm run build

打包完成后,我们在 ./dist 目录下应该可以看到提取出的 CSS 文件。

webpack 开发服务器

每次你修改了项目代码,都要运行 npm run dev 才能在浏览器中看到修改后的效果?不,这不是我们所要的。
使用 webpack 配置开发服务器只需一分钟,一旦配置好 webpack 开发服务器,它将在浏览器中启动你的应用程序,每次更改文件时,它都会自动刷新浏览器的窗口。
运行下面命令安装所需的包:

npm i webpack-dev-server --save-dev

打开 package.json 文件,配置下面的脚本命令:

"scripts": {  "start": "webpack-dev-server --mode development --open",  "build": "webpack --mode production"}

现在,运行 start 命令:

npm run start

你可以看到 webpack 开发服务器在浏览器中启动了你的应用。