webpack 入门教程

webpack是什么?

简而言之,webpack是一个开源的JavaScript模块打包器。在github上有超过60k星量,它是这个领域的领导者。
Webpack允许你在开发中将JavaScript拆分为单独的模块(更好的维护),同时让你在生产中将这些模块编译成单个包(更好的提高性能)。
从历史上看,很多新手或者经验不足的开发者由于webpack的复杂性而避开了webpack,这在某种程度上可能是真的,但webpack继续接收定期更新,并在每个版本中变得更好。webpack团队在2020年10月发布了5.0.0版本,此后进行了多次增量更新。
值得注意的是,webpack 4.0.0是第一个不需要webpack.config.js文件来打包项目的版本。仅就这一项就是的新开发人员更容易的使用它。

安装 webpack

安装 webpack 5 需要 Node 10.13.0 或更高版本的Node,所以如果你有一段时间没有更新Node的话,你必须在安装webpack之前更新下Node。
webpack 文档强烈建议在本地安装 webpack,而不是全局安装。这也就意味着你在每个项目中要单独安装它,而不是在每个项目中使用一个全局安装。通过单独的本地安装,也可以根据需要升级(或不升级)每个安装。
跟随本webpack教程,创建一个项目目录,然后使用它来运行教程介绍的各种命令。一旦项目目录准备好了,然后运行以下两个命令(第一个命令确保转到目中):

cd webpack-example
npm init -y

在本例中,我将示例项目的根文件夹命名为webpack-tutorial。你可以随意命名。npm init -y命令使用npm的默认设置初始化目录,这会创建一个package.json的文件。
下一步,安装 webpack 和 webpack CLI

npm install webpack webpack-cli --save-dev

一旦我将两个包都安装为项目的依赖项,我的package.json文件将如下所示:

{
  "name": "webpack-tutorial",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^5.72.1",
    "webpack-cli": "^4.9.2"
  }
}

注意底部附近列出的两个作为依赖项的包(webpack 和 webpack-cli),这个项目现在基本上可以使用webpack作为它的打包器了,因此可以开始在这个webpack教程中付诸实践了。

设置要捆绑的项目

在当前状态下,本项目还没有绑定任何东西,因此我们可以添加一些东西来演示一个简单的绑定过程是如何发生的。仅此一项就足够让你开始使用webpack了,但是后面会添加一些配置,使得webpack变得更加强大。
在与package.json文件同目录下,添加以下内容:

  • 一个名为src的文件夹
  • src下创建一个名为index.html的文件
  • src下创建一个名为index.js的文件
  • 一个dist文件夹

webpack文档很好地解释了src (source)和dist (distribution)文件夹的用途(尽管这不是针对webpack的,更多的是关于打包和构建过程的):
The “source” code is the code that we’ll write and edit. The “distribution” code is the minimized and optimized output of our build process that the browser will display.
理想情况下,包设置将在每次创建包时清空dist文件夹。后面会做介绍,但现在更专注于src文件夹中的文件(编辑一直在该文件夹中进行)。
首先,我需要给index.html和index.js文件中添加一些内容。自然,index.html文件可以包含任何内容。我通常会将所有网站内容包括在src目录中,包括样式表、图像等,但这个简单的示例只是为了演示webpack的特性。
传统做法上,当想要在项目中添加一个或多个依赖库时,应该使用单独的<script>元素逐个将它们列在index.html页面的底部。还将包含使用这些其他依赖项的自定义的JavaScript。这就是webpack这种工具的作用,因为你不仅可以避免手动添加脚本到你的页面,你还可以添加它们,打包它们进行优化,有时甚至可以按需加载它们。

安装打包脚本

我将使用 npm 来安装我的依赖项,然后使用 webpack 来捆绑它们,而不是传统的和非最佳的添加和合并脚本的方法。出于演示目的,我将使用两个 JavaScript 实用程序库:

需要明确的是:webpack 不需要这些;它们只是随机选择的几个示例实用程序,用于演示 webpack 的打包功能。项目将包含不同的库和实用程序,可能是更大的工具,例如用于跨浏览器 JavaScriptReactVueBabel.js
要使用选择的这些实用程序,就得必须安装它们,所以要先这样做:

