# 前置教育

# 模块(Modules)

模块化编程 (opens new window)中,开发者将程序分解为功能离散的 chunk,并称之为 模块

每个模块都拥有小于完整程序的体积,使得验证、调试及测试变得轻而易举。 精心编写的 模块 提供了可靠的抽象和封装界限,使得应用程序中每个模块都具备了条理清晰的设计和明确的目的。

Node.js 从一开始就支持模块化编程。 然而,web 的 模块化 正在缓慢支持中。 在 web 界存在多种支持 JavaScript 模块化的工具,这些工具各有优势和限制。 webpack 从这些系统中汲取了经验和教训,并将 模块 的概念应用到项目的任何文件中。

# 何为 webpack 模块

Node.js 模块 (opens new window)相比,webpack 模块 能以各种方式表达它们的依赖关系。下面是一些示例:

# 支持的模块类型

webpack 天生支持如下模块类型:

通过 loader 可以使 webpack 支持多种语言和预处理器语法编写的模块。loader 向 webpack 描述了如何处理非原生模块,并将相关依赖引入到你的 bundles中。 webpack 社区已经为各种流行的语言和预处理器创建了 loader,其中包括:

当然还有更多!总得来说,webpack 提供了可定制,强大且丰富的 API,允许在 任何技术栈 中使用,同时支持在开发、测试和生产环境的工作流中做到 无侵入性

关于 loader 的相关信息,请参考 loader 列表 (opens new window)自定义 loader (opens new window)

# 模块化

在 webpack 打包应用程序时,你可以选择各种模块语法风格,包括 ES6 (opens new window)CommonJS (opens new window)AMD (opens new window)

# ES6 (推荐)

webpack 2 支持原生的 ES6 模块语法,意味着你无须额外引入 babel 这样的工具,就可以使用 importexport。但是注意,如果使用其他的 ES6+ 特性,仍然需要引入 babel。

# 解析器(Resolvers)

解析器是使用 enhanced-resolve 库创建的。Resolver 类 拓展了 tapable 类,并使用 tapable 来提供了一些钩子。 enhanced-resolve 可以直接用于创建新的解析器, 但是,任何 compiler 实例 (opens new window) 都有一些解析器实例,可以 被 tap 进去。

在继续阅读之前,请确保你已经读过 enhanced-resolve (opens new window)tapable (opens new window) 文档。

# 模块解析(Module Resolution)

resolver 帮助 webpack 从每个 require/import 语句中,找到需要引入到 bundle 中的模块代码。 当打包模块时,webpack 使用 enhanced-resolve (opens new window) 来解析文件路径。

# webpack 中的解析规则

使用 enhanced-resolve,webpack 能解析三种文件路径:

# 绝对路径

import '/home/me/file';

import 'C:\\Users\\me\\file';

由于已经获得文件的绝对路径,因此不需要再做进一步解析。

# 相对路径

import '../src/file1';
import './file2';

在这种情况下,使用 importrequire 的资源文件所处的目录,被认为是上下文目录。在 import/require 中给定的相对路径,会拼接此上下文路径,来生成模块的绝对路径。

# 模块路径

import 'module';
import 'module/lib/file';

resolve.modules (opens new window) 中指定的所有目录检索模块。 你可以通过配置别名的方式来替换初始模块路径,具体请参照 resolve.alias (opens new window) 配置选项。

一旦根据上述规则解析路径后,resolver 将会检查路径是指向文件还是文件夹。如果路径指向文件:

  • 如果文件具有扩展名,则直接将文件打包。
  • 否则,将使用 resolve.extensions (opens new window) 选项作为文件扩展名来解析,此选项会告诉解析器在解析中能够接受那些扩展名(例如 .js.jsx)。

如果路径指向一个文件夹,则进行如下步骤寻找具有正确扩展名的文件:

webpack 会根据构建目标,为这些选项提供合理的默认 (opens new window)配置。

# 解析 loader

loader 的解析规则也遵循特定的规范。但是 resolveLoader (opens new window) 配置项可以为 loader 设置独立的解析规则。

# 缓存

每次文件系统访问文件都会被缓存,以便于更快触发对同一文件的多个并行或串行请求。在 watch 模式 (opens new window) 下,只有修改过的文件会被从缓存中移出。如果关闭 watch 模式,则会在每次编译前清理缓存。

欲了解更多上述配置信息,请查阅 Resolve API (opens new window)

# Shimming 预置依赖

webpack compiler 能够识别遵循 ES2015 模块语法、CommonJS 或 AMD 规范编写的模块。然而,一些 third party(第三方库) 可能会引用一些全局依赖(例如 jQuery 中的 $)。因此这些 library 也可能会创建一些需要导出的全局变量。这些 "broken modules(不符合规范的模块)" 就是 shimming(预置依赖) 发挥作用的地方。

WARNING

我们不推荐使用全局依赖!webpack 背后的整个理念是使前端开发更加模块化。也就是说,需要编写具有良好的封闭性(well contained)、不依赖于隐含依赖(例如,全局变量)的彼此隔离的模块。请只在必要的时候才使用这些特性。

webpack.config.js

 const path = require('path');
+const webpack = require('webpack');

 module.exports = {
   entry: './src/index.js',
   output: {
     filename: 'main.js',
     path: path.resolve(__dirname, 'dist'),
   },
+  plugins: [
+    new webpack.ProvidePlugin({
+     $: 'jQuery',
+   }),
+  ],
 };

# 参考文献

Last Updated: 5/23/2021, 5:43:33 PM