Skip to content

Commit

Permalink
docs: add detailed explanation for NormalModuleFactory hooks (#7468)
Browse files Browse the repository at this point in the history
* docs: add detailed explanation for NormalModuleFactory hooks

* Apply suggestions from code review

Co-authored-by: Gengkun <[email protected]>

---------

Co-authored-by: Gengkun <[email protected]>
  • Loading branch information
chenjiahan and ahabhgk authored Aug 6, 2024
1 parent f420048 commit 1480afa
Show file tree
Hide file tree
Showing 2 changed files with 181 additions and 27 deletions.
103 changes: 90 additions & 13 deletions website/docs/en/api/plugin-api/normal-module-factory-hooks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,36 @@ import { Collapse, CollapsePanel } from '@components/Collapse';

# NormalModuleFactory

`NormalModuleFactory` is used by the [Compiler](/api/javascript-api/compiler) to generate modules (`NormalModule`). Starting from each entry module (`entry`), it resolves the dependency requests of the modules to obtain the final paths of the dependencies. Based on these final paths, it creates `NormalModule` instances. It then further resolves the dependency requests of the newly created modules. This process is recursive, creating each module as a `NormalModule` through `NormalModuleFactory`.

`NormalModuleFactory` provides the following lifecycle hooks. These can be used just like `Compiler` hooks:

```js
NormalModuleFactory.hooks.someHook.tap(/* ... */);
```

All hooks inherit from `Tapable`. In addition to `tap()`, you can also use `tapAsync()` and `tapPromise()`, depending on the type of the hook.

## `beforeResolve`

`AsyncSeriesBailHook<[ResolveData]>`

Called when a new dependency request is encountered. A dependency can be ignored by returning `false`. Otherwise, it should return `undefined` to proceed.

The `beforeResolve` hook is called at the very beginning of the module resolution process, allowing the module's request information to be intercepted and modified before the resolution takes place. This hook can be used to pre-process, filter or block the resolution of certain modules.

```js
compiler.hooks.compilation.tap(
'MyPlugin',
(compilation, { normalModuleFactory }) => {
normalModuleFactory.hooks.beforeResolve.tap('MyPlugin', resolveData => {
// access and modify module request information
console.log(JSON.stringify(resolveData, null, 2));
});
},
);
```

<Collapse>
<CollapsePanel
className="collapse-code-panel"
Expand All @@ -23,12 +47,22 @@ Called when a new dependency request is encountered. A dependency can be ignored

`AsyncSeriesBailHook<[ResolveData]>`

:::warning
Returning module instance is not supported for now.
:::

Called before initiating resolve. It should return undefined to proceed.

The `factorize` hook is used to add custom logic before a module is instantiated, modifying the module creation process.

```js
compiler.hooks.compilation.tap(
'MyPlugin',
(compilation, { normalModuleFactory }) => {
normalModuleFactory.hooks.factorize.tap('MyPlugin', resolveData => {
// access and modify module request information
console.log(JSON.stringify(resolveData, null, 2));
});
},
);
```

<Collapse>
<CollapsePanel
className="collapse-code-panel"
Expand All @@ -39,15 +73,27 @@ Called before initiating resolve. It should return undefined to proceed.
</CollapsePanel>
</Collapse>

:::warning
Returning module instance is not supported for now. This hook will affect the module creation process, so use it with caution.
:::

## `resolve`

`AsyncSeriesBailHook<[ResolveData]>`

:::warning
Returning module instance or `false` is not supported for now.
:::

Called before the request is resolved. It should return undefined to proceed.
Called before the request is resolved, it should return `undefined` to continue. The `resolve` hook can be used to intercept and modify module request information before module resolution begins. This hook allows for preprocessing of module requests.

```js
compiler.hooks.compilation.tap(
'MyPlugin',
(compilation, { normalModuleFactory }) => {
normalModuleFactory.hooks.resolve.tap('MyPlugin', resolveData => {
// access and modify module request information
console.log(JSON.stringify(resolveData, null, 2));
});
},
);
```

<Collapse>
<CollapsePanel
Expand All @@ -59,12 +105,30 @@ Called before the request is resolved. It should return undefined to proceed.
</CollapsePanel>
</Collapse>

:::warning
Returning module instance or `false` is not supported for now.
:::

## `afterResolve`

`AsyncSeriesBailHook<[ResolveData]>`

Called after the request is resolved.

The `afterResolve` hook is used to further process or modify the results after the module has been resolved. It is called at the end of the module resolution process, which means that at this stage, the module's path, request information, etc., have already been determined.

```js
compiler.hooks.compilation.tap(
'MyPlugin',
(compilation, { normalModuleFactory }) => {
normalModuleFactory.hooks.afterResolve.tap('MyPlugin', resolveData => {
// access and modify the resolved module information
console.log(JSON.stringify(resolveData, null, 2));
});
},
);
```

<Collapse>
<CollapsePanel
className="collapse-code-panel"
Expand All @@ -81,14 +145,27 @@ Called after the request is resolved.

Called before a request with scheme (URI) is resolved.

The `resolveForScheme` is typically used to handle module requests that have a specific protocol, such as `file://`, `https://`, etc.

```js
compiler.hooks.compilation.tap(
'MyPlugin',
(compilation, { normalModuleFactory }) => {
normalModuleFactory.hooks.resolveForScheme.tap('MyPlugin', resourceData => {
console.log(JSON.stringify(resourceData, null, 2));
});
},
);
```

<Collapse>
<CollapsePanel className="collapse-code-panel" header="ResourceDataWithData.ts" key="ResourceDataWithData">
```ts
type ResourceDataWithData = {
resource: string;
path: string;
query?: string;
fragment?: string;
resource: string;
path: string;
query?: string;
fragment?: string;
data?: Record<string, any>;
};
```
Expand Down
105 changes: 91 additions & 14 deletions website/docs/zh/api/plugin-api/normal-module-factory-hooks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,36 @@ import { Collapse, CollapsePanel } from '@components/Collapse';

# NormalModuleFactory 钩子

`NormalModuleFactory`[Compiler](/api/javascript-api/compiler) 用来生成模块(`NormalModule`)。从每个入口模块(`entry`)开始,它解析模块的依赖请求,得到依赖的最终路径,从而根据最终路径创建 `NormalModule`,并进一步解析新创建出的模块的依赖请求,递归此过程,以此将每个模块通过 `NormalModuleFactory` 创建为 `NormalModule`

`NormalModuleFactory` 提供以下生命周期钩子。它们可以像 `Compiler` 钩子一样被使用:

```js
NormalModuleFactory.hooks.someHook.tap(/* ... */);
```

所有钩子均继承自 `Tapable`,除了 `tap()`,你还可以使用 `tapAsync()``tapPromise()`,具体取决于钩子的类型。

## `beforeResolve`

`AsyncSeriesBailHook<[ResolveData]>`

当遇到新的依赖请求时调用。可以通过返回 `false` 来忽略依赖项。否则,应该返回 `undefined` 以继续。

`beforeResolve` 在模块解析过程的最开始阶段触发,用于在模块解析之前,拦截并修改模块的请求信息。通过这个钩子,可以对模块请求进行预处理、过滤或阻止某些模块的解析。

```js
compiler.hooks.compilation.tap(
'MyPlugin',
(compilation, { normalModuleFactory }) => {
normalModuleFactory.hooks.beforeResolve.tap('MyPlugin', resolveData => {
// 访问和修改模块请求信息
console.log(JSON.stringify(resolveData, null, 2));
});
},
);
```

<Collapse>
<CollapsePanel
className="collapse-code-panel"
Expand All @@ -23,11 +47,21 @@ import { Collapse, CollapsePanel } from '@components/Collapse';

`AsyncSeriesBailHook<[ResolveData]>`

:::warning
目前不支持返回模块实例,返回 `undefined` 以继续。
:::
在请求开始解析之前调用,返回 `undefined` 以继续。

`factorize` 用于在模块实例化之前插入自定义逻辑,修改模块的创建过程。

在请求开始解析之前调用。
```js
compiler.hooks.compilation.tap(
'MyPlugin',
(compilation, { normalModuleFactory }) => {
normalModuleFactory.hooks.factorize.tap('MyPlugin', resolveData => {
// 访问和修改模块请求信息
console.log(JSON.stringify(resolveData, null, 2));
});
},
);
```

<Collapse>
<CollapsePanel
Expand All @@ -39,15 +73,27 @@ import { Collapse, CollapsePanel } from '@components/Collapse';
</CollapsePanel>
</Collapse>

:::warning
目前不支持返回模块实例。这个钩子会影响模块的创建过程,请谨慎使用。
:::

## `resolve`

`AsyncSeriesBailHook<[ResolveData]>`

:::warning
目前不支持返回模块实例和 `false`
:::

在请求被解析之前调用,返回 `undefined` 以继续。
在请求被解析之前调用,返回 `undefined` 以继续。`resolve` 用于在模块解析开始之前,拦截并修改模块的请求信息。通过这个钩子可以对模块请求进行预处理。

```js
compiler.hooks.compilation.tap(
'MyPlugin',
(compilation, { normalModuleFactory }) => {
normalModuleFactory.hooks.resolve.tap('MyPlugin', resolveData => {
// 访问和修改模块请求信息
console.log(JSON.stringify(resolveData, null, 2));
});
},
);
```

<Collapse>
<CollapsePanel
Expand All @@ -59,11 +105,29 @@ import { Collapse, CollapsePanel } from '@components/Collapse';
</CollapsePanel>
</Collapse>

:::warning
目前不支持返回模块实例和 `false`
:::

## `afterResolve`

`AsyncSeriesBailHook<[ResolveData]>`

在请求被解析后调用。
在模块的请求被解析后调用。

`afterResolve` 用于在模块解析完成之后,进一步处理或修改模块的解析结果。它在模块解析过程的末尾触发,意味着在这个阶段,模块的路径、请求信息等已经确定。

```js
compiler.hooks.compilation.tap(
'MyPlugin',
(compilation, { normalModuleFactory }) => {
normalModuleFactory.hooks.afterResolve.tap('MyPlugin', resolveData => {
// 访问和修改解析后的模块信息
console.log(JSON.stringify(resolveData, null, 2));
});
},
);
```

<Collapse>
<CollapsePanel
Expand All @@ -81,14 +145,27 @@ import { Collapse, CollapsePanel } from '@components/Collapse';

在带有 scheme 的解析(URI)请求之前调用。

`resolveForScheme` 通常用于处理具有特定协议的模块请求,例如 `file://``https://` 等。

```js
compiler.hooks.compilation.tap(
'MyPlugin',
(compilation, { normalModuleFactory }) => {
normalModuleFactory.hooks.resolveForScheme.tap('MyPlugin', resourceData => {
console.log(JSON.stringify(resourceData, null, 2));
});
},
);
```

<Collapse>
<CollapsePanel className="collapse-code-panel" header="ResourceDataWithData.ts" key="ResourceDataWithData">
```ts
type ResourceDataWithData = {
resource: string;
path: string;
query?: string;
fragment?: string;
resource: string;
path: string;
query?: string;
fragment?: string;
data?: Record<string, any>;
};
```
Expand Down

0 comments on commit 1480afa

Please sign in to comment.