npm install panzoom --save
npm install @egjs/flicking --save

在本示例中,我是用 --save 标志而不是 --save-dev,因为我希望这些作为我的生产构建的一部分。当我安装 webpack 时,我将它安装未开发人员依赖项,因此 webpack 不会成为我的生产构建的一部分。
现在我的 package.json 在dependencies 部分下面附加了以下内容:

  "dependencies": {
    "@egjs/flicking": "^4.7.1",
    "panzoom": "^9.4.2"
  }

然后我可以在我的 index.html 文件中包含我的两个实用程序将与之交互的元素。例如,轮播将需要 HTML 中的包装器和“面板”元素,而缩放实用程序需要该实用程序的 API 所针对的一个或多个 HTML 元素。
为了证明这些实用程序已成功捆绑,我将在 src 文件夹中的 index.js 文件中添加以下内容:

import panzoom from "panzoom";
import flicking from "@egjs/flicking";

console.log(panzoom)
console.log(flicking)

在幕后,webpack 将识别这两个 import 语句,并在我的 node_modules 文件夹中查找这两个依赖项。console() 命令只是为了证明捆绑成功并且两个导入都按预期工作。

创建捆绑包

Webpack 使用名为 package.json 的特定 JavaScript 文件作为入口点。入口点向 webpack 指示使用哪个模块来构建项目的依赖关系图。依赖图本质上是应用程序需要的每个模块的映射。
如果我愿意,我可以指定一个自定义入口点,但我更喜欢根据需要使用配置最少的 webpack,所以我将使用默认入口点:./src/index.js。有关更改入口点的信息,请参阅文档
现在我已经安装了一些依赖项,我可以使用 webpack 构建我的包。我可以通过在我的项目目录中运行以下命令来做到这一点:

npx webpack

运行此命令告诉 webpack 使用指定的入口点捆绑我的 JavaScript 依赖项,并且 dist 文件夹将生成输出。在这种情况下,main.js 是我的应用程序将使用的唯一生成文件。尽管我在 src 文件夹中包含了一个 index.html 文件,但 webpack 还没有做任何事情,所以 webpack 到目前为止只生成了 main.js
如果我打开 dist 文件夹中的 main.js,我会找到一个包含我项目中指定的所有依赖项的缩小文件(这两个实用程序以及这两个实用程序所依赖的任何实用程序)。

注意:如果您在 CLI 中收到有关未设置模式选项的警告,请暂时不要担心。稍后我将向您展示如何纠正它。

配置 webpack 以生成 HTML

如前所述,我的 index.html 文件在捆绑过程中没有出现在 dist 目录中。如果我愿意,我可以手动执行此操作,但这违背了使用 webpack 之类的工具来简化构建的目的。
为了解决这个问题,我将安装一个名为 HtmlWebpackPlugin 的插件:

npm install html-webpack-plugin --save-dev

我在 package.json 中的 devDependencies 将反映更改:

"devDependencies": {
    "html-webpack-plugin": "^5.5.0",
    "webpack": "^5.72.1",
    "webpack-cli": "^4.9.2"
  },

虽然我可以在没有任何手动配置的情况下使用 webpack,但它在一些配置下效果最好。要添加手动配置,我将在项目的根文件夹中创建一个 webpack.config.js 文件。在这个文件中,我将添加以下内容以利用这个新安装的插件:

const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');

module.exports = {
  plugins: [
    new HtmlWebpackPlugin()
  ]
};

有了这个,我将再次运行 npx webpack 以获得我的 dist 文件夹中更好的结果。 HtmlWebpackPlugin 生成一个缩小的 HTML 文件,其中添加了我的 JavaScript 包,在页面的 <script> 标记中引用。
问题是,这没有使用我最初在 src 文件夹中创建的 index.html 文件。配置 HtmlWebpackPlugin 以使用该文件作为模板,而不是构建自己的文件。
我将对 src/index.html 进行以下更改:

