Press "Enter" to skip to content

Webpack的入门教程(一)

本文略译自《Webpack – A Detailed Introduction》。在开始阅读教程前,如果你是初学者,理解webpack我写了一些抽象提醒,你可随时回来读:

对任务细致的了解极利于对工具/技术细致的认识。本文假设你的任务是:
第一,开发一个前端JS程序/web app;
第二,JS程序使用了第三方的库;
第三,为是了提供「自动化模块化构建」,构建使用了webpack ,webpack本身也是nodejs cli 程序;
这里最巧妙,又容易让人迷惑的地方是,目标程序(前端JS程序),使用的构建工具(webpack),和依赖的第三方库,都是JS模块/软件/程序;

好,开始翻译。

Module Bundler是什么为什么?

浏览器加载模块(文件)的脆弱方式

大多数编程语言都有某种形式的「模块化机制」,通过模块,你可以将代码分成多个文件,再将这些文件引用到主程序中,以使用其中包含的功能。程序模块化一般需要「语言以及其运行时环境支持」(例如支持动态加载模块),然而,JS(前端JS)以及浏览器(JS语言的运行时环境),对模块化的支持非常脆弱。脆弱表现有:

  1. 第一,ES5没有内置的模块化语言功能,只有通过浏览器的script标签的顺序加载(被引用的通用模块先加载),模拟一种蹩脚的模块化;
  2. 第二,ESM支持有限;
  3. 第三,存在多种第三方模块化系统;

为了强化前端模块化开发功能,现实统一的方式编写程序模块,「Module bundlers」的概念出现了,它将使用了高级的统一的模块系统(例如CJS)编写的(多个)模块,“编译”或打包(bundle原始概念)成浏览器能理解的方式,Module bundlers 使用两种实现方式

  • 第一,通过异步加载模块并在加载完成后运行模块;
  • 第二,将所有必要的文件合并(bundle原始概念)到一个 JavaScript 文件中,将通过<script>加载。

EM:Module Bundler工具以及其针对的模块化自动化任务,是前端JS程序模块化开发的「额外任务」。具体这个任务是什么,得先细致前端JS程序的运行结构,怎么去构建它。

手动维护复杂的模块依赖关系

如上所说,如果没有模块加载器和 bundlers,你始终需要手动合并文件,不然要维护大量<script>标签,这有几个缺点:

• 您需要跟踪文件应加载的正确顺序,和依赖关系,例如哪些文件依赖于哪些其他文件,并确保不包括你不需要的任何文件;
• 多个<script> 标记意味着多次调用服务器以加载所有代码,这损耗了性能。
• 以上,这需要大量的手工工作,耗费了不少工作时间,因为它完全可以让电脑自动为你做。

大多数Module Bundler工具可以直接与 npm 或 Bower 集成,以便轻松地将「第三方依赖项」添加到你的应用程序中。安装第三方依赖只需放入一行代码,即可将它们导入到你的应用程序中。然后,运行Module Bundler,就可将第三方代码合并入你的应用程序中。又或者,如果你正确配置了它,你还可以将所有第三方代码放在一个单独的文件中,这样当更新了你的应用程序代码(升级或修复BUG)时, 用户「只需要更新缓存中你的应用程序代码,而不用更新第三方的代码」。

为什么选择Webpack?

现在你已经知道了 module bundlers 的理论、意义了,那在具体选择工具上,为什么你应该选择的webpack而不是其它竞争的bundler?有几个理由:

  • webpack技术更先进,克服先前技术的一些问题和不足
  • webpack使用更简单,如果没有 fancy stuff,不需配置文件
  • webpack有丰富的插件系统
  • webpack有较全面的社区

有了我给的所有的赞美,我相信你只是在等我继续前进,展示一些代码,对吧?那我们就这么做吧。

Webpack的安装及使用方式

在我们可以使用webpack之前,我们需要安装它。要做到这一点,我们需要一台完整的nodejs虚拟机,至少安装有 nodejs 和 npm,这两者我都假设你的电脑已经安装有。

webpack安装到项目本地

webpack本质只是一个 nodejs package,是nodejs虚拟机的CLI tool,然而在使用上,你可以有两种方法安装:全局或本地。如果全局安装,就像其它nodejs cli tool一样,你可以在任意目录内使用,但它不会作为项目的依赖项包括在内(EM:这是一种构建上的依赖,而不是源码功能上的依赖), 并且你不能在「不同的项目」内切换「不同版本的 webpack」(某些web项目使用了旧版本的webpack可能不立即使用新版webpack,需要更多的工作才能升级到更高版本)。

因此,我更倾向于在项目本地安装 CLI 包,使用相对路径或「 npm 脚本」来运行它。如果你不习惯在本地安装 CLI 包,你可以在我写的关于摆脱全局 npm 包的帖子中看到它。

使用npm脚本执行构建

本文的例子中,我们是使用项目本地安装的webpack的,并展示如何中使用 「npm 脚本」来执行任务。首先要做的是:为项目创建一个目录,我们可以在其中进行实验和学习有关webpack的知识。我在 GitHub 上有一个仓库,你可以克隆该库,在其中切换其分支直接查看,也可以一步一步从头开始自己试, 也可以使用我的进行比较。

