解析器

解析器插件负责将依赖说明符转换为将由转换器处理的完整文件路径。解析器在管道中运行,直到其中一个返回结果。有关默认解析器如何工作的详细信息,请参见依赖解析

示例

#

此示例覆盖了 special-module 的解析,否则返回 null 以允许管道中的下一个解析器处理依赖。有关详细信息,请参见 Parcel 配置文档中的解析器

import { Resolver } from "@parcel/plugin";
import path from "path";

export default new Resolver({
async resolve({ specifier }) {
if (specifier === "special-module") {
return {
filePath: path.join(__dirname, "special-module.js"),
};
}

// 让管道中的下一个解析器处理
// 此依赖。
return null;
},
});

加载配置

#

应在解析器插件的 loadConfig 方法中从用户的项目加载配置。有关如何执行此操作的详细信息,请参见加载配置

note:使用 Parcel 的配置加载机制以便正确使缓存失效非常重要。避免直接从文件系统读取文件。

虚拟模块

#

解析器不仅可以解析到文件系统上的文件,还可以直接返回 code。这允许按需以编程方式生成虚拟模块。但是,您仍然必须返回 filePath,因为这表明应该相对于何处解析代码中的依赖,以及源代码应该如何由转换器处理(例如,通过文件扩展名)。

import {Resolver} from '@parcel/plugin';
import path from 'path';

export default new Resolver({
async resolve({specifier}) {
if (specifier === 'special-module') {
return {
filePath: path.join(__dirname, 'special-module.js'),
code: 'export default "This is a special module!";'
};
}

return null;
}
});

依赖元数据

#

除了 specifier,解析器插件还接收完整的 Dependency 对象,其中包含关于依赖的其他元数据。specifierType 属性指示应如何解释 specifier(例如 ESM、CommonJS、URL 等)。resolveFrom 属性指定应从哪个文件路径解析依赖(例如,如果说明符是相对路径)。

此示例根据 specifierType 解析相对 URL 和路径。

import { Resolver } from "@parcel/plugin";
import path from "path";
import { fileURLToPath, pathToFileURL } from "url";

export default new Resolver({
async resolve({ specifier, dependency }) {
return {
filePath:
dependency.specifierType === "url"
? fileURLToPath(
new URL(specifier, pathToFileURL(dependency.resolveFrom))
)
: path.resolve(dependency.resolveFrom, specifier),
};
},
});

排除模块

#

可以返回 isExcluded 属性以指示应从构建中排除某个模块。此示例排除了 aws-sdk,该模块在 AWS 托管环境中自动包含,不需要打包。

import {Resolver} from '@parcel/plugin';

export default new Resolver({
async resolve({specifier}) {
if (specifier === 'aws-sdk') {
return {isExcluded: true};
}

return null;
}
});

缓存失效

#

Parcel 自动缓存解析器插件的结果。如果在解析期间从文件系统读取任何文件,则需要告诉 Parcel 这些文件,以便它可以监视它们并在它们更改时使解析失效。

invalidateOnFileChange 属性应设置为在解析期间成功读取的所有文件的数组。invalidateOnFileCreate 属性应设置为描述文件的 FileCreateInvalidation 对象数组,如果这些文件被创建,则应使解析失效。

import {Resolver} from '@parcel/plugin';
import path from 'path';

export default new Resolver({
async resolve({specifier, options}) {
let aliasFile = path.join(options.projectRoot, 'alias.json');

try {
let aliasConfig = await options.inputFS.readFile(aliasFile);
let aliases = JSON.parse(aliasConfig);
return {
filePath: aliases[specifier] || null,
invalidateOnFileChange: [aliasFile]
};
} catch (err) {
return {
invalidateOnFileCreate: [{filePath: aliasFile}]
};
}
}
});

诊断

#

解析器插件在解析期间可能遇到错误。发生这种情况时,它可以 throw 错误或返回 diagnostics。如果解析器抛出错误,解析过程立即停止,并向用户显示错误。

如果解析器返回 diagnostics,解析将继续到下一个解析器插件。如果没有解析器插件能够解析依赖,则向用户显示所有解析器插件的所有诊断。

import {Resolver} from '@parcel/plugin';
import path from 'path';

export default new Resolver({
async resolve({specifier, options}) {
let aliasFile = path.join(options.projectRoot, 'alias.json');

try {
let aliasConfig = await options.inputFS.readFile(aliasFile);
let aliases = JSON.parse(aliasConfig);
return {
filePath: aliases[specifier] || null,
invalidateOnFileChange: [aliasFile]
};
} catch (err) {
return {
invalidateOnFileCreate: [{filePath: aliasFile}],
diagnostics: [
{
message: 'Could not read alias.json',
hints: ['Create an alias.json file in the project root.']
}]
};
}
}
});

有关更多详细信息,请参见诊断

副作用

#

解析器还可以返回 sideEffects 属性,该属性指示执行资源时是否可能产生副作用。这通常对应 package.json 中的相同属性,并用于作用域提升

相关 API

#

ResolveResult parcel/packages/core/types/index.js:1539

type ResolveResult = {|
  +filePath?: FilePath,

An absolute path to the resolved file.

  +pipeline?: ?string,

An optional named pipeline to use to compile the resolved file.

  +query?: URLSearchParams,

Query parameters to be used by transformers when compiling the resolved file.

  +isExcluded?: boolean,

Whether the resolved file should be excluded from the build.

  +priority?: DependencyPriority,

Overrides the priority set on the dependency.

  +sideEffects?: boolean,

Corresponds to BaseAsset's sideEffects.

  +code?: string,

The code of the resolved asset. If provided, this is used rather than reading the file from disk.

  +canDefer?: boolean,

Whether this dependency can be deferred by Parcel itself (true by default).

  +diagnostics?: Diagnostic | Array<Diagnostic>,

A resolver might return diagnostics to also run subsequent resolvers while still providing a reason why it failed.

  +meta?: JSONObject,

Is spread (shallowly merged) onto the request's dependency.meta

  +invalidateOnFileCreate?: Array<FileCreateInvalidation>,

A list of file paths or patterns that should invalidate the resolution if created.

  +invalidateOnFileChange?: Array<FilePath>,

A list of files that should invalidate the resolution if modified or deleted.

  +invalidateOnEnvChange?: Array<string>,

Invalidates the resolution when the given environment variable changes.

|}
Referenced by:
Resolver

Resolver parcel/packages/core/types/index.js:1723

type Resolver<ConfigType> = {|
  loadConfig?: ({|
    config: Config,
    options: PluginOptions,
    logger: PluginLogger,
  |}) => Promise<ConfigType> | ConfigType,
  resolve({|
    dependency: Dependency,
    options: PluginOptions,
    logger: PluginLogger,
    specifier: FilePath,
    pipeline: ?string,
    config: ConfigType,
  |}): Async<?ResolveResult>,
|}