<!DOCTYPE html>
<html lang="en">
<head>
  <title><%= htmlWebpackPlugin.options.title %></title>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width,initial-scale=1" />
  <meta name="description" content="<%= htmlWebpackPlugin.options.metaDesc %>" />
</head>
<body>
  <h1><%= htmlWebpackPlugin.options.header %></h1>

  <div id="wrapper" style="height: 120px">
    <div class="panel"></div>
    <div class="panel"></div>
    <div class="panel"></div>
  </div>
  <div id="zoom-scene"></div>

</body>
</html>

注意,我添加了多个访问值的变量,在这里用作占位符。这类似于使用 JavaScript 模板或后端模板语言所做的事情。请注意,没有对 JavaScript 文件的引用。
接下来我要在 webpack.config.js 文件的 HtmlWebpackPlugin() 中添加一些选项。我的 webpack.config.js 文件的 plugins:[] 部分现在看起来像这样:

plugins: [
  new HtmlWebpackPlugin({
    hash: true,
    title: 'Webpack Example App',
    header: 'Webpack Example Title',
    metaDesc: 'Webpack Example Description',
    template: './src/index.html',
    filename: 'index.html',
    inject: 'body'
  })
]

注意上面的代码:

  • 我已将哈希设置为 true 以进行缓存清除
  • 我已经指定了模板的位置
  • 我已经给出了要在 dist 文件夹中输出的 HTML 文件的名称

此外,注意我已经在模板中指定了三个用作占位符的变量。我可以在这里创建我想要的任何属性,只要它们不与插件允许的任何预定义选项冲突。最后,我将注入选项设置为 body 值,以确保脚本出现在我的 HTML 中 <body> 元素的底部。

在 webpack 中启用开发模式

目前,当 webpack 构建我的 dist 文件夹时,它使用默认的生产模式构建和捆绑它。如果我不断地在本地构建和检查我的工作,那么如果我的文件没有被缩小可能会更有用。另外,指定一个模式,会避免前面提到的警告。
为了启用开发模式,我将在我的 webpack.config.js 文件中添加一行,因此完整的文件现在看起来像这样:

const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');

module.exports = {
    plugins: [
        new HtmlWebpackPlugin({
          hash: true,
          title: 'Webpack Example App',
          header: 'Webpack Example Title',
          metaDesc: 'Webpack Example Description',
          template: './src/index.html',
          filename: 'index.html',
          inject: 'body'
        })
    ],
    mode: 'development'
};

注意现在在我的 module.exports 对象中指定了模式(不要忘记方括号后面的逗号)。当我准备好发布我的作品时,我可以将其切换到mode: production。现在我的构建将在没有我之前提到的警告消息的情况下干净地进行。

清理 dist 文件夹

在这个设置下,当我在项目上运行webpack时,dist文件夹保持不变,webpack会创建一些同样的文件去覆盖dist文件夹及其里面的相同文件。这样其实可以了,但理想情况下,我希望每个构建都输出到一个空的dist文件夹里。
这是有道理的,因为某些构建可能有新目录、要构建的新文件、重命名文件等等。我不希望旧文件闲置,我只想要每次运行时 webpack 构建和捆绑的内容。
在我的 webpack.config.js 文件中添加另一行,它现在看起来像这样(再次注意额外的逗号以确保语法正确):

const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');

module.exports = {
    plugins: [
        new HtmlWebpackPlugin({
          hash: true,
          title: 'Webpack Example App',
          header: 'Webpack Example Title',
          metaDesc: 'Webpack Example Description',
          template: './src/index.html',
          filename: 'index.html',
          inject: 'body'
        })
    ],
    mode: 'development',
    output: {
        clean: true
    }
};

现在module.export包含有一个具有属性/值对得output对象。这可以确保webpack在每次构建之前都清理了我的dist文件夹。

使用 npm 脚本运行 webpack

到目前为止,我一直使用 npx webpack 命令绑定我的资源。这是一种方式,但是在用 webpack 时,使用 npm 脚本执行命令会效率更高。当我想添加其他命令作为构建过程的一部分时,这将派上用场。
在我的 package.json 文件中,有一个“scripts”部分。我将在其中添加一行,添加后如下(再次注意额外的逗号):

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack"
  },