实验项目的创建与配置

创建nodejs项目

学习的第一步,是创建一个空白的nodejs项目,你通过命令行控制台进入项目的目录,使用 npm init 初始化项目。过程会问你的一些问题,不过, 除非你计划在 npm 上发布这个项目,否则你提供的信息不是那么重要。

安装和配置「某项目的构建依赖」

现在,你通过创建 package. json 文件已经创建一个nodejs平台的开发项目(虽然这个项目的目标是转换成在浏览器端运行的JS程序),你可以将你的项目依赖项保存在其中。现在让我们使用 npm 安装 webpack 作为「项目的构建依赖项」:

npm install webpack -D  //-D 将其保存在 pack. json 中作为开发依赖项,参数相同–save-dev

安装和配置「某项目的源码依赖」

要展示如何使用webpack,我们需要一个(简单的)具体应用程序例子。首先,假设我们有一个简单的项目,它使用了js库lodash,我们先安装这个包,然后将引入我们的项目作为「源码依赖」:

npm install lodash -S  //-S is the same as –save

一支简单的nodejs程序

现在我们创建一个名为 src 的目录,并在其中创建一个名为 main. js 的文件,其中包含以下内容:

var map = require('lodash/map');

function square(n) {
return n*n;
}

console.log(map([1,2,3,4,5,6], square));

即使你没有nodejs开发经验都很容易看懂这个程序,它用一个具体的数组,和自定义高阶函数square调用了map进行数值转换,这里重点是你的项目代码引用了第三方库lodash。main. js本质是一个nodejs模块,可以在nodejs运行。但是,我们是学习用webpack打包模块依赖,在浏览器上运行,怎么做呢?。

配置npm脚本

「简单的打包任务」可以直接在命令行配置webpack,调用命令提供打包输入和打包输出参数就行了。如果打包任务较复杂,则需要使用配置文件(下面会讲到),由于只是我们将webpack安装到项目本地,所以要通过npm 脚本来调用webpack。

在本例中, 我们的输入路径是 src/main.js,我们要将打包的文件输出到 dist/bundle.js。让我们创建一个 「npm 脚本」来执行此操作 。在 package. json 中,编辑 “scripts” 部分,使其如下所示:

…
"scripts": {
"build": "webpack src/main.js dist/bundle.js",
}
…

执行「npm 脚本」,在项目目录运行 npm run build,就会得到一个 dist/bundle.js。现在你可以在nodejs上运行bundle.js 文件,也可以在浏览器中使用简单的 HTML 页面运行该文件,并在控制台中看到相同的结果。

使用npm 脚本作为构建工具

「npm 脚本」可以作为一通用的事务工具,类似grunt,「打包JS模块」只是「构建任务」的一小部分。在探索更多的 webpack 之前,让我们尝试增加清理上次构建的数据(dist目录),执行(run)打包好的bundle.js当常见构建事务。

要完成清理任务,我们需要安装 del-cli,使用统一的方式删除目录,我使用的是windows平台,系统清理命令不同于非windoows系统。和wedpack一样,我们以安装项目构建依赖的方法将del-cli安装到本地:

npm install del-cli -D

然后, 我们将 npm 脚本更新为以下内容:

…
"scripts": {
"prebuild": "del-cli dist -f",
"build": "webpack src/main.js dist/bundle.js",
"execute": "node dist/bundle.js",
"start": "npm run build -s && npm run execute -s"
}
…

可以看到我们设置一个“前构建”prebuild的任务,它在每次“build”前被执行。另外,我们还设置“执行”和“启动”两个任务,“执行”意思很直观,就是用node执行构建的bundle.js,“启动”就是将构建和执行组合在一起(注意-s 是silent参数,消除执行噪音)。 OK,到此你完成了我前面提到的例子仓库中的example1分支中的所有内容。

webpack 的配置文件

webpack 命令行配置(configuration)只适用于「模块打包任务」较简单的,当打包任务较复杂时,你得使用单独的配置文件(webpack.config.js),来保存了配置数据(configuration opions),一为可行,二为更易阅读。webpack配置数据是常见的opions对象。

OK,让我们来创建一个配置文件,它的名字webpack.config.js 是默认的,也可使用命令行开关-config自定义,文件保存在项目根目录下。

在这里,我们只使用默认文件名。现在我们将前面的webpack命令行配置,改写为使用配置文件配置。具体如下:

module.exports = {
 entry: './src/main.js',
 output: {
  path: './dist',
  filename: 'bundle.js'
 }
};

注意,这是一个 JavaScript 文件/模块,而不是 JSON 文件,因此我们需要导出配置对象——module.exports。这看起来并不比通过「命令行配置」好,但到后面就看到好处。

现在,我们可更新npm脚本了——package.json中删除那些传递给 webpack的选项:

…
"scripts": {
"prebuild": "del-cli dist -f",
"build": "webpack",
"execute": "node dist/bundle.js",
"start": "npm run build -s && npm run execute -s"
}
…

OK,这是例子仓库中的example2分支中的内容。

Be First to Comment

Leave a Reply

Your email address will not be published. Required fields are marked *