深入了解 Webpack 4

深入了解 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-dev
npm 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 的另一个不错的功能:生产和开发模式。

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:覆盖默认的入口/输出

我喜欢 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"
}

webpack 4:使用 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。让我们接下来来看看…

webpack 4: 搭配配置文件使用 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 文件,查看转换后的代码。

webpack 4: 无需配置文件使用 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"
  }

webpack 4: 在 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";

再次运行打包命令。

webpack 4: 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

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

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

webpack 4: 在 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 文件中。

webpack 4: 提取 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 4: 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 开发服务器在浏览器中启动了你的应用。

可能还喜欢下面的内容

JavaScript 中有趣的特性

JavaScript 中有趣的特性

帮你节省旅行开销的几点方法

帮你节省旅行开销的几点方法

如何成为一名优秀的前端工程师

如何成为一名优秀的前端工程师

ins@heyrock