现在我可以在我项目得根目录下运行以下命令行来运行webpack:

npm run build

这与npx webpack命令有相同的效果:Webpack将使用src里面的入口点开始我的构建,它将绑定我的依赖,然后在dist文件夹下生成输出。
或者,如果想使用脚本来区分开发和生产版本,可以执行下面操作:

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack --mode development",
    "build": "webpack --mode production"
  },

现在我可以运行npm run devnpm run build,这取决于我想对我的项目做什么。

使用热重载安装和使用一个服务器

当使用像 webpack 这样的工具时,最好在本地模拟一个真实的服务器环境,而不是处理 file:// 协议。您可能已经为此设置了一些东西(例如,我使用 XAMPP,因为我经常使用 PHPWordPress)。但是 webpack 让你可以选择轻松地安装带有实时重新加载的服务器,如果你需要的话。
将服务器安装为开发依赖项,在项目的根目录中运行以下命令:

npm install webpack-dev-server --save-dev

安装完成后,我将在我的 webpack.config.js 文件中添加如下:

const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');

module.exports = {
    plugins: [
        new HtmlWebpackPlugin({
          hash: true,
          title: 'Webpack Example App',
          header: 'Webpack Example Title',
          metaDesc: 'Webpack Example Description',
          template: './src/index.html',
          filename: 'index.html',
          inject: 'body'
        })
    ],
    mode: 'development',
    output: {
        clean: true
    },
    devServer: {
        static: {
            directory: path.join(__dirname, 'dist'),
        },
        compress: true,
        port: 9000,
        open: true
    }
};

注意,我在 module.exports 中添加了一个名为 devServer 的部分。这块我已经指定了我希望从哪里提供我的页面,并且我正在使用打开选项在浏览器中自动打开我的项目。浏览器使用默认端口 8080 为页面提供服务,因此在没有设置端口的情况下我可以使用 URL:http://localhost:8080/ 查看我的页面。
需要做的最后一件事是将服务器作为构建脚本的一部分添加到 package.json 中:

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack serve --mode development",
    "build": "webpack --mode production"
  },

注意,我已将 serve 添加到开发脚本中。如果愿意,还可以为生产的构建脚本做同样的事情。有了这个,可以运行以下命令来构建我的包并从 localhost:9000 提供我的页面:

npm run dev

这将打开浏览器,以便查看页面。这也将实时重新加载,如果对 src 文件夹中的内容进行任何更改,捆绑包将在 dist 中再次构建,并且浏览器将自动重新加载页面。

webpack 实现的最终示例

完成上述所有操作后, npm run dev 命令将在每次执行时生成我的构建。然后我可以使用以下命令来构建我的生产项目:

npm run build

这将在生产模式下执行构建脚本(如 package.json 中所述)。这会在 dist 文件夹中的 index.html 中生成以下内容的缩小版本:

<!doctype html>
<html lang="en">
  <head>
    <title>Webpack Example App</title>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width,initial-scale=1"/>
    <meta name="description" content="Webpack Example Description"/>
  </head>

  <body>
    <h1>Webpack Example Title</h1>
    <div id="wrapper" style="height: 120px">
      <div class="panel"></div>
      <div class="panel"></div>
      <div class="panel"></div>
    </div>
    <div id="zoom-scene"></div>
    <script defer="defer" src="main.js?097d8b8eda8ecc97a023"></script>
  </body>
</html>

Webpack 已经使用 HtmlWebpackPlugin 生成的信息更新了我的占位符,我的模板的其余部分保持不变,而且——最重要的是——webpack 已经将我的 JavaScript 模块捆绑到一个 main.js 文件中。文件引用使用查询字符串值来确保浏览器加载新版本而不是缓存版本。
如果我在浏览器中查看我的页面,我会看到两个控制台日志,确认 ‘webpack’ 正确捆绑了我的依赖项。如果你按照这个 ‘webpack’ 教程进行操作,你应该会得到相同的结果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值