Appearance
插件开发
插件概述
¥Plugins Overview
Rollup 插件是一个具有下面描述的 特性、构建钩子 和 输出生成钩子 中的一个或多个的对象,它遵循我们的 惯例。插件应该作为包分发,该包导出可以使用插件特定选项调用的函数并返回这样的对象。
¥A Rollup plugin is an object with one or more of the properties, build hooks, and output generation hooks described below, and which follows our conventions. A plugin should be distributed as a package which exports a function that can be called with plugin specific options and returns such an object.
插件允许你自定义 Rollup 的行为,例如,在打包之前转译代码,或者在 node_modules
文件夹中查找第三方模块。有关如何使用它们的示例,请参阅 使用插件。
¥Plugins allow you to customise Rollup's behaviour by, for example, transpiling code before bundling, or finding third-party modules in your node_modules
folder. For an example on how to use them, see Using plugins.
插件列表可以在 github.com/rollup/awesome 找到。如果你想对插件提出建议,请提交 Pull Request。
¥A List of Plugins may be found at github.com/rollup/awesome. If you would like to make a suggestion for a plugin, please submit a Pull Request.
一个简单的例子
¥A Simple Example
以下插件将拦截 virtual-module
的任何导入,而无需访问文件系统。例如,如果你想在浏览器中使用 Rollup,这是必要的。它甚至可以用来替换入口点,如示例所示。
¥The following plugin will intercept any imports of virtual-module
without accessing the file system. This is for instance necessary if you want to use Rollup in a browser. It can even be used to replace entry points as shown in the example.
js
// @filename: rollup-plugin-my-example.js
export default function myExample () {
return {
name: 'my-example', // this name will show up in logs and errors
resolveId ( source ) {
if (source === 'virtual-module') {
// this signals that Rollup should not ask other plugins or check
// the file system to find this id
return source;
}
return null; // other ids should be handled as usually
},
load ( id ) {
if (id === 'virtual-module') {
// the source code for "virtual-module"
return 'export default "This is virtual!"';
}
return null; // other ids should be handled as usually
}
};
}
// @filename: rollup.config.js
import myExample from './rollup-plugin-my-example.js';
export default ({
input: 'virtual-module', // resolved by our plugin
plugins: [myExample()],
output: [{
file: 'bundle.js',
format: 'es'
}]
});
惯例
¥Conventions
插件应该有一个明确的名称,并带有
rollup-plugin-
前缀。¥Plugins should have a clear name with
rollup-plugin-
prefix.在
package.json
中包含rollup-plugin
关键字。¥Include
rollup-plugin
keyword inpackage.json
.应该测试插件。我们推荐 Mocha 或 艾娃,它们支持开箱即用的 Promise。
¥Plugins should be tested. We recommend mocha or ava which support Promises out of the box.
尽可能使用异步方法,例如
fs.readFile
而不是fs.readFileSync
。¥Use asynchronous methods when it is possible, e.g.
fs.readFile
instead offs.readFileSync
.用英语记录你的插件。
¥Document your plugin in English.
如果适用,请确保你的插件输出正确的源映射。
¥Make sure your plugin outputs correct source mappings if appropriate.
如果你的插件使用 '虚拟模块'(例如用于辅助函数),请在模块 ID 前添加
\0
前缀。这可以防止其他插件尝试处理它。¥If your plugin uses 'virtual modules' (e.g. for helper functions), prefix the module ID with
\0
. This prevents other plugins from trying to process it.
属性
¥Properties
name
类型: | string |
---|
插件的名称,用于错误消息和日志。
¥The name of the plugin, for use in error messages and logs.
version
类型: | string |
---|
插件的版本,用于插件间通信场景。
¥The version of the plugin, for use in inter-plugin communication scenarios.
构建钩子
¥Build Hooks
为了与构建过程进行交互,你的插件对象包括 "钩子"。钩子是在构建的各个阶段调用的函数。钩子可以影响构建的运行方式、提供有关构建的信息或在构建完成后修改构建。有不同种类的钩子:
¥To interact with the build process, your plugin object includes "hooks". Hooks are functions which are called at various stages of the build. Hooks can affect how a build is run, provide information about a build, or modify a build once complete. There are different kinds of hooks:
async
:钩子还可以返回解析为相同类型值的 Promise;否则,该钩子标记为sync
。¥
async
: The hook may also return a Promise resolving to the same type of value; otherwise, the hook is marked assync
.first
:如果多个插件实现此钩子,则钩子将按顺序运行,直到钩子返回null
或undefined
以外的值。¥
first
: If several plugins implement this hook, the hooks are run sequentially until a hook returns a value other thannull
orundefined
.sequential
:如果多个插件实现了此钩子,则所有插件都将按照指定的插件顺序运行。如果某个钩子是async
,则此类后续钩子将等待,直到当前钩子被解析。¥
sequential
: If several plugins implement this hook, all of them will be run in the specified plugin order. If a hook isasync
, subsequent hooks of this kind will wait until the current hook is resolved.parallel
:如果多个插件实现了此钩子,则所有插件都将按照指定的插件顺序运行。如果一个钩子是async
,则后续的此类钩子将并行运行,而不等待当前的钩子。¥
parallel
: If several plugins implement this hook, all of them will be run in the specified plugin order. If a hook isasync
, subsequent hooks of this kind will be run in parallel and not wait for the current hook.
钩子不仅可以是函数,还可以是对象。在这种情况下,实际的钩子函数(或 banner/footer/intro/outro
的值)必须指定为 handler
。这允许你提供更改钩子执行的附加可选属性:
¥Instead of a function, hooks can also be objects. In that case, the actual hook function (or value for banner/footer/intro/outro
) must be specified as handler
. This allows you to provide additional optional properties that change hook execution:
order: "pre" | "post" | null
如果有多个插件实现此钩子,则首先运行此插件("pre"
),最后运行此插件("post"
),或在用户指定的位置(无值或null
)运行此插件。¥
order: "pre" | "post" | null
If there are several plugins implementing this hook, either run this plugin first ("pre"
), last ("post"
), or in the user-specified position (no value ornull
).jsexport default function
resolveFirst() { return {name: 'resolve-first',resolveId: {order: 'pre',handler(source) { if (source=== 'external') { return {id:source,external: true }; } return null; } } }; }如果多个插件使用
"pre"
或"post"
,Rollup 会按照用户指定的顺序运行它们。该选项可用于所有插件钩子。对于并行钩子,它会更改钩子同步部分的运行顺序。¥If several plugins use
"pre"
or"post"
, Rollup runs them in the user-specified order. This option can be used for all plugin hooks. For parallel hooks, it changes the order in which the synchronous part of the hook is run.sequential: boolean
不要与其他插件的同一钩子并行运行此钩子。只能用于parallel
钩子。使用此选项将使 Rollup 等待所有先前插件的结果,然后执行插件钩子,然后再次并行运行其余插件。例如。当你有插件A
、B
、C
、D
、E
都实现相同的并行钩子并且中间插件C
有sequential: true
时,Rollup 将首先并行运行A + B
,然后单独运行C
,然后并行运行D + E
。¥
sequential: boolean
Do not run this hook in parallel with the same hook of other plugins. Can only be used forparallel
hooks. Using this option will make Rollup await the results of all previous plugins, then execute the plugin hook, and then run the remaining plugins in parallel again. E.g. when you have pluginsA
,B
,C
,D
,E
that all implement the same parallel hook and the middle pluginC
hassequential: true
, then Rollup will first runA + B
in parallel, thenC
on its own, thenD + E
in parallel.当你需要在相互依赖的不同
writeBundle
钩子中运行多个命令行工具时,这可能很有用(请注意,如果可能,建议在顺序generateBundle
钩子中添加/删除文件,不过,速度更快,可以与 纯内存构建并允许其他内存构建插件查看文件)。你可以将此选项与order
结合使用以进行额外排序。¥This can be useful when you need to run several command line tools in different
writeBundle
hooks that depend on each other (note that if possible, it is recommended to add/remove files in the sequentialgenerateBundle
hook, though, which is faster, works with pure in-memory builds and permits other in-memory build plugins to see the files). You can combine this option withorder
for additional sorting.jsimport
pathfrom 'node:path'; import {readdir} from 'node:fs/promises'; export default functiongetFilesOnDisk() { return {name: 'getFilesOnDisk',writeBundle: {sequential: true,order: 'post', asynchandler({dir}) { consttopLevelFiles= awaitreaddir(path.resolve(dir));console.log(topLevelFiles); } } }; }
构建钩子在构建阶段运行,由 rollup.rollup(inputOptions)
触发。它们主要关注在 Rollup 处理输入文件之前对其进行定位、提供和转换。构建阶段的第一个钩子是 options
,最后一个钩子始终是 buildEnd
。如果出现构建错误,则之后将调用 closeBundle
。
¥Build hooks are run during the build phase, which is triggered by rollup.rollup(inputOptions)
. They are mainly concerned with locating, providing and transforming input files before they are processed by Rollup. The first hook of the build phase is options
, the last one is always buildEnd
. If there is a build error, closeBundle
will be called after that.
parallel
sequential
first
async
sync
此外,在监视模式下,可以随时触发 watchChange
钩子,以通知当前运行生成输出后将触发新的运行。另外,当观察者关闭时,closeWatcher
钩子将被触发。
¥Additionally, in watch mode the watchChange
hook can be triggered at any time to notify a new run will be triggered once the current run has generated its outputs. Also, when watcher closes, the closeWatcher
hook will be triggered.
请参阅 输出生成钩子 了解在输出生成阶段运行以修改生成的输出的钩子。
¥See Output Generation Hooks for hooks that run during the output generation phase to modify the generated output.
buildEnd
类型: | (error?: Error) => void |
---|---|
种类: | 异步、并行 |
以前的: | moduleParsed 、resolveId 或 resolveDynamicImport |
下一个: | outputOptions 在输出生成阶段,因为这是构建阶段的最后一个钩子 |
当 Rollup 完成打包后,但在调用 generate
或 write
之前调用;你也可以返回一个 Promise。如果构建期间发生错误,则会将其传递到此钩子。
¥Called when Rollup has finished bundling, but before generate
or write
is called; you can also return a Promise. If an error occurred during the build, it is passed on to this hook.
buildStart
类型: | (options: InputOptions) => void |
---|---|
种类: | 异步、并行 |
以前的: | options |
下一个: | resolveId 并行解析每个入口点 |
在每个 rollup.rollup
版本上调用。当你需要访问传递给 rollup.rollup()
的选项时,建议使用此钩子,因为它考虑了所有 options
钩子的转换,并且还包含未设置选项的正确默认值。
¥Called on each rollup.rollup
build. This is the recommended hook to use when you need access to the options passed to rollup.rollup()
as it takes the transformations by all options
hooks into account and also contains the right default values for unset options.
closeWatcher
类型: | () => void |
---|---|
种类: | 异步、并行 |
上一页/下一页: | 在构建和输出生成阶段,可以随时触发该钩子。如果是这种情况,当前构建仍将继续,但不会触发新的 watchChange 事件 |
当观察程序进程将关闭时通知插件,以便所有打开的资源也可以关闭。如果返回 Promise,Rollup 将等待 Promise 解析后再关闭流程。输出插件不能使用此钩子。
¥Notifies a plugin when the watcher process will close so that all open resources can be closed too. If a Promise is returned, Rollup will wait for the Promise to resolve before closing the process. This hook cannot be used by output plugins.
load
类型: | (id: string) => LoadResult |
---|---|
种类: | 异步,首先 |
以前的: | 解析加载的 id 的 resolveId 或 resolveDynamicImport 。此外,通过调用 this.load 来预加载与 id 对应的模块,可以随时从插件钩子触发此钩子 |
下一个: | 如果没有使用缓存,或者没有具有相同 code 的缓存副本,则 transform 转换加载的文件,否则 shouldTransformCachedModule |
typescript
type LoadResult = string | null | SourceDescription;
interface SourceDescription {
code: string;
map?: string | SourceMap;
ast?: ESTree.Program;
attributes?: { [key: string]: string } | null;
meta?: { [plugin: string]: any } | null;
moduleSideEffects?: boolean | 'no-treeshake' | null;
syntheticNamedExports?: boolean | string | null;
}
定义自定义加载程序。返回 null
遵循其他 load
函数(最终是从文件系统加载的默认行为)。为了防止额外的解析开销,例如 由于某种原因,该钩子已使用 this.parse
生成 AST,该钩子可以选择返回 { code, ast, map }
对象。ast
必须是标准 ESTree AST,每个节点具有 start
和 end
属性。如果转换不移动代码,你可以通过将 map
设置为 null
来保留现有源映射。否则,你可能需要生成源映射。请参阅有关 源代码转换 的部分。
¥Defines a custom loader. Returning null
defers to other load
functions (and eventually the default behavior of loading from the file system). To prevent additional parsing overhead in case e.g. this hook already used this.parse
to generate an AST for some reason, this hook can optionally return a { code, ast, map }
object. The ast
must be a standard ESTree AST with start
and end
properties for each node. If the transformation does not move code, you can preserve existing sourcemaps by setting map
to null
. Otherwise, you might need to generate the source map. See the section on source code transformations.
如果为 moduleSideEffects
返回 false
并且没有其他模块从该模块导入任何内容,则该模块将不会包含在打包包中,即使该模块会产生副作用。如果返回 true
,Rollup 将使用其默认算法来包含模块中具有副作用(例如修改全局或导出变量)的所有语句。如果返回 "no-treeshake"
,则该模块的 treeshaking 将被关闭,并且它也将包含在生成的块之一中,即使它是空的。如果返回 null
或省略标志,则 moduleSideEffects
将由解析此模块的第一个 resolveId
钩子、treeshake.moduleSideEffects
选项确定,或最终默认为 true
。transform
钩子可以覆盖它。
¥If false
is returned for moduleSideEffects
and no other module imports anything from this module, then this module will not be included in the bundle even if the module would have side effects. If true
is returned, Rollup will use its default algorithm to include all statements in the module that have side effects (such as modifying a global or exported variable). If "no-treeshake"
is returned, treeshaking will be turned off for this module and it will also be included in one of the generated chunks even if it is empty. If null
is returned or the flag is omitted, then moduleSideEffects
will be determined by the first resolveId
hook that resolved this module, the treeshake.moduleSideEffects
option, or eventually default to true
. The transform
hook can override this.
attributes
包含导入此模块时使用的导入属性。目前,它们不影响打包模块的渲染,而是用于文档目的。如果返回 null
或省略该标志,则 attributes
将由解析此模块的第一个 resolveId
钩子或此模块的第一次导入中存在的属性确定。transform
钩子可以覆盖它。
¥attributes
contain the import attributes that were used when this module was imported. At the moment, they do not influence rendering for bundled modules but rather serve documentation purposes. If null
is returned or the flag is omitted, then attributes
will be determined by the first resolveId
hook that resolved this module, or the attributes present in the first import of this module. The transform
hook can override this.
请参阅 合成命名导出 了解 syntheticNamedExports
选项的效果。如果返回 null
或省略标志,则 syntheticNamedExports
将由解析此模块的第一个 resolveId
钩子确定,或最终默认为 false
。transform
钩子可以覆盖它。
¥See synthetic named exports for the effect of the syntheticNamedExports
option. If null
is returned or the flag is omitted, then syntheticNamedExports
will be determined by the first resolveId
hook that resolved this module or eventually default to false
. The transform
hook can override this.
请参阅 自定义模块元数据 了解如何使用 meta
选项。如果此钩子返回 meta
对象,它将与 resolveId 钩子返回的任何 meta
对象进行浅层合并。如果没有钩子返回 meta
对象,它将默认为空对象。transform
钩子可以进一步添加或替换该对象的属性。
¥See custom module meta-data for how to use the meta
option. If a meta
object is returned by this hook, it will be merged shallowly with any meta
object returned by the resolveId hook. If no hook returns a meta
object it will default to an empty object. The transform
hook can further add or replace properties of this object.
你可以使用 this.getModuleInfo
找出该钩子中 attributes
、meta
、moduleSideEffects
和 syntheticNamedExports
的先前值。
¥You can use this.getModuleInfo
to find out the previous values of attributes
, meta
, moduleSideEffects
and syntheticNamedExports
inside this hook.
moduleParsed
类型: | (moduleInfo: ModuleInfo) => void |
---|---|
种类: | 异步、并行 |
以前的: | 当前处理的文件被转换的 transform |
下一个: | resolveId 和 resolveDynamicImport 并行解析所有发现的静态和动态导入(如果存在),否则 buildEnd |
每次 Rollup 完全解析模块时都会调用此钩子。请参阅 this.getModuleInfo
了解传递给此钩子的信息。
¥This hook is called each time a module has been fully parsed by Rollup. See this.getModuleInfo
for what information is passed to this hook.
与 transform
钩子相比,此钩子从不缓存,可用于获取有关缓存模块和其他模块的信息,包括 meta
属性、code
和 ast
的最终形状。
¥In contrast to the transform
hook, this hook is never cached and can be used to get information about both cached and other modules, including the final shape of the meta
property, the code
and the ast
.
该钩子将等到所有导入都得到解决,以便 moduleInfo.importedIds
、moduleInfo.dynamicallyImportedIds
、moduleInfo.importedIdResolutions
和 moduleInfo.dynamicallyImportedIdResolutions
中的信息完整且准确。但请注意,有关导入模块的信息可能不完整,因为稍后可能会发现其他导入程序。如果你需要此信息,请使用 buildEnd
钩子。
¥This hook will wait until all imports are resolved so that the information in moduleInfo.importedIds
, moduleInfo.dynamicallyImportedIds
, moduleInfo.importedIdResolutions
, and moduleInfo.dynamicallyImportedIdResolutions
is complete and accurate. Note however that information about importing modules may be incomplete as additional importers could be discovered later. If you need this information, use the buildEnd
hook.
onLog
类型: | (level: LogLevel, log: RollupLog) => boolean | null |
---|---|
种类: | 同步、顺序 |
上一页/下一页: | 该钩子可以随时触发。 |
有关可用的 Loglevel
值和 RollupLog
类型,请参阅 onLog
选项。
¥See the onLog
option for the available Loglevel
values and the RollupLog
type.
一个函数,用于接收和过滤由 Rollup 和插件生成的日志和警告,然后将其传递到 onLog
选项或打印到控制台。
¥A function that receives and filters logs and warnings generated by Rollup and plugins before they are passed to the onLog
option or printed to the console.
如果从此钩子返回 false
,则日志将被过滤。否则,日志将被交给下一个插件的 onLog
钩子,onLog
选项,或者打印到控制台。插件还可以通过将日志传递给 this.error
、this.warn
、this.info
或 this.debug
并返回 false
来更改日志的日志级别或将日志变为错误。请注意,与其他添加例如的插件钩子不同 将插件名称添加到日志中,这些函数不会添加或更改日志的属性。此外,onLog
钩子生成的日志不会传递回同一插件的 onLog
钩子。如果另一个插件在其自己的 onLog
钩子中生成一条日志来响应此类日志,则该日志也不会传递到原始 onLog
钩子。
¥If false
is returned from this hook, the log will be filtered. Otherwise, the log will be handed to the onLog
hook of the next plugin, the onLog
option, or printed to the console. Plugins can also change the log level of a log or turn a log into an error by passing the log to this.error
, this.warn
, this.info
or this.debug
and returning false
. Note that unlike other plugin hooks that add e.g. the plugin name to the log, those functions will not add or change properties of the log. Additionally, logs generated by an onLog
hook will not be passed back to the onLog
hook of the same plugin. If another plugin generates a log in response to such a log in its own onLog
hook, this log will not be passed to the original onLog
hook, either.
js
function plugin1() {
return {
name: 'plugin1',
buildStart() {
this.info({ message: 'Hey', pluginCode: 'SPECIAL_CODE' });
},
onLog(level, log) {
if (log.plugin === 'plugin1' && log.pluginCode === 'SPECIAL_CODE') {
// We turn logs into warnings based on their code. This warnings
// will not be passed back to the same plugin to avoid an
// infinite loop, but other plugins will still receive it.
this.warn(log);
return false;
}
}
};
}
function plugin2() {
return {
name: 'plugin2',
onLog(level, log) {
if (log.plugin === 'plugin1' && log.pluginCode === 'SPECIAL_CODE') {
// You can modify logs in this hooks as well
log.meta = 'processed by plugin 2';
// This turns the log back to "info". If this happens in
// response to the first plugin, it will not be passed back to
// either plugin to avoid an infinite loop. If both plugins are
// active, the log will be an info log if the second plugin is
// placed after the first one
this.info(log);
return false;
}
}
};
}
与 options
钩子一样,此钩子无法访问大多数 插件上下文 实用程序函数,因为它可能在 Rollup 完全配置之前运行。唯一支持的属性是 this.meta
以及用于日志记录和错误的 this.error
、this.warn
、this.info
和 this.debug
。
¥Like the options
hook, this hook does not have access to most plugin context utility functions as it may be run before Rollup is fully configured. The only supported properties are this.meta
as well as this.error
, this.warn
, this.info
and this.debug
for logging and errors.
options
类型: | (options: InputOptions) => InputOptions | null |
---|---|
种类: | 异步、顺序 |
以前的: | 这是构建阶段的第一个钩子 |
下一个: | buildStart |
替换或操作传递给 rollup.rollup
的选项对象。返回 null
不会替代任何内容。如果你只需要读取选项,建议使用 buildStart
钩子,因为在考虑所有 options
钩子的转换后,该钩子可以访问选项。
¥Replaces or manipulates the options object passed to rollup.rollup
. Returning null
does not replace anything. If you just need to read the options, it is recommended to use the buildStart
hook as that hook has access to the options after the transformations from all options
hooks have been taken into account.
与 onLog
钩子一样,该钩子无法访问大多数 插件上下文 实用程序函数,因为它是在 Rollup 完全配置之前运行的。唯一支持的属性是 this.meta
以及用于日志记录和错误的 this.error
、this.warn
、this.info
和 this.debug
。
¥Like the onLog
hook, this hook does not have access to most plugin context utility functions as it is run before Rollup is fully configured. The only supported properties are this.meta
as well as this.error
, this.warn
, this.info
and this.debug
for logging and errors.
resolveDynamicImport
类型: | ResolveDynamicImportHook |
---|---|
种类: | 异步,首先 |
以前的: | moduleParsed 为导入文件 |
下一个: | 如果钩子使用尚未加载的 id 进行解析,则为 load ;如果动态导入包含字符串并且钩子未解析,则为 resolveId ;否则为 buildEnd |
typescript
type ResolveDynamicImportHook = (
specifier: string | AstNode,
importer: string,
options: { attributes: Record<string, string> }
) => ResolveIdResult;
提示
返回类型 ResolveIdResult 与 resolveId
钩子的返回类型相同。
¥The return type ResolveIdResult is the same as that of the resolveId
hook.
定义动态导入的自定义解析器。返回 false
表示导入应保持原样,而不是传递给其他解析器,从而使其成为外部的。与 resolveId
钩子类似,你也可以返回一个对象来解析导入到不同的 id,同时将其标记为外部。
¥Defines a custom resolver for dynamic imports. Returning false
signals that the import should be kept as it is and not be passed to other resolvers thus making it external. Similar to the resolveId
hook, you can also return an object to resolve the import to a different id while marking it as external at the same time.
attributes
告诉你导入中存在哪些导入属性。IE。import("foo", {assert: {type: "json"}})
将传递 attributes: {type: "json"}
。
¥attributes
tells you which import attributes were present in the import. I.e. import("foo", {assert: {type: "json"}})
will pass along attributes: {type: "json"}
.
如果动态导入传递一个字符串作为参数,则从此钩子返回的字符串将被解释为现有模块 id,同时返回 null
将遵循其他解析器并最终遵循 resolveId
。
¥In case a dynamic import is passed a string as argument, a string returned from this hook will be interpreted as an existing module id while returning null
will defer to other resolvers and eventually to resolveId
.
如果动态导入未传递字符串作为参数,则此钩子可以访问原始 AST 节点进行分析,并且在以下方面表现略有不同:
¥In case a dynamic import is not passed a string as argument, this hook gets access to the raw AST nodes to analyze and behaves slightly different in the following ways:
如果所有插件都返回
null
,则导入将被视为external
,且不会触发警告。¥If all plugins return
null
, the import is treated asexternal
without a warning.如果返回一个字符串,则该字符串不会解释为模块 ID,而是用作导入参数的替换。插件有责任确保生成的代码有效。
¥If a string is returned, this string is not interpreted as a module id but is instead used as a replacement for the import argument. It is the responsibility of the plugin to make sure the generated code is valid.
要解决对现有模块的此类导入,你仍然可以返回对象
{id, external}
。¥To resolve such an import to an existing module, you can still return an object
{id, external}
.
注意这个 hook 的返回值之后不会传递给 resolveId
;如果你需要访问静态解析算法,你可以在插件上下文中使用 this.resolve(source, importer)
。
¥Note that the return value of this hook will not be passed to resolveId
afterwards; if you need access to the static resolution algorithm, you can use this.resolve(source, importer)
on the plugin context.
resolveId
类型: | ResolveIdHook |
---|---|
种类: | 异步,首先 |
以前的: | 如果我们正在解析入口点,则为 buildStart ;如果我们正在解析导入,则为 moduleParsed ;或者作为 resolveDynamicImport 的后备。此外,可以在插件钩子的构建阶段通过调用 this.emitFile 触发入口点或随时通过调用 this.resolve 手动解析 id 来触发此钩子 |
下一个: | 如果解析的 id 尚未加载,则为 load ,否则为 buildEnd |
typescript
type ResolveIdHook = (
source: string,
importer: string | undefined,
options: {
attributes: Record<string, string>;
custom?: { [plugin: string]: any };
isEntry: boolean;
}
) => ResolveIdResult;
type ResolveIdResult = string | null | false | PartialResolvedId;
interface PartialResolvedId {
id: string;
external?: boolean | 'absolute' | 'relative';
attributes?: Record<string, string> | null;
meta?: { [plugin: string]: any } | null;
moduleSideEffects?: boolean | 'no-treeshake' | null;
resolvedBy?: string | null;
syntheticNamedExports?: boolean | string | null;
}
定义自定义解析器。解析器可用于例如 定位第三方依赖。这里 source
是导入者,与导入语句中所写的完全相同,即 for
¥Defines a custom resolver. A resolver can be useful for e.g. locating third-party dependencies. Here source
is the importee exactly as it is written in the import statement, i.e. for
js
import { foo } from '../bar.js';
源将是 "../bar.js"
。
¥the source will be "../bar.js"
.
importer
是导入模块的完全解析 ID。解析入口点时,导入商通常是 undefined
。这里的一个例外是通过 this.emitFile
生成的入口点,你可以提供 importer
参数。
¥The importer
is the fully resolved id of the importing module. When resolving entry points, importer will usually be undefined
. An exception here are entry points generated via this.emitFile
as here, you can provide an importer
argument.
对于这些情况,isEntry
选项将告诉你我们是否正在解析用户定义的入口点、触发的块,或者是否为 this.resolve
上下文函数提供了 isEntry
参数。
¥For those cases, the isEntry
option will tell you if we are resolving a user defined entry point, an emitted chunk, or if the isEntry
parameter was provided for the this.resolve
context function.
例如,你可以使用它作为为入口点定义自定义代理模块的机制。以下插件将代理所有入口点以注入 polyfill 导入。
¥You can use this for instance as a mechanism to define custom proxy modules for entry points. The following plugin will proxy all entry points to inject a polyfill import.
js
// We prefix the polyfill id with \0 to tell other plugins not to try to load or
// transform it
const POLYFILL_ID = '\0polyfill';
const PROXY_SUFFIX = '?inject-polyfill-proxy';
function injectPolyfillPlugin() {
return {
name: 'inject-polyfill',
async resolveId(source, importer, options) {
if (source === POLYFILL_ID) {
// It is important that side effects are always respected
// for polyfills, otherwise using
// "treeshake.moduleSideEffects: false" may prevent the
// polyfill from being included.
return { id: POLYFILL_ID, moduleSideEffects: true };
}
if (options.isEntry) {
// Determine what the actual entry would have been.
const resolution = await this.resolve(source, importer, options);
// If it cannot be resolved or is external, just return it
// so that Rollup can display an error
if (!resolution || resolution.external) return resolution;
// In the load hook of the proxy, we need to know if the
// entry has a default export. There, however, we no longer
// have the full "resolution" object that may contain
// meta-data from other plugins that is only added on first
// load. Therefore we trigger loading here.
const moduleInfo = await this.load(resolution);
// We need to make sure side effects in the original entry
// point are respected even for
// treeshake.moduleSideEffects: false. "moduleSideEffects"
// is a writable property on ModuleInfo.
moduleInfo.moduleSideEffects = true;
// It is important that the new entry does not start with
// \0 and has the same directory as the original one to not
// mess up relative external import generation. Also
// keeping the name and just adding a "?query" to the end
// ensures that preserveModules will generate the original
// entry name for this entry.
return `${resolution.id}${PROXY_SUFFIX}`;
}
return null;
},
load(id) {
if (id === POLYFILL_ID) {
// Replace with actual polyfill
return "console.log('polyfill');";
}
if (id.endsWith(PROXY_SUFFIX)) {
const entryId = id.slice(0, -PROXY_SUFFIX.length);
// We know ModuleInfo.hasDefaultExport is reliable because
// we awaited this.load in resolveId
const { hasDefaultExport } = this.getModuleInfo(entryId);
let code =
`import ${JSON.stringify(POLYFILL_ID)};` +
`export * from ${JSON.stringify(entryId)};`;
// Namespace reexports do not reexport default, so we need
// special handling here
if (hasDefaultExport) {
code += `export { default } from ${JSON.stringify(entryId)};`;
}
return code;
}
return null;
}
};
}
attributes
告诉你导入中存在哪些导入属性。IE。import "foo" assert {type: "json"}
将传递 attributes: {type: "json"}
。
¥attributes
tells you which import attributes were present in the import. I.e. import "foo" assert {type: "json"}
will pass along attributes: {type: "json"}
.
返回 null
会遵循其他 resolveId
函数,并最终遵循默认的解析行为。返回 false
表示 source
应被视为外部模块并且不包含在打包包中。如果相对导入发生这种情况,则 id 将按照与使用 external
选项时相同的方式重新规范化。
¥Returning null
defers to other resolveId
functions and eventually the default resolution behavior. Returning false
signals that source
should be treated as an external module and not included in the bundle. If this happens for a relative import, the id will be renormalized the same way as when the external
option is used.
如果返回一个对象,则可以解析对不同 id 的导入,同时将其从包中排除。这允许你用外部依赖替换依赖,而无需用户通过 external
选项手动将它们标记为 "external":
¥If you return an object, then it is possible to resolve an import to a different id while excluding it from the bundle at the same time. This allows you to replace dependencies with external dependencies without the need for the user to mark them as "external" manually via the external
option:
js
function externalizeDependencyPlugin() {
return {
name: 'externalize-dependency',
resolveId(source) {
if (source === 'my-dependency') {
return { id: 'my-dependency-develop', external: true };
}
return null;
}
};
}
如果 external
是 true
,则绝对 id 将根据用户对 makeAbsoluteExternalsRelative
选项的选择转换为相对 id。可以通过传递 external: "relative"
来始终将绝对 id 转换为相对 id 或传递 external: "absolute"
来将其保留为绝对 id 来覆盖此选择。返回对象时,相对外部 id(即以 ./
或 ../
开头的 id)不会在内部转换为绝对 id 并在输出中转换回相对 id,而是原封不动地包含在输出中。如果你希望重新规范化相对 ID 并进行数据去重,请将绝对文件系统位置返回为 id
并选择 external: "relative"
。
¥If external
is true
, then absolute ids will be converted to relative ids based on the user's choice for the makeAbsoluteExternalsRelative
option. This choice can be overridden by passing either external: "relative"
to always convert an absolute id to a relative id or external: "absolute"
to keep it as an absolute id. When returning an object, relative external ids, i.e. ids starting with ./
or ../
, will not be internally converted to an absolute id and converted back to a relative id in the output, but are instead included in the output unchanged. If you want relative ids to be renormalised and deduplicated instead, return an absolute file system location as id
and choose external: "relative"
.
如果在解析模块 ID 的第一个钩子中为 moduleSideEffects
返回 false
,并且没有其他模块从该模块导入任何内容,则即使该模块有副作用,也不会包含该模块。如果返回 true
,Rollup 将使用其默认算法来包含模块中具有副作用(例如修改全局或导出变量)的所有语句。如果返回 "no-treeshake"
,则该模块的 treeshaking 将被关闭,并且它也将包含在生成的块之一中,即使它是空的。如果返回 null
或省略该标志,则 moduleSideEffects
将由 treeshake.moduleSideEffects
选项确定或默认为 true
。load
和 transform
钩子可以覆盖它。
¥If false
is returned for moduleSideEffects
in the first hook that resolves a module id and no other module imports anything from this module, then this module will not be included even if the module would have side effects. If true
is returned, Rollup will use its default algorithm to include all statements in the module that have side effects (such as modifying a global or exported variable). If "no-treeshake"
is returned, treeshaking will be turned off for this module and it will also be included in one of the generated chunks even if it is empty. If null
is returned or the flag is omitted, then moduleSideEffects
will be determined by the treeshake.moduleSideEffects
option or default to true
. The load
and transform
hooks can override this.
resolvedBy
可以在返回的对象中显式声明。它将替换 this.resolve
返回的相应字段。
¥resolvedBy
can be explicitly declared in the returned object. It will replace the corresponding field returned by this.resolve
.
如果你为外部模块返回 attributes
的值,这将确定在生成 "es"
输出时如何渲染该模块的导入。例如。{id: "foo", external: true, attributes: {type: "json"}}
将导致该模块的导入显示为 import "foo" assert {type: "json"}
。如果不传递值,则将使用 attributes
输入参数的值。传递一个空对象以删除任何属性。虽然 attributes
不影响打包模块的渲染,但它们仍然需要在模块的所有导入中保持一致,否则会触发警告。load
和 transform
钩子可以覆盖它。
¥If you return a value for attributes
for an external module, this will determine how imports of this module will be rendered when generating "es"
output. E.g. {id: "foo", external: true, attributes: {type: "json"}}
will cause imports of this module appear as import "foo" assert {type: "json"}
. If you do not pass a value, the value of the attributes
input parameter will be used. Pass an empty object to remove any attributes. While attributes
do not influence rendering for bundled modules, they still need to be consistent across all imports of a module, otherwise a warning is emitted. The load
and transform
hooks can override this.
请参阅 合成命名导出 了解 syntheticNamedExports
选项的效果。如果返回 null
或省略该标志,则 syntheticNamedExports
将默认为 false
。load
和 transform
钩子可以覆盖它。
¥See synthetic named exports for the effect of the syntheticNamedExports
option. If null
is returned or the flag is omitted, then syntheticNamedExports
will default to false
. The load
and transform
hooks can override this.
请参阅 自定义模块元数据 了解如何使用 meta
选项。如果返回 null
或省略该选项,则 meta
将默认为空对象。load
和 transform
钩子可以添加或替换该对象的属性。
¥See custom module meta-data for how to use the meta
option. If null
is returned or the option is omitted, then meta
will default to an empty object. The load
and transform
hooks can add or replace properties of this object.
请注意,虽然每次导入模块时都会调用 resolveId
,因此可以多次解析为相同的 id
,但 external
、attributes
、meta
、moduleSideEffects
或 syntheticNamedExports
的值只能在加载模块之前设置一次。原因是,在此调用之后,Rollup 将继续使用该模块的 load
和 transform
钩子,这些钩子可能会覆盖这些值,并且如果它们这样做,则应优先考虑。
¥Note that while resolveId
will be called for each import of a module and can therefore resolve to the same id
many times, values for external
, attributes
, meta
, moduleSideEffects
or syntheticNamedExports
can only be set once before the module is loaded. The reason is that after this call, Rollup will continue with the load
and transform
hooks for that module that may override these values and should take precedence if they do so.
当通过 this.resolve
从插件触发此钩子时,可以将自定义选项对象传递给此钩子。虽然此对象将未经修改地传递,但插件应遵循向对象添加 custom
属性的约定,其中键对应于选项所针对的插件的名称。详情参见 自定义解析器选项。
¥When triggering this hook from a plugin via this.resolve
, it is possible to pass a custom options object to this hook. While this object will be passed unmodified, plugins should follow the convention of adding a custom
property with an object where the keys correspond to the names of the plugins that the options are intended for. For details see custom resolver options.
在监视模式下或显式使用缓存时,缓存模块的已解析导入也将从缓存中获取,并且不再通过 resolveId
钩子确定。为了防止这种情况,你可以从该模块的 shouldTransformCachedModule
钩子返回 true
。这将从缓存中删除模块及其导入解析并再次调用 transform
和 resolveId
。
¥In watch mode or when using the cache explicitly, the resolved imports of a cached module are also taken from the cache and not determined via the resolveId
hook again. To prevent this, you can return true
from the shouldTransformCachedModule
hook for that module. This will remove the module and its import resolutions from cache and call transform
and resolveId
again.
shouldTransformCachedModule
类型: | ShouldTransformCachedModuleHook |
---|---|
种类: | 异步,首先 |
以前的: | load 加载缓存文件以将其代码与缓存版本进行比较 |
下一个: | 如果没有插件则返回 moduleParsed ,否则返回 transform |
typescript
type ShouldTransformCachedModuleHook = (options: {
ast: AstNode;
code: string;
id: string;
meta: { [plugin: string]: any };
moduleSideEffects: boolean | 'no-treeshake';
syntheticNamedExports: boolean | string;
}) => boolean | NullValue;
如果使用 Rollup 缓存(例如,在监视模式下或显式通过 JavaScript API),如果在 load
钩子之后加载的 code
与缓存副本的代码相同,则 Rollup 将跳过模块的 transform
钩子。为了防止这种情况,请丢弃缓存的副本并转换模块,插件可以实现此钩子并返回 true
。
¥If the Rollup cache is used (e.g. in watch mode or explicitly via the JavaScript API), Rollup will skip the transform
hook of a module if after the load
hook, the loaded code
is identical to the code of the cached copy. To prevent this, discard the cached copy and instead transform a module, plugins can implement this hook and return true
.
该钩子还可用于查找缓存了哪些模块并访问其缓存的元信息。
¥This hook can also be used to find out which modules were cached and access their cached meta information.
如果插件不返回布尔值,Rollup 将为其他插件触发此钩子,否则将跳过所有剩余插件。
¥If a plugin does not return a boolean, Rollup will trigger this hook for other plugins, otherwise all remaining plugins will be skipped.
transform
类型: | (code: string, id: string) => TransformResult |
---|---|
种类: | 异步、顺序 |
以前的: | load 当前处理的文件被加载到的位置。如果使用缓存并且存在该模块的缓存副本,则 shouldTransformCachedModule 如果插件为该钩子返回 true |
下一个: | 文件处理和解析后 moduleParsed |
typescript
type TransformResult = string | null | Partial<SourceDescription>;
interface SourceDescription {
code: string;
map?: string | SourceMap;
ast?: ESTree.Program;
attributes?: { [key: string]: string } | null;
meta?: { [plugin: string]: any } | null;
moduleSideEffects?: boolean | 'no-treeshake' | null;
syntheticNamedExports?: boolean | string | null;
}
可用于改造各个模块。为了防止额外的解析开销,例如 由于某种原因,该钩子已使用 this.parse
生成 AST,该钩子可以选择返回 { code, ast, map }
对象。ast
必须是标准 ESTree AST,每个节点具有 start
和 end
属性。如果转换不移动代码,你可以通过将 map
设置为 null
来保留现有源映射。否则,你可能需要生成源映射。参见 源代码转换部分。
¥Can be used to transform individual modules. To prevent additional parsing overhead in case e.g. this hook already used this.parse
to generate an AST for some reason, this hook can optionally return a { code, ast, map }
object. The ast
must be a standard ESTree AST with start
and end
properties for each node. If the transformation does not move code, you can preserve existing sourcemaps by setting map
to null
. Otherwise, you might need to generate the source map. See the section on source code transformations.
请注意,在监视模式下或明确使用缓存时,此钩子的结果在重建时会被缓存,并且只有在模块的 code
发生更改或上次通过 this.addWatchFile
或 this.emitFile
添加的文件发生更改时,才会再次触发模块 id
的钩子。
¥Note that in watch mode or when using the cache explicitly, the result of this hook is cached when rebuilding and the hook is only triggered again for a module id
if either the code
of the module has changed or a file has changed that was added via this.addWatchFile
or this.emitFile
the last time the hook was triggered for this module.
在所有其他情况下,都会触发 shouldTransformCachedModule
钩子,从而可以访问缓存的模块。从 shouldTransformCachedModule
返回 true
将从缓存中删除该模块,并再次调用 transform
。
¥In all other cases, the shouldTransformCachedModule
hook is triggered instead, which gives access to the cached module. Returning true
from shouldTransformCachedModule
will remove the module from cache and instead call transform
again.
你还可以使用返回值的对象形式来配置模块的其他属性。请注意,可以仅返回属性而不返回代码转换。
¥You can also use the object form of the return value to configure additional properties of the module. Note that it's possible to return only properties and no code transformations.
如果为 moduleSideEffects
返回 false
并且没有其他模块从该模块导入任何内容,则即使该模块会产生副作用,也不会包含该模块。
¥If false
is returned for moduleSideEffects
and no other module imports anything from this module, then this module will not be included even if the module would have side effects.
如果返回 true
,Rollup 将使用其默认算法来包含模块中具有副作用(例如修改全局或导出变量)的所有语句。
¥If true
is returned, Rollup will use its default algorithm to include all statements in the module that have side effects (such as modifying a global or exported variable).
如果返回 "no-treeshake"
,则该模块的 treeshaking 将被关闭,并且它也将包含在生成的块之一中,即使它是空的。
¥If "no-treeshake"
is returned, treeshaking will be turned off for this module and it will also be included in one of the generated chunks even if it is empty.
如果返回 null
或省略该标志,则 moduleSideEffects
将由加载此模块的 load
钩子、解析此模块的第一个 resolveId
钩子、treeshake.moduleSideEffects
选项或最终默认为 true
确定。
¥If null
is returned or the flag is omitted, then moduleSideEffects
will be determined by the load
hook that loaded this module, the first resolveId
hook that resolved this module, the treeshake.moduleSideEffects
option, or eventually default to true
.
attributes
包含导入此模块时使用的导入属性。目前,它们不影响打包模块的渲染,而是用于文档目的。如果返回 null
或省略该标志,则 attributes
将由加载此模块的 load
钩子、解析此模块的第一个 resolveId
钩子或此模块的第一次导入中存在的属性确定。
¥attributes
contain the import attributes that were used when this module was imported. At the moment, they do not influence rendering for bundled modules but rather serve documentation purposes. If null
is returned or the flag is omitted, then attributes
will be determined by the load
hook that loaded this module, the first resolveId
hook that resolved this module, or the attributes present in the first import of this module.
请参阅 合成命名导出 了解 syntheticNamedExports
选项的效果。如果返回 null
或省略该标志,则 syntheticNamedExports
将由加载此模块的 load
钩子、解析此模块的第一个 resolveId
钩子、treeshake.moduleSideEffects
选项或最终默认为 false
确定。
¥See synthetic named exports for the effect of the syntheticNamedExports
option. If null
is returned or the flag is omitted, then syntheticNamedExports
will be determined by the load
hook that loaded this module, the first resolveId
hook that resolved this module, the treeshake.moduleSideEffects
option, or eventually default to false
.
请参阅 自定义模块元数据 了解如何使用 meta
选项。如果返回 null
或省略该选项,则 meta
将由加载此模块的 load
钩子、解析此模块的第一个 resolveId
钩子确定,或者最终默认为空对象。
¥See custom module meta-data for how to use the meta
option. If null
is returned or the option is omitted, then meta
will be determined by the load
hook that loaded this module, the first resolveId
hook that resolved this module or eventually default to an empty object.
你可以使用 this.getModuleInfo
找出该钩子中 attributes
、meta
、moduleSideEffects
和 syntheticNamedExports
的先前值。
¥You can use this.getModuleInfo
to find out the previous values of attributes
, meta
, moduleSideEffects
and syntheticNamedExports
inside this hook.
watchChange
类型: | watchChange: (id: string, change: {event: 'create' | 'update' | 'delete'}) => void |
---|---|
种类: | 异步、并行 |
上一页/下一页: | 在构建和输出生成阶段,可以随时触发该钩子。如果是这种情况,当前构建仍将继续,但一旦当前构建完成,将计划开始新的构建,并从 options 重新开始 |
每当 Rollup 在 --watch
模式下检测到受监控文件发生更改时通知插件。如果返回 Promise,Rollup 将等待 Promise 解析后再安排另一个构建。输出插件不能使用此钩子。第二个参数包含更改事件的其他详细信息。
¥Notifies a plugin whenever Rollup has detected a change to a monitored file in --watch
mode. If a Promise is returned, Rollup will wait for the Promise to resolve before scheduling another build. This hook cannot be used by output plugins. The second argument contains additional details of the change event.
输出生成钩子
¥Output Generation Hooks
输出生成钩子可以提供有关生成的包的信息,并在完成后修改构建。它们的工作方式与 构建钩子 相同,类型也相同,但每次调用 bundle.generate(outputOptions)
或 bundle.write(outputOptions)
时都会单独调用。仅使用输出生成钩子的插件也可以通过输出选项传递,因此仅针对某些输出运行。
¥Output generation hooks can provide information about a generated bundle and modify a build once complete. They work the same way and have the same types as Build Hooks but are called separately for each call to bundle.generate(outputOptions)
or bundle.write(outputOptions)
. Plugins that only use output generation hooks can also be passed in via the output options and therefore run only for certain outputs.
输出生成阶段的第一个钩子是 outputOptions
,最后一个钩子是 generateBundle
(如果通过 bundle.generate(...)
成功生成输出)、writeBundle
(如果通过 bundle.write(...)
成功生成输出)或 renderError
(如果在输出生成期间的任何时间发生错误)。
¥The first hook of the output generation phase is outputOptions
, the last one is either generateBundle
if the output was successfully generated via bundle.generate(...)
, writeBundle
if the output was successfully generated via bundle.write(...)
, or renderError
if an error occurred at any time during the output generation.
parallel
sequential
first
async
sync
此外,closeBundle
可以作为最后一个钩子调用,但用户有责任手动调用 bundle.close()
来触发此钩子。CLI 将始终确保情况确实如此。
¥Additionally, closeBundle
can be called as the very last hook, but it is the responsibility of the User to manually call bundle.close()
to trigger this. The CLI will always make sure this is the case.
augmentChunkHash
类型: | (chunkInfo: RenderedChunk) => string |
---|---|
种类: | 同步、顺序 |
以前的: | renderChunk |
下一个: | 如果还有其他块还需要处理则 renderChunk ,否则 generateBundle |
有关 RenderedChunk
类型,请参阅 renderChunk
钩子。
¥See the renderChunk
hook for the RenderedChunk
type.
可用于增强各个块的哈希值。为每个 Rollup 输出块调用。返回假值不会修改哈希值。真值将传递给 hash.update
。RenderedChunk
类型是 generateBundle
中 OutputChunk
类型的简化版本,没有 code
和 map
,并使用文件名中的哈希占位符。
¥Can be used to augment the hash of individual chunks. Called for each Rollup output chunk. Returning a falsy value will not modify the hash. Truthy values will be passed to hash.update
. The RenderedChunk
type is a reduced version of the OutputChunk
type in generateBundle
without code
and map
and using placeholders for hashes in file names.
以下插件将使带有当前时间戳的块 foo
的哈希值无效:
¥The following plugin will invalidate the hash of chunk foo
with the current timestamp:
js
function augmentWithDatePlugin() {
return {
name: 'augment-with-date',
augmentChunkHash(chunkInfo) {
if (chunkInfo.name === 'foo') {
return Date.now().toString();
}
}
};
}
banner
类型: | string | ((chunk: RenderedChunk) => string) |
---|---|
种类: | 异步、顺序 |
以前的: | resolveFileUrl 用于每次使用 import.meta.ROLLUP_FILE_URL_referenceId 和 resolveImportMeta 用于当前块中对 import.meta 的所有其他访问 |
下一个: | renderDynamicImport 代表下一个块中的每个动态导入表达式(如果有另一个动态导入表达式),否则 renderChunk 代表第一个块 |
比照。output.banner/output.footer
。
¥Cf. output.banner/output.footer
.
closeBundle
类型: | closeBundle: () => Promise<void> | void |
---|---|
种类: | 异步、并行 |
以前的: | buildEnd 如果存在构建错误,否则当调用 bundle.close() 时,在这种情况下这将是最后一个触发的钩子 |
可用于清理可能正在运行的任何外部服务。Rollup 的 CLI 将确保每次运行后都会调用此钩子,但 JavaScript API 用户有责任在生成打包包后手动调用 bundle.close()
。因此,任何依赖此功能的插件都应该在其文档中仔细提及这一点。
¥Can be used to clean up any external service that may be running. Rollup's CLI will make sure this hook is called after each run, but it is the responsibility of users of the JavaScript API to manually call bundle.close()
once they are done generating bundles. For that reason, any plugin relying on this feature should carefully mention this in its documentation.
如果插件想要在监视模式下跨构建保留资源,他们可以检查此钩子中的 this.meta.watchMode
并在 closeWatcher
中对监视模式执行必要的清理。
¥If a plugin wants to retain resources across builds in watch mode, they can check for this.meta.watchMode
in this hook and perform the necessary cleanup for watch mode in closeWatcher
.
footer
类型: | string | ((chunk: RenderedChunk) => string) |
---|---|
种类: | 异步、顺序 |
以前的: | resolveFileUrl 用于每次使用 import.meta.ROLLUP_FILE_URL_referenceId 和 resolveImportMeta 用于当前块中对 import.meta 的所有其他访问 |
下一个: | renderDynamicImport 代表下一个块中的每个动态导入表达式(如果有另一个动态导入表达式),否则 renderChunk 代表第一个块 |
比照。output.banner/output.footer
。
¥Cf. output.banner/output.footer
.
generateBundle
类型: | (options: OutputOptions, bundle: { [fileName: string]: OutputAsset | OutputChunk }, isWrite: boolean) => void |
---|---|
种类: | 异步、顺序 |
以前的: | augmentChunkHash |
下一个: | 如果输出是通过 bundle.write(...) 生成的,则为 writeBundle ,否则这是输出生成阶段的最后一个钩子,如果生成另一个输出,则可能会再次跟随 outputOptions |
typescript
interface OutputAsset {
fileName: string;
names: string[];
needsCodeReference: boolean;
originalFileNames: string[];
source: string | Uint8Array;
type: 'asset';
}
interface OutputChunk {
code: string;
dynamicImports: string[];
exports: string[];
facadeModuleId: string | null;
fileName: string;
implicitlyLoadedBefore: string[];
imports: string[];
importedBindings: { [imported: string]: string[] };
isDynamicEntry: boolean;
isEntry: boolean;
isImplicitEntry: boolean;
map: SourceMap | null;
modules: {
[id: string]: {
renderedExports: string[];
removedExports: string[];
renderedLength: number;
originalLength: number;
code: string | null;
};
};
moduleIds: string[];
name: string;
preliminaryFileName: string;
referencedFiles: string[];
sourcemapFileName: string | null;
type: 'chunk';
}
在 bundle.generate()
结束时或在 bundle.write()
写入文件之前调用。要在写入文件后对其进行修改,请使用 writeBundle
钩子。bundle
提供了正在写入或生成的文件的完整列表及其详细信息。
¥Called at the end of bundle.generate()
or immediately before the files are written in bundle.write()
. To modify the files after they have been written, use the writeBundle
hook. bundle
provides the full list of files being written or generated along with their details.
你可以通过从此钩子中的打包对象中删除文件来防止触发文件。要触发其他文件,请使用 this.emitFile
插件上下文函数。
¥You can prevent files from being emitted by deleting them from the bundle object in this hook. To emit additional files, use the this.emitFile
plugin context function.
危险
不要直接将资源添加到打包包中。这绕过了 Rollup 用于跟踪资源的内部机制。它还可能导致你的资源遗漏 Rollup 内部依赖的重要属性,并且你的插件可能会因较小的 Rollup 版本而中断。
¥Do not directly add assets to the bundle. This circumvents internal mechanisms that Rollup has for tracking assets. It can also cause your asset to miss vital properties that Rollup relies on internally and your plugin can break with minor Rollup releases.
相反,请始终使用 this.emitFile
。
¥Instead, always use this.emitFile
.
intro
类型: | string | ((chunk: RenderedChunk) => string) |
---|---|
种类: | 异步、顺序 |
以前的: | resolveFileUrl 用于每次使用 import.meta.ROLLUP_FILE_URL_referenceId 和 resolveImportMeta 用于当前块中对 import.meta 的所有其他访问 |
下一个: | renderDynamicImport 代表下一个块中的每个动态导入表达式(如果有另一个动态导入表达式),否则 renderChunk 代表第一个块 |
¥Cf. output.intro/output.outro
.
outputOptions
类型: | (outputOptions: OutputOptions) => OutputOptions | null |
---|---|
种类: | 同步、顺序 |
以前的: | 如果这是第一次生成输出,则为 buildEnd ,否则为 generateBundle 、writeBundle 或 renderError ,具体取决于先前生成的输出。这是输出生成阶段的第一个钩子 |
下一个: | renderStart |
替换或操作传递给 bundle.generate()
或 bundle.write()
的输出选项对象。返回 null
不会替代任何内容。如果你只需要读取输出选项,建议使用 renderStart
钩子,因为在考虑所有 outputOptions
钩子的转换后,该钩子可以访问输出选项。
¥Replaces or manipulates the output options object passed to bundle.generate()
or bundle.write()
. Returning null
does not replace anything. If you just need to read the output options, it is recommended to use the renderStart
hook as this hook has access to the output options after the transformations from all outputOptions
hooks have been taken into account.
outro
类型: | string | ((chunk: RenderedChunk) => string) |
---|---|
种类: | 异步、顺序 |
以前的: | resolveFileUrl 用于每次使用 import.meta.ROLLUP_FILE_URL_referenceId 和 resolveImportMeta 用于当前块中对 import.meta 的所有其他访问 |
下一个: | renderDynamicImport 代表下一个块中的每个动态导入表达式(如果有另一个动态导入表达式),否则 renderChunk 代表第一个块 |
¥Cf. output.intro/output.outro
.
renderChunk
类型: | RenderChunkHook |
---|---|
种类: | 异步、顺序 |
以前的: | 最后一个块的 banner 、footer 、intro 、outro |
下一个: | augmentChunkHash |
typescript
type RenderChunkHook = (
code: string,
chunk: RenderedChunk,
options: NormalizedOutputOptions,
meta: { chunks: Record<string, RenderedChunk> }
) => { code: string; map?: SourceMapInput } | string | null;
interface RenderedChunk {
dynamicImports: string[];
exports: string[];
facadeModuleId: string | null;
fileName: string;
implicitlyLoadedBefore: string[];
importedBindings: {
[imported: string]: string[];
};
imports: string[];
isDynamicEntry: boolean;
isEntry: boolean;
isImplicitEntry: boolean;
moduleIds: string[];
modules: {
[id: string]: RenderedModule;
};
name: string;
referencedFiles: string[];
type: 'chunk';
}
可用于转换各个块。为每个 Rollup 输出块文件调用。返回 null
将不应用任何转换。如果你更改此钩子中的代码并希望支持源映射,则需要返回描述你的更改的 map
,请参阅 源代码转换部分。
¥Can be used to transform individual chunks. Called for each Rollup output chunk file. Returning null
will apply no transformations. If you change code in this hook and want to support source maps, you need to return a map
describing your changes, see the section on source code transformations.
chunk
包含有关使用与 generateBundle
钩子相同的 OutputChunk
类型的块的附加信息,但存在以下差异:
¥chunk
contains additional information about the chunk using the same OutputChunk
type as the generateBundle
hook with the following differences:
code
和map
未设置。相反,请使用此钩子的code
参数。¥
code
andmap
are not set. Instead, use thecode
parameter of this hook.所有包含哈希值的引用块文件名将包含哈希占位符。这包括
fileName
、imports
、importedBindings
、dynamicImports
和implicitlyLoadedBefore
。当你在此钩子返回的代码中使用此类占位符文件名或其中的一部分时,Rollup 会将占位符替换为generateBundle
之前的实际哈希值,确保哈希值反映最终生成的块的实际内容,包括所有引用的文件哈希值 。¥all referenced chunk file names that would contain hashes will contain hash placeholders instead. This includes
fileName
,imports
,importedBindings
,dynamicImports
andimplicitlyLoadedBefore
. When you use such a placeholder file name or part of it in the code returned from this hook, Rollup will replace the placeholder with the actual hash beforegenerateBundle
, making sure the hash reflects the actual content of the final generated chunk including all referenced file hashes.
chunk
是可变的,在此钩子中应用的更改将传播到其他插件和生成的包。这意味着如果你在此钩子中添加或删除导入或导出,则应该更新 imports
、importedBindings
和/或 exports
。
¥chunk
is mutable and changes applied in this hook will propagate to other plugins and to the generated bundle. That means if you add or remove imports or exports in this hook, you should update imports
, importedBindings
and/or exports
.
meta.chunks
包含有关 Rollup 生成的所有块的信息,并允许你访问它们的 RenderedChunk
信息,同样使用哈希占位符。这意味着你可以在这个钩子中探索整个块图。
¥meta.chunks
contains information about all the chunks Rollup is generating and gives you access to their RenderedChunk
information, again using placeholders for hashes. That means you can explore the entire chunk graph in this hook.
renderDynamicImport
类型: | renderDynamicImportHook |
---|---|
种类: | 同步,首先 |
以前的: | 如果这是第一个块,则为 renderStart ,否则为前一个块的 banner 、footer 、intro 、outro |
下一个: | resolveFileUrl 用于每次使用 import.meta.ROLLUP_FILE_URL_referenceId 和 resolveImportMeta 用于当前块中对 import.meta 的所有其他访问 |
typescript
type renderDynamicImportHook = (options: {
customResolution: string | null;
format: string;
moduleId: string;
targetModuleId: string | null;
}) => { left: string; right: string } | null;
此钩子通过提供导入表达式参数左侧 (import(
) 和右侧 ()
) 的代码替换,提供对如何渲染动态导入的细粒度控制。返回 null
会遵循此类型的其他钩子,并最终渲染特定于格式的默认值。
¥This hook provides fine-grained control over how dynamic imports are rendered by providing replacements for the code to the left (import(
) and right ()
) of the argument of the import expression. Returning null
defers to other hooks of this type and ultimately renders a format-specific default.
format
是渲染的输出格式,moduleId
是执行动态导入的模块的 ID。如果导入可以解析为内部或外部 id,则 targetModuleId
将设置为该 id,否则将为 null
。如果动态导入包含由 resolveDynamicImport
钩子解析为替换字符串的非字符串表达式,则 customResolution
将包含该字符串。
¥format
is the rendered output format, moduleId
the id of the module performing the dynamic import. If the import could be resolved to an internal or external id, then targetModuleId
will be set to this id, otherwise it will be null
. If the dynamic import contained a non-string expression that was resolved by a resolveDynamicImport
hook to a replacement string, then customResolution
will contain that string.
以下代码将使用自定义处理程序替换所有动态导入,添加 import.meta.url
作为第二个参数以允许处理程序正确解析相对导入:
¥The following code will replace all dynamic imports with a custom handler, adding import.meta.url
as a second argument to allow the handler to resolve relative imports correctly:
js
function dynamicImportPolyfillPlugin() {
return {
name: 'dynamic-import-polyfill',
renderDynamicImport() {
return {
left: 'dynamicImportPolyfill(',
right: ', import.meta.url)'
};
}
};
}
// input
import('./lib.js');
// output
dynamicImportPolyfill('./lib.js', import.meta.url);
下一个插件将确保 esm-lib
的所有动态导入都标记为外部并保留为导入表达式,例如 允许 CommonJS 构建在 Node 13+ 中导入 ES 模块,参见。如何在 Node 文档中进行 从 CommonJS 导入 ES 模块。
¥The next plugin will make sure all dynamic imports of esm-lib
are marked as external and retained as import expressions to e.g. allow a CommonJS build to import an ES module in Node 13+, cf. how to import ES modules from CommonJS in the Node documentation.
js
function retainImportExpressionPlugin() {
return {
name: 'retain-import-expression',
resolveDynamicImport(specifier) {
if (specifier === 'esm-lib') return false;
return null;
},
renderDynamicImport({ targetModuleId }) {
if (targetModuleId === 'esm-lib') {
return {
left: 'import(',
right: ')'
};
}
}
};
}
请注意,当此钩子以非 ES 格式重写动态导入时,没有互操作代码来确保例如 生成 .default
后,默认导出可用。插件的责任是确保重写的动态导入返回一个解析为正确的命名空间对象的 Promise。
¥Note that when this hook rewrites dynamic imports in non-ES formats, no interop code to make sure that e.g. the default export is available as .default
is generated. It is the responsibility of the plugin to make sure the rewritten dynamic import returns a Promise that resolves to a proper namespace object.
renderError
类型: | (error: Error) => void |
---|---|
种类: | 异步、并行 |
以前的: | 从 renderStart 到 renderChunk 的任何钩子 |
下一个: | 如果调用它,则这是输出生成阶段的最后一个钩子,如果生成另一个输出,则可能会再次跟随 outputOptions |
当 Rollup 在 bundle.generate()
或 bundle.write()
期间遇到错误时调用。错误被传递给这个钩子。要在生成成功完成时收到通知,请使用 generateBundle
钩子。
¥Called when Rollup encounters an error during bundle.generate()
or bundle.write()
. The error is passed to this hook. To get notified when generation completes successfully, use the generateBundle
hook.
renderStart
类型: | (outputOptions: OutputOptions, inputOptions: InputOptions) => void |
---|---|
种类: | 异步、并行 |
以前的: | outputOptions |
下一个: | renderDynamicImport 对于第一个块中的每个动态导入表达式 |
每次调用 bundle.generate()
或 bundle.write()
时都会首先调用。要在生成完成时收到通知,请使用 generateBundle
和 renderError
钩子。当你需要访问传递给 bundle.generate()
或 bundle.write()
的输出选项时,建议使用此钩子,因为它考虑了所有 outputOptions
钩子的转换,并且还包含未设置选项的正确默认值。它还接收传递给 rollup.rollup()
的输入选项,以便可用作输出插件的插件(即仅使用 generate
阶段钩子的插件)可以访问它们。
¥Called initially each time bundle.generate()
or bundle.write()
is called. To get notified when generation has completed, use the generateBundle
and renderError
hooks. This is the recommended hook to use when you need access to the output options passed to bundle.generate()
or bundle.write()
as it takes the transformations by all outputOptions
hooks into account and also contains the right default values for unset options. It also receives the input options passed to rollup.rollup()
so that plugins that can be used as output plugins, i.e. plugins that only use generate
phase hooks, can get access to them.
resolveFileUrl
类型: | ResolveFileUrlHook |
---|---|
种类: | 同步,首先 |
以前的: | renderDynamicImport 对于当前块中的每个动态导入表达式 |
下一个: | 当前 chunk 并行 banner , footer , intro , outro |
typescript
type ResolveFileUrlHook = (options: {
chunkId: string;
fileName: string;
format: InternalModuleFormat;
moduleId: string;
referenceId: string;
relativePath: string;
}) => string | NullValue;
允许自定义 Rollup 如何解析插件通过 this.emitFile
触发的文件的 URL。默认情况下,Rollup 将为 import.meta.ROLLUP_FILE_URL_referenceId
生成代码,该代码应正确生成触发文件的绝对 URL,与输出格式和部署代码的主机系统无关。
¥Allows to customize how Rollup resolves URLs of files that were emitted by plugins via this.emitFile
. By default, Rollup will generate code for import.meta.ROLLUP_FILE_URL_referenceId
that should correctly generate absolute URLs of emitted files independent of the output format and the host system where the code is deployed.
为此,除 CommonJS 和 UMD 之外的所有格式都假定它们在 URL
和 document
可用的浏览器环境中运行。如果失败或生成更优化的代码,可以使用此钩子来自定义此行为。为此,可以使用以下信息:
¥For that, all formats except CommonJS and UMD assume that they run in a browser environment where URL
and document
are available. In case that fails or to generate more optimized code, this hook can be used to customize this behaviour. To do that, the following information is available:
chunkId
:引用此文件的块的 ID。如果块文件名包含哈希值,则此 id 将包含占位符。如果此占位符最终出现在生成的代码中,则 Rollup 会将该占位符替换为实际文件名。¥
chunkId
: The id of the chunk this file is referenced from. If the chunk file name would contain a hash, this id will contain a placeholder instead. Rollup will replace this placeholder with the actual file name if it ends up in the generated code.fileName
:触发的文件的路径和文件名,相对于output.dir
,不带前导./
。同样,如果这是一个名称中包含哈希值的块,那么它将包含一个占位符。¥
fileName
: The path and file name of the emitted file, relative tooutput.dir
without a leading./
. Again if this is a chunk that would have a hash in its name, it will contain a placeholder instead.format
:渲染的输出格式。¥
format
: The rendered output format.moduleId
:引用此文件的原始模块的 ID。对于有条件地以不同方式解决某些资源很有用。¥
moduleId
: The id of the original module this file is referenced from. Useful for conditionally resolving certain assets differently.referenceId
:文件的参考 ID。¥
referenceId
: The reference id of the file.relativePath
:触发的文件的路径和文件名,相对于引用文件的块。该路径将不包含前导./
,但可能包含前导../
。¥
relativePath
: The path and file name of the emitted file, relative to the chunk the file is referenced from. This will path will contain no leading./
but may contain a leading../
.
以下插件将始终解析与当前文档相关的所有文件:
¥The following plugin will always resolve all files relative to the current document:
js
function resolveToDocumentPlugin() {
return {
name: 'resolve-to-document',
resolveFileUrl({ fileName }) {
return `new URL('${fileName}', document.baseURI).href`;
}
};
}
resolveImportMeta
类型: | (property: string | null, {chunkId: string, moduleId: string, format: string}) => string | null |
---|---|
种类: | 同步,首先 |
以前的: | renderDynamicImport 对于当前块中的每个动态导入表达式 |
下一个: | 当前 chunk 并行 banner , footer , intro , outro |
允许自定义 Rollup 如何处理 import.meta
和 import.meta.someProperty
,特别是 import.meta.url
。在 ES 模块中,import.meta
是一个对象,import.meta.url
包含当前模块的 URL,例如 浏览器中为 http://server.net/bundle.js
,Node 中为 file:///path/to/bundle.js
。
¥Allows to customize how Rollup handles import.meta
and import.meta.someProperty
, in particular import.meta.url
. In ES modules, import.meta
is an object and import.meta.url
contains the URL of the current module, e.g. http://server.net/bundle.js
for browsers or file:///path/to/bundle.js
in Node.
默认情况下,对于 ES 模块以外的格式,Rollup 会将 import.meta.url
替换为尝试通过返回当前块的动态 URL 来匹配此行为的代码。请注意,除 CommonJS 和 UMD 之外的所有格式都假定它们在 URL
和 document
可用的浏览器环境中运行。对于其他属性,import.meta.someProperty
将替换为 undefined
,而 import.meta
将替换为包含 url
属性的对象。
¥By default, for formats other than ES modules, Rollup replaces import.meta.url
with code that attempts to match this behaviour by returning the dynamic URL of the current chunk. Note that all formats except CommonJS and UMD assume that they run in a browser environment where URL
and document
are available. For other properties, import.meta.someProperty
is replaced with undefined
while import.meta
is replaced with an object containing a url
property.
可以通过此钩子更改此行为(也适用于 ES 模块)。对于每次出现 import.meta<.someProperty>
,都会使用属性名称或 null
(如果直接访问 import.meta
)调用此钩子。例如,以下代码将使用原始模块到当前工作目录的相对路径解析 import.meta.url
,并在运行时再次根据当前文档的基本 URL 解析此路径:
¥This behaviour can be changed—also for ES modules—via this hook. For each occurrence of import.meta<.someProperty>
, this hook is called with the name of the property or null
if import.meta
is accessed directly. For example, the following code will resolve import.meta.url
using the relative path of the original module to the current working directory and again resolve this path against the base URL of the current document at runtime:
js
function importMetaUrlCurrentModulePlugin() {
return {
name: 'import-meta-url-current-module',
resolveImportMeta(property, { moduleId }) {
if (property === 'url') {
return `new URL('${path.relative(
process.cwd(),
moduleId
)}', document.baseURI).href`;
}
return null;
}
};
}
如果 chunkId
包含哈希值,它将包含一个占位符。如果此占位符最终出现在生成的代码中,Rollup 会将其替换为实际的块哈希。
¥If the chunkId
would contain a hash, it will contain a placeholder instead. If this placeholder ends up in the generated code, Rollup will replace it with the actual chunk hash.
writeBundle
类型: | (options: OutputOptions, bundle: { [fileName: string]: OutputAsset | OutputChunk }) => void |
---|---|
种类: | 异步、并行 |
以前的: | generateBundle |
下一个: | 如果调用它,则这是输出生成阶段的最后一个钩子,如果生成另一个输出,则可能会再次跟随 outputOptions |
仅在写入所有文件后在 bundle.write()
末尾调用。与 generateBundle
钩子类似,bundle
提供正在写入的文件的完整列表及其详细信息。
¥Called only at the end of bundle.write()
once all files have been written. Similar to the generateBundle
hook, bundle
provides the full list of files being written along with their details.
插件上下文
¥Plugin Context
可以通过 this
从大多数 钩子 内访问许多实用函数和信息位:
¥A number of utility functions and informational bits can be accessed from within most hooks via this
:
this.addWatchFile
类型: | (id: string) => void |
---|
添加要在监视模式下监视的其他文件,以便对这些文件的更改将触发重建。id
可以是文件或目录的绝对路径,也可以是相对于当前工作目录的路径。该上下文函数可以在除 closeBundle
之外的所有插件钩子中使用。但如果将 watch.skipWrite
设置为 true
,则在 输出生成钩子 中使用时不会产生任何效果。
¥Adds additional files to be monitored in watch mode so that changes to these files will trigger rebuilds. id
can be an absolute path to a file or directory or a path relative to the current working directory. This context function can be used in all plugin hooks except closeBundle
. However, it will not have an effect when used in output generation hooks if watch.skipWrite
is set to true
.
请注意,当触发与现有文件相对应的资源时,建议在 this.emitFile
调用中设置 originalFileName
属性,因为这样不仅可以监视文件,还可以使连接对其他插件透明。
¥Note that when emitting assets that correspond to an existing file, it is recommended to set the originalFileName
property in the this.emitFile
call instead as that will not only watch the file but also make the connection transparent to other plugins.
注意:通常在监视模式下为了提高重建速度,只有当给定模块的内容实际发生更改时,才会触发 transform
钩子。在 transform
钩子中使用 this.addWatchFile
将确保如果监视的文件发生更改,也会重新评估该模块的 transform
钩子。
¥Note: Usually in watch mode to improve rebuild speed, the transform
hook will only be triggered for a given module if its contents actually changed. Using this.addWatchFile
from within the transform
hook will make sure the transform
hook is also reevaluated for this module if the watched file changes.
一般来说,建议在取决于监视文件的钩子内使用 this.addWatchFile
。
¥In general, it is recommended to use this.addWatchFile
from within the hook that depends on the watched file.
this.debug
类型: | (log: string | RollupLog | (() => RollupLog | string), position?: number | { column: number; line: number }) => void |
---|
生成 "debug"
日志。详情请参见 this.warn
。调试日志总是由 Rollup 添加 code: "PLUGIN_LOG"
。确保向这些日志添加独特的 pluginCode
以便于过滤。
¥Generate a "debug"
log. See this.warn
for details. Debug logs always get code: "PLUGIN_LOG"
added by Rollup. Make sure to add a distinctive pluginCode
to those logs for easy filtering.
仅当 logLevel
选项显式设置为 "debug"
时才会处理这些日志,否则不执行任何操作。因此,鼓励向插件添加有用的调试日志,因为这可以帮助发现问题,同时默认情况下它们将被有效地静音。如果你需要进行昂贵的计算来生成日志,请确保使用函数形式,以便仅在实际处理日志时才执行这些计算。
¥These logs are only processed if the logLevel
option is explicitly set to "debug"
, otherwise it does nothing. Therefore, it is encouraged to add helpful debug logs to plugins as that can help spot issues while they will be efficiently muted by default. If you need to do expensive computations to generate the log, make sure to use the function form so that these computations are only performed if the log is actually processed.
js
function plugin() {
return {
name: 'test',
transform(code, id) {
this.debug(
() =>
`transforming ${id},\n` +
`module contains, ${code.split('\n').length} lines`
);
}
};
}
this.emitFile
类型: | (emittedFile: EmittedChunk | EmittedPrebuiltChunk | EmittedAsset) => string |
---|
typescript
interface EmittedChunk {
type: 'chunk';
id: string;
name?: string;
fileName?: string;
implicitlyLoadedAfterOneOf?: string[];
importer?: string;
preserveSignature?: 'strict' | 'allow-extension' | 'exports-only' | false;
}
interface EmittedPrebuiltChunk {
type: 'prebuilt-chunk';
fileName: string;
code: string;
exports?: string[];
map?: SourceMap;
}
interface EmittedAsset {
type: 'asset';
name?: string;
needsCodeReference?: boolean;
originalFileName?: string;
fileName?: string;
source?: string | Uint8Array;
}
触发一个包含在构建输出中的新文件,并返回一个 referenceId
,可在各个地方使用该文件来引用触发的文件。你可以触发块、预构建块或资源。
¥Emits a new file that is included in the build output and returns a referenceId
that can be used in various places to reference the emitted file. You can emit chunks, prebuilt chunks or assets.
当触发块或资源时,可以提供 name
或 fileName
。如果提供了 fileName
,它将不加修改地用作生成文件的名称,如果这导致冲突,则会抛出错误。否则,如果提供了 name
,它将用作相应 output.chunkFileNames
或 output.assetFileNames
模式中 [name]
的替换,可能会在文件名末尾添加一个唯一的数字以避免冲突。如果未提供 name
或 fileName
,则将使用默认名称。预构建块必须始终具有 fileName
。
¥When emitting chunks or assets, either a name
or a fileName
can be supplied. If a fileName
is provided, it will be used unmodified as the name of the generated file, throwing an error if this causes a conflict. Otherwise, if a name
is supplied, this will be used as substitution for [name]
in the corresponding output.chunkFileNames
or output.assetFileNames
pattern, possibly adding a unique number to the end of the file name to avoid conflicts. If neither a name
nor fileName
is supplied, a default name will be used. Prebuilt chunks must always have a fileName
.
你可以在 load
或 transform
插件钩子通过 import.meta.ROLLUP_FILE_URL_referenceId
返回的任何代码中引用触发文件的 URL。有关更多详细信息和示例,请参阅 文件网址。
¥You can reference the URL of an emitted file in any code returned by a load
or transform
plugin hook via import.meta.ROLLUP_FILE_URL_referenceId
. See File URLs for more details and an example.
可以通过 resolveFileUrl
插件钩子自定义替换 import.meta.ROLLUP_FILE_URL_referenceId
的生成代码。你还可以在文件名可用时立即使用 this.getFileName(referenceId)
来确定该文件名。如果没有显式设置文件名,则
¥The generated code that replaces import.meta.ROLLUP_FILE_URL_referenceId
can be customized via the resolveFileUrl
plugin hook. You can also use this.getFileName(referenceId)
to determine the file name as soon as it is available. If the file name is not set explicitly, then
资源文件名以
renderStart
钩子开头。对于稍后触发的资源,文件名将在触发资源后立即可用。¥asset file names are available starting with the
renderStart
hook. For assets that are emitted later, the file name will be available immediately after emitting the asset.在
renderStart
钩子之后创建块后,不包含哈希的块文件名就可用。¥chunk file names that do not contain a hash are available as soon as chunks are created after the
renderStart
hook.如果块文件名包含哈希值,则在
generateBundle
之前的任何钩子中使用getFileName
将返回包含占位符的名称,而不是实际名称。如果你在renderChunk
中转换的块中使用此文件名或其部分内容,则 Rollup 会将占位符替换为generateBundle
之前的实际哈希值,确保哈希值反映最终生成的块的实际内容,包括所有引用的文件哈希值。¥if a chunk file name would contain a hash, using
getFileName
in any hook beforegenerateBundle
will return a name containing a placeholder instead of the actual name. If you use this file name or parts of it in a chunk you transform inrenderChunk
, Rollup will replace the placeholder with the actual hash beforegenerateBundle
, making sure the hash reflects the actual content of the final generated chunk including all referenced file hashes.
如果 type
是 chunk
,那么这会触发一个以给定模块 id
作为入口点的新块。为了解决这个问题,id
将像常规入口点一样通过构建钩子,从 resolveId
开始。如果提供了 importer
,则它充当 resolveId
的第二个参数,对于正确解析相对路径非常重要。如果未提供,路径将相对于当前工作目录进行解析。如果提供了 preserveSignature
的值,这将覆盖该特定块的 preserveEntrySignatures
。
¥If the type
is chunk
, then this emits a new chunk with the given module id
as entry point. To resolve it, the id
will be passed through build hooks just like regular entry points, starting with resolveId
. If an importer
is provided, this acts as the second parameter of resolveId
and is important to properly resolve relative paths. If it is not provided, paths will be resolved relative to the current working directory. If a value for preserveSignature
is provided, this will override preserveEntrySignatures
for this particular chunk.
这不会导致图中出现重复的模块,相反,如果有必要,现有的块将被分割或创建具有重新导出的外观块。具有指定 fileName
的块将始终生成单独的块,而其他触发的块可能会与现有块进行数据去重,即使 name
不匹配也是如此。如果此类块未进行数据去重,则将使用 output.chunkFileNames
名称模式。
¥This will not result in duplicate modules in the graph, instead if necessary, existing chunks will be split or a facade chunk with reexports will be created. Chunks with a specified fileName
will always generate separate chunks while other emitted chunks may be deduplicated with existing chunks even if the name
does not match. If such a chunk is not deduplicated, the output.chunkFileNames
name pattern will be used.
默认情况下,Rollup 假定触发的块是独立于其他入口点执行的,甚至可能在执行任何其他代码之前执行。这意味着,如果触发的块与现有入口点共享依赖,Rollup 将为这些入口点之间共享的依赖创建一个附加块。为 implicitlyLoadedAfterOneOf
提供非空模块 id 数组将改变该行为,方法是为 Rollup 提供附加信息以防止在某些情况下发生这种情况。这些 ID 将以与 id
属性相同的方式解析,并尊重 importer
属性(如果提供)。Rollup 现在将假设仅当导致 implicitlyLoadedAfterOneOf
中的 id 之一被加载的至少一个入口点已被执行时才执行触发的块,创建相同的块,就好像新触发的块只能通过动态访问一样 从 implicitlyLoadedAfterOneOf
中的模块导入。下面是一个示例,它使用它创建一个包含多个脚本的简单 HTML 文件,创建优化的块以尊重它们的执行顺序:
¥By default, Rollup assumes that emitted chunks are executed independent of other entry points, possibly even before any other code is executed. This means that if an emitted chunk shares a dependency with an existing entry point, Rollup will create an additional chunk for dependencies that are shared between those entry points. Providing a non-empty array of module ids for implicitlyLoadedAfterOneOf
will change that behaviour by giving Rollup additional information to prevent this in some cases. Those ids will be resolved the same way as the id
property, respecting the importer
property if it is provided. Rollup will now assume that the emitted chunk is only executed if at least one of the entry points that lead to one of the ids in implicitlyLoadedAfterOneOf
being loaded has already been executed, creating the same chunks as if the newly emitted chunk was only reachable via dynamic import from the modules in implicitlyLoadedAfterOneOf
. Here is an example that uses this to create a simple HTML file with several scripts, creating optimized chunks to respect their execution order:
js
// rollup.config.js
function generateHtmlPlugin() {
let ref1;
let ref2;
let ref3;
return {
name: 'generate-html',
buildStart() {
ref1 = this.emitFile({
type: 'chunk',
id: 'src/entry1'
});
ref2 = this.emitFile({
type: 'chunk',
id: 'src/entry2',
implicitlyLoadedAfterOneOf: ['src/entry1']
});
ref3 = this.emitFile({
type: 'chunk',
id: 'src/entry3',
implicitlyLoadedAfterOneOf: ['src/entry2']
});
},
generateBundle() {
this.emitFile({
type: 'asset',
fileName: 'index.html',
source: `
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="${this.getFileName(ref1)}" type="module"></script>
<script src="${this.getFileName(ref2)}" type="module"></script>
<script src="${this.getFileName(ref3)}" type="module"></script>
</body>
</html>`
});
}
};
}
export default {
input: [],
preserveEntrySignatures: false,
plugins: [generateHtmlPlugin()],
output: {
format: 'es',
dir: 'dist'
}
};
如果没有动态导入,这将创建三个块,其中第一个块包含 src/entry1
的所有依赖,第二个块仅包含第一个块中未包含的 src/entry2
的依赖,从第一个块导入这些依赖,然后再次导入 第三块也一样。
¥If there are no dynamic imports, this will create exactly three chunks where the first chunk contains all dependencies of src/entry1
, the second chunk contains only the dependencies of src/entry2
that are not contained in the first chunk, importing those from the first chunk, and again the same for the third chunk.
请注意,即使任何模块 id 都可以在 implicitlyLoadedAfterOneOf
中使用,如果此类 id 无法与块唯一关联,则 Rollup 将抛出错误,例如 因为 id
无法从现有的静态入口点隐式或显式到达,或者因为该文件完全是树状摇动的。不过,仅使用由用户定义的或先前触发的块的入口点总是有效的。
¥Note that even though any module id can be used in implicitlyLoadedAfterOneOf
, Rollup will throw an error if such an id cannot be uniquely associated with a chunk, e.g. because the id
cannot be reached implicitly or explicitly from the existing static entry points, or because the file is completely tree-shaken. Using only entry points, either defined by the user or of previously emitted chunks, will always work, though.
如果 type
是 prebuilt-chunk
,它会触发一个具有 code
参数提供的固定内容的块。目前,fileName
还需要提供块的名称。如果它导出一些变量,我们应该通过可选的 exports
列出这些变量。通过 map
,我们可以提供对应于 code
的源映射。
¥If the type
is prebuilt-chunk
, it emits a chunk with fixed contents provided by the code
parameter. At the moment, fileName
is also required to provide the name of the chunk. If it exports some variables, we should list these via the optional exports
. Via map
we can provide a sourcemap that corresponds to code
.
要在导入中引用预构建块,我们需要在 resolveId
钩子中将 "模块" 标记为外部,因为预构建块不是模块图的一部分。相反,它们的行为就像带有块元数据的资源:
¥To reference a prebuilt chunk in imports, we need to mark the "module" as external in the resolveId
hook as prebuilt chunks are not part of the module graph. Instead, they behave like assets with chunk meta-data:
js
function emitPrebuiltChunkPlugin() {
return {
name: 'emit-prebuilt-chunk',
resolveId(source) {
if (source === './my-prebuilt-chunk.js') {
return {
id: source,
external: true
};
}
},
buildStart() {
this.emitFile({
type: 'prebuilt-chunk',
fileName: 'my-prebuilt-chunk.js',
code: 'export const foo = "foo"',
exports: ['foo']
});
}
};
}
然后你可以在代码中引用预构建的块:
¥Then you can reference the prebuilt chunk in your code:
js
import { foo } from './my-prebuilt-chunk.js';
目前,触发预构建块是一项基本功能。期待你的反馈。
¥Currently, emitting a prebuilt chunk is a basic feature. Looking forward to your feedback.
如果 type
是 asset
,则这会触发一个以给定 source
作为内容的任意新文件。可以将 source
通过 this.setAssetSource(referenceId, source)
的设置推迟到稍后的时间,以便能够在构建阶段引用文件,同时在生成阶段为每个输出单独设置源。具有指定 fileName
的资源将始终生成单独的文件,而其他触发的资源如果具有相同的源,则可能会与现有资源进行数据去重,即使 name
不匹配也是如此。如果没有对没有 fileName
的资源进行数据去重,则将使用 output.assetFileNames
名称模式。
¥If the type
is asset
, then this emits an arbitrary new file with the given source
as content. It is possible to defer setting the source
via this.setAssetSource(referenceId, source)
to a later time to be able to reference a file during the build phase while setting the source separately for each output during the generate phase. Assets with a specified fileName
will always generate separate files while other emitted assets may be deduplicated with existing assets if they have the same source even if the name
does not match. If an asset without a fileName
is not deduplicated, the output.assetFileNames
name pattern will be used.
如果此资源对应于磁盘上的实际文件,则应将 originalFileName
设置为文件的绝对路径。在这种情况下,此属性将传递给接收 PreRenderedAsset
或 OutputAsset
(如 generateBundle
)的后续插件钩子。在监视模式下,Rollup 还将自动监视此文件的更改,并在更改时触发重建。因此,没有必要为此文件调用 this.addWatchFile
。
¥If this asset corresponds to an actual file on disk, then originalFileName
should be set to the absolute path of the file. In that case, this property will be passed on to subsequent plugin hooks that receive a PreRenderedAsset
or an OutputAsset
like generateBundle
. In watch mode, Rollup will also automatically watch this file for changes and trigger a rebuild if it changes. Therefore, it is not necessary to call this.addWatchFile
for this file.
如果 needsCodeReference
设置为 true
,并且该资源未通过 import.meta.ROLLUP_FILE_URL_referenceId
输出中的任何代码引用,则 Rollup 将不会触发它。这也尊重通过树摇动删除的引用,即,如果相应的 import.meta.ROLLUP_FILE_URL_referenceId
是源代码的一部分但实际上并未使用,并且引用通过树摇动删除,则不会触发资源。
¥If needsCodeReference
is set to true
and this asset is not referenced by any code in the output via import.meta.ROLLUP_FILE_URL_referenceId
, then Rollup will not emit it. This also respects references removed via tree-shaking, i.e. if the corresponding import.meta.ROLLUP_FILE_URL_referenceId
is part of the source code but is not actually used and the reference is removed by tree-shaking, then the asset is not emitted.
this.error
类型: | (error: string | RollupLog | Error, position?: number | { column: number; line: number }) => never |
---|
结构上与 this.warn
相同,但它也会因错误而中止打包过程。有关 RollupLog
类型的信息,请参阅 onLog
选项。
¥Structurally equivalent to this.warn
, except that it will also abort the bundling process with an error. See the onLog
option for information about the RollupLog
type.
如果传递了 Error 实例,它将按原样使用,否则将使用给定的错误消息和所有其他提供的属性创建一个新的 Error 实例。
¥If an Error instance is passed, it will be used as-is, otherwise a new Error instance will be created with the given error message and all additional provided properties.
在除 onLog
钩子之外的所有钩子中,错误都会因 code: "PLUGIN_ERROR"
和 plugin: plugin.name
属性而增加。如果 acode
属性已经存在并且代码不是以 PLUGIN_
开头,它将被重命名为 pluginCode
。
¥In all hooks except the onLog
hook, the error will be augmented with code: "PLUGIN_ERROR"
and plugin: plugin.name
properties. If acode
property already exists and the code does not start withPLUGIN_
, it will be renamed to pluginCode
.
在 onLog
钩子中,此函数是一种将警告转变为错误的简单方法,同时保留警告的所有附加属性:
¥In the onLog
hook, this function is an easy way to turn warnings into errors while keeping all additional properties of the warning:
js
function myPlugin() {
return {
name: 'my-plugin',
onLog(level, log) {
if (level === 'warn' && log.code === 'THIS_IS_NOT_OK') {
return this.error(log);
}
}
};
}
当在 transform
钩子中使用时,当前模块的 id
也会被添加,并且可以提供 position
。这是一个字符索引或文件位置,将用于使用 pos
、loc
(标准 { file, line, column }
对象)和 frame
(显示位置的代码片段)来扩充日志。
¥When used in the transform
hook, the id
of the current module will also be added and a position
can be supplied. This is a character index or file location which will be used to augment the log with pos
, loc
(a standard { file, line, column }
object) and frame
(a snippet of code showing the location).
this.getCombinedSourcemap
类型: | () => SourceMap |
---|
获取所有以前插件的组合源映射。此上下文函数只能在 transform
插件钩子中使用。
¥Get the combined source maps of all previous plugins. This context function can only be used in the transform
plugin hook.
this.getFileName
类型: | (referenceId: string) => string |
---|
获取已通过 this.emitFile
触发的块或资源的文件名。文件名将相对于 outputOptions.dir
。
¥Get the file name of a chunk or asset that has been emitted via this.emitFile
. The file name will be relative to outputOptions.dir
.
this.getModuleIds
类型: | () => IterableIterator<string> |
---|
返回一个 Iterator
,它允许访问当前图中的所有模块 id。可以通过迭代
¥Returns an Iterator
that gives access to all module ids in the current graph. It can be iterated via
js
for (const moduleId of this.getModuleIds()) {
/* ... */
}
或通过 Array.from(this.getModuleIds())
转换为数组。
¥or converted into an Array via Array.from(this.getModuleIds())
.
this.getModuleInfo
类型: | (moduleId: string) => (ModuleInfo | null) |
---|
typescript
interface ModuleInfo {
id: string; // the id of the module, for convenience
code: string | null; // the source code of the module, `null` if external or not yet available
ast: ESTree.Program; // the parsed abstract syntax tree if available
hasDefaultExport: boolean | null; // is there a default export, `null` if external or not yet available
isEntry: boolean; // is this a user- or plugin-defined entry point
isExternal: boolean; // for external modules that are referenced but not included in the graph
isIncluded: boolean | null; // is the module included after tree-shaking, `null` if external or not yet available
importedIds: string[]; // the module ids statically imported by this module
importedIdResolutions: ResolvedId[]; // how statically imported ids were resolved, for use with this.load
importers: string[]; // the ids of all modules that statically import this module
exportedBindings: Record<string, string[]> | null; // contains all exported variables associated with the path of `from`, `null` if external
exports: string[] | null; // all exported variables, `null` if external
dynamicallyImportedIds: string[]; // the module ids imported by this module via dynamic import()
dynamicallyImportedIdResolutions: ResolvedId[]; // how ids imported via dynamic import() were resolved
dynamicImporters: string[]; // the ids of all modules that import this module via dynamic import()
implicitlyLoadedAfterOneOf: string[]; // implicit relationships, declared via this.emitFile
implicitlyLoadedBefore: string[]; // implicit relationships, declared via this.emitFile
attributes: { [key: string]: string }; // import attributes for this module
meta: { [plugin: string]: any }; // custom module meta-data
moduleSideEffects: boolean | 'no-treeshake'; // are imports of this module included if nothing is imported from it
syntheticNamedExports: boolean | string; // final value of synthetic named exports
}
interface ResolvedId {
id: string; // the id of the imported module
external: boolean | 'absolute'; // is this module external, "absolute" means it will not be rendered as relative in the module
attributes: { [key: string]: string }; // import attributes for this import
meta: { [plugin: string]: any }; // custom module meta-data when resolving the module
moduleSideEffects: boolean | 'no-treeshake'; // are side effects of the module observed, is tree-shaking enabled
resolvedBy: string; // which plugin resolved this module, "rollup" if resolved by Rollup itself
syntheticNamedExports: boolean | string; // does the module allow importing non-existing named exports
}
返回有关相关模块的附加信息。
¥Returns additional information about the module in question.
在构建过程中,该对象表示有关模块的当前可用信息,这些信息在 buildEnd
钩子之前可能不准确:
¥During the build, this object represents currently available information about the module which may be inaccurate before the buildEnd
hook:
id
和isExternal
永远不会改变。¥
id
andisExternal
will never change.code
、ast
、hasDefaultExport
、exports
和exportedBindings
仅在解析后可用,即在moduleParsed
钩子中或等待this.load
后。到那时,他们将不再改变。¥
code
,ast
,hasDefaultExport
,exports
andexportedBindings
are only available after parsing, i.e. in themoduleParsed
hook or after awaitingthis.load
. At that point, they will no longer change.如果
isEntry
是true
,则不再改变。然而,模块在解析后有可能成为入口点,无论是通过this.emitFile
还是因为插件在解析入口点时通过resolveId
钩子中的this.load
检查潜在的入口点。因此,不建议在transform
钩子中依赖此标志。buildEnd
年后不再改变。¥if
isEntry
istrue
, it will no longer change. It is however possible for modules to become entry points after they are parsed, either viathis.emitFile
or because a plugin inspects a potential entry point viathis.load
in theresolveId
hook when resolving an entry point. Therefore, it is not recommended relying on this flag in thetransform
hook. It will no longer change afterbuildEnd
.同样,
implicitlyLoadedAfterOneOf
可以在buildEnd
之前的任何时间通过this.emitFile
接收附加条目。¥Similarly,
implicitlyLoadedAfterOneOf
can receive additional entries at any time beforebuildEnd
viathis.emitFile
.importers
、dynamicImporters
和implicitlyLoadedBefore
将以空数组开始,当发现新的导入器和隐式依赖时,它们会接收附加条目。buildEnd
之后它们将不再改变。¥
importers
,dynamicImporters
andimplicitlyLoadedBefore
will start as empty arrays, which receive additional entries as new importers and implicit dependents are discovered. They will no longer change afterbuildEnd
.isIncluded
仅在buildEnd
之后可用,此时它将不再改变。¥
isIncluded
is only available afterbuildEnd
, at which point it will no longer change.当模块已被解析并且其依赖已被解析时,
importedIds
、importedIdResolutions
、dynamicallyImportedIds
和dynamicallyImportedIdResolutions
可用。这是在moduleParsed
钩子中或在使用resolveDependencies
标志等待this.load
之后的情况。到那时,他们将不再改变。¥
importedIds
,importedIdResolutions
,dynamicallyImportedIds
anddynamicallyImportedIdResolutions
are available when a module has been parsed and its dependencies have been resolved. This is the case in themoduleParsed
hook or after awaitingthis.load
with theresolveDependencies
flag. At that point, they will no longer change.attributes
、meta
、moduleSideEffects
和syntheticNamedExports
可以通过load
和transform
钩子更改。此外,虽然大多数属性是只读的,但这些属性是可写的,并且如果在触发buildEnd
钩子之前发生更改,则会拾取更改。meta
本身不应被覆盖,但可以随时改变其属性以存储有关模块的元信息。这样做而不是在插件中保留状态的优点是,如果使用了meta
,它会被持久化到缓存并从缓存中恢复,例如 从 CLI 使用监视模式时。¥
attributes
,meta
,moduleSideEffects
andsyntheticNamedExports
can be changed byload
andtransform
hooks. Moreover, while most properties are read-only, these properties are writable and changes will be picked up if they occur before thebuildEnd
hook is triggered.meta
itself should not be overwritten, but it is ok to mutate its properties at any time to store meta information about a module. The advantage of doing this instead of keeping state in a plugin is thatmeta
is persisted to and restored from the cache if it is used, e.g. when using watch mode from the CLI.
如果找不到模块 ID,则返回 null
。
¥Returns null
if the module id cannot be found.
this.getWatchFiles
类型: | () => string[] |
---|
获取之前监视过的文件的 ID。包括由带有 this.addWatchFile
的插件添加的文件以及在构建期间由 Rollup 隐式添加的文件。
¥Get ids of the files which has been watched previously. Include both files added by plugins with this.addWatchFile
and files added implicitly by Rollup during the build.
this.info
类型: | (log: string | RollupLog | (() => RollupLog | string), position?: number | { column: number; line: number }) => void |
---|
生成 "info"
日志。详情请参见 this.warn
。信息日志总是由 Rollup 添加 code: "PLUGIN_LOG"
。由于这些日志是默认显示的,因此将它们用于非警告但有意义的信息,以在每个构建中向所有用户显示。
¥Generate an "info"
log. See this.warn
for details. Info logs always get code: "PLUGIN_LOG"
added by Rollup. As these logs are displayed by default, use them for information that is not a warning but makes sense to display to all users on every build.
如果 logLevel
选项设置为 "warn"
或 "silent"
,则此方法将不执行任何操作。
¥If the logLevel
option is set to "warn"
or "silent"
, this method will do nothing.
this.load
类型: | Load |
---|
typescript
type Load = (options: {
id: string;
resolveDependencies?: boolean;
attributes?: Record<string, string> | null;
meta?: CustomPluginOptions | null;
moduleSideEffects?: boolean | 'no-treeshake' | null;
syntheticNamedExports?: boolean | string | null;
}) => Promise<ModuleInfo>;
加载并解析与给定 id 对应的模块,将附加元信息附加到模块(如果提供)。这将触发相同的 load
、transform
和 moduleParsed
钩子,如果该模块被另一个模块导入,这些钩子也会被触发。
¥Loads and parses the module corresponding to the given id, attaching additional meta information to the module if provided. This will trigger the same load
, transform
and moduleParsed
hooks that would be triggered if the module were imported by another module.
这允许你在决定如何在 resolveId
钩子中解析模块之前检查模块的最终内容,例如 改为解析为代理模块。如果模块稍后成为图的一部分,则使用此上下文函数不会产生额外的开销,因为该模块将不会被再次解析。该签名允许你直接将 this.resolve
的返回值传递给此函数,只要它既不是 null
也不是外部的。
¥This allows you to inspect the final content of modules before deciding how to resolve them in the resolveId
hook and e.g. resolve to a proxy module instead. If the module becomes part of the graph later, there is no additional overhead from using this context function as the module will not be parsed again. The signature allows you to directly pass the return value of this.resolve
to this function as long as it is neither null
nor external.
一旦模块完全转换和解析,但在解决任何导入之前,返回的 Promise 将解析。这意味着生成的 ModuleInfo
将具有空的 importedIds
、dynamicallyImportedIds
、importedIdResolutions
和 dynamicallyImportedIdResolutions
。这有助于避免在 resolveId
钩子中等待 this.load
时出现死锁情况。如果你对 importedIds
和 dynamicallyImportedIds
感兴趣,你可以实现 moduleParsed
钩子或传递 resolveDependencies
标志,这将使 this.load
返回的 Promise 等待,直到所有依赖 ID 都已解析。
¥The returned Promise will resolve once the module has been fully transformed and parsed but before any imports have been resolved. That means that the resulting ModuleInfo
will have empty importedIds
, dynamicallyImportedIds
, importedIdResolutions
and dynamicallyImportedIdResolutions
. This helps to avoid deadlock situations when awaiting this.load
in a resolveId
hook. If you are interested in importedIds
and dynamicallyImportedIds
, you can either implement a moduleParsed
hook or pass the resolveDependencies
flag, which will make the Promise returned by this.load
wait until all dependency ids have been resolved.
请注意,对于 attributes
、meta
、moduleSideEffects
和 syntheticNamedExports
选项,适用与 resolveId
钩子相同的限制:它们的值仅在模块尚未加载时才有效。因此,首先使用 this.resolve
来查明是否有任何插件想要在其 resolveId
钩子中为这些选项设置特殊值,然后在适当的情况下将这些选项传递给 this.load
是非常重要的。下面的示例展示了如何处理此问题,为包含特殊代码注释的模块添加代理模块。请注意重新导出默认导出的特殊处理:
¥Note that with regard to the attributes
, meta
, moduleSideEffects
and syntheticNamedExports
options, the same restrictions apply as for the resolveId
hook: Their values only have an effect if the module has not been loaded yet. Thus, it is very important to use this.resolve
first to find out if any plugins want to set special values for these options in their resolveId
hook, and pass these options on to this.load
if appropriate. The example below showcases how this can be handled to add a proxy module for modules containing a special code comment. Note the special handling for re-exporting the default export:
js
export default function addProxyPlugin() {
return {
async resolveId(source, importer, options) {
if (importer?.endsWith('?proxy')) {
// Do not proxy ids used in proxies
return null;
}
// We make sure to pass on any resolveId options to
// this.resolve to get the module id
const resolution = await this.resolve(source, importer, options);
// We can only pre-load existing and non-external ids
if (resolution && !resolution.external) {
// we pass on the entire resolution information
const moduleInfo = await this.load(resolution);
if (moduleInfo.code.includes('/* use proxy */')) {
return `${resolution.id}?proxy`;
}
}
// As we already fully resolved the module, there is no reason
// to resolve it again
return resolution;
},
load(id) {
if (id.endsWith('?proxy')) {
const importee = id.slice(0, -'?proxy'.length);
// Note that namespace reexports do not reexport default
// exports
let code = `console.log('proxy for ${importee}'); export * from ${JSON.stringify(
importee
)};`;
// We know that while resolving the proxy, importee was
// already fully loaded and parsed, so we can rely on
// hasDefaultExport
if (this.getModuleInfo(importee).hasDefaultExport) {
code += `export { default } from ${JSON.stringify(importee)};`;
}
return code;
}
return null;
}
};
}
如果模块已经加载,this.load
将等待解析完成,然后返回其模块信息。如果该模块尚未被其他模块导入,则不会自动触发加载该模块导入的其他模块。相反,只有在该模块实际导入至少一次后,才会加载静态和动态依赖。
¥If the module was already loaded, this.load
will just wait for the parsing to complete and then return its module information. If the module was not yet imported by another module, it will not automatically trigger loading other modules imported by this module. Instead, static and dynamic dependencies will only be loaded once this module has actually been imported at least once.
虽然在 resolveId
钩子中使用 this.load
是安全的,但在 load
或 transform
钩子中等待它时应该非常小心。如果模块图中存在循环依赖,这很容易导致死锁,因此任何插件都需要手动注意避免在与加载的模块处于循环的任何模块的 load
或 transform
内等待 this.load
。
¥While it is safe to use this.load
in a resolveId
hook, you should be very careful when awaiting it in a load
or transform
hook. If there are cyclic dependencies in the module graph, this can easily lead to a deadlock, so any plugin needs to manually take care to avoid waiting for this.load
inside the load
or transform
of the any module that is in a cycle with the loaded module.
这是另一个更详细的示例,其中我们通过 resolveDependencies
选项扫描整个依赖子图并重复调用 this.load
。我们使用 Set
个已处理模块 ID 来处理循环依赖。该插件的目标是向每个动态导入的块添加一个日志,仅列出该块中的所有模块。虽然这只是一个玩具示例,但该技术可用于例如 为子图中导入的所有 CSS 创建单个样式标签。
¥Here is another, more elaborate example where we scan entire dependency sub-graphs via the resolveDependencies
option and repeated calls to this.load
. We use a Set
of handled module ids to handle cyclic dependencies. The goal of the plugin is to add a log to each dynamically imported chunk that just lists all modules in the chunk. While this is just a toy example, the technique could be used to e.g. create a single style tag for all CSS imported in the sub-graph.
js
// The leading \0 instructs other plugins not to try to resolve, load or
// transform our proxy modules
const DYNAMIC_IMPORT_PROXY_PREFIX = '\0dynamic-import:';
export default function dynamicChunkLogsPlugin() {
return {
name: 'dynamic-chunk-logs',
async resolveDynamicImport(specifier, importer) {
// Ignore non-static targets
if (!(typeof specifier === 'string')) return;
// Get the id and initial meta information of the import target
const resolved = await this.resolve(specifier, importer);
// Ignore external targets. Explicit externals have the
// "external" property while unresolved imports are "null".
if (resolved && !resolved.external) {
// We trigger loading the module without waiting for it
// here because meta information attached by resolveId
// hooks, that may be contained in "resolved" and that
// plugins like "commonjs" may depend upon, is only
// attached to a module the first time it is loaded. This
// ensures that this meta information is not lost when we
// later use "this.load" again in the load hook with just
// the module id.
this.load(resolved);
return `${DYNAMIC_IMPORT_PROXY_PREFIX}${resolved.id}`;
}
},
async load(id) {
// Ignore all files except our dynamic import proxies
if (!id.startsWith('\0dynamic-import:')) return null;
const actualId = id.slice(DYNAMIC_IMPORT_PROXY_PREFIX.length);
// To allow loading modules in parallel while keeping
// complexity low, we do not directly await each "this.load"
// call but put their promises into an array where we await
// them via an async for loop.
const moduleInfoPromises = [
this.load({ id: actualId, resolveDependencies: true })
];
// We track each loaded dependency here so that we do not load
// a file twice and also do not get stuck when there are
// circular dependencies.
const dependencies = new Set([actualId]);
// "importedIdResolutions" tracks the objects created by
// resolveId hooks. We are using those instead of "importedIds"
// so that again, important meta information is not lost.
for await (const { importedIdResolutions } of moduleInfoPromises) {
for (const resolved of importedIdResolutions) {
if (!dependencies.has(resolved.id)) {
dependencies.add(resolved.id);
moduleInfoPromises.push(
this.load({ ...resolved, resolveDependencies: true })
);
}
}
}
// We log all modules in a dynamic chunk when it is loaded.
let code = `console.log([${[...dependencies]
.map(JSON.stringify)
.join(', ')}]); export * from ${JSON.stringify(actualId)};`;
// Namespace reexports do not reexport default exports, which
// is why we reexport it manually if it exists
if (this.getModuleInfo(actualId).hasDefaultExport) {
code += `export { default } from ${JSON.stringify(actualId)};`;
}
return code;
}
};
}
this.meta
类型: | {rollupVersion: string, watchMode: boolean} |
---|
包含潜在有用的 Rollup 元数据的对象:
¥An object containing potentially useful Rollup metadata:
rollupVersion
:当前运行的 Rollup 版本,如package.json
中定义。¥
rollupVersion
: The currently running version of Rollup as define inpackage.json
.watchMode
:如果 Rollup 是通过rollup.watch(...)
或从命令行启动的,则为true
,否则为--watch
、false
。¥
watchMode
:true
if Rollup was started viarollup.watch(...)
or from the command line with--watch
,false
otherwise.
meta
是唯一可通过 options
钩子访问的上下文属性。
¥meta
is the only context property accessible from the options
hook.
this.parse
类型: | (code: string, options?: ParseOptions) => ESTree.Program |
---|
typescript
interface ParseOptions {
allowReturnOutsideFunction?: boolean;
}
使用 Rollup 内部基于 SWC 的解析器将代码解析为 兼容 ESTree AST。
¥Use Rollup's internal SWC-based parser to parse code to an ESTree-compatible AST.
allowReturnOutsideFunction
:当true
时,这允许 return 语句位于函数之外,例如 支持解析 CommonJS 代码。¥
allowReturnOutsideFunction
: Whentrue
this allows return statements to be outside functions to e.g. support parsing CommonJS code.
this.resolve
类型: | Resolve |
---|
typescript
type Resolve = (
source: string,
importer?: string,
options?: {
skipSelf?: boolean;
isEntry?: boolean;
attributes?: { [key: string]: string };
custom?: { [plugin: string]: any };
}
) => ResolvedId;
提示
该钩子的返回类型 ResolvedId 在 this.getModuleInfo
中定义。
¥The return type ResolvedId of this hook is defined in this.getModuleInfo
.
使用 Rollup 使用的相同插件解析模块 ID(即文件名)的导入,并确定导入是否应该是外部的。如果返回 null
,则导入无法通过 Rollup 或任何插件解析,但用户未明确标记为外部。如果返回的绝对外部 id 应通过 makeAbsoluteExternalsRelative
选项或通过 resolveId
钩子中的显式插件选择在输出中保持绝对,则 external
将是 "absolute"
而不是 true
。
¥Resolve imports to module ids (i.e. file names) using the same plugins that Rollup uses, and determine if an import should be external. If null
is returned, the import could not be resolved by Rollup or any plugin but was not explicitly marked as external by the user. If an absolute external id is returned that should remain absolute in the output either via the makeAbsoluteExternalsRelative
option or by explicit plugin choice in the resolveId
hook, external
will be "absolute"
instead of true
.
skipSelf
的默认值是 true
,因此解析时将跳过调用 this.resolve
的插件的 resolveId
钩子。当其他插件本身在处理原始 this.resolve
调用时也在其 resolveId
钩子中使用完全相同的 source
和 importer
调用 this.resolve
时,那么原始插件的 resolveId
钩子也将被跳过这些调用。这里的基本原理是,插件已经声明 "不知道" 如何在此时解决 source
和 importer
的特定组合。如果你不希望出现这种行为,请将 skipSelf
设置为 false
,并在必要时实现你自己的无限循环预防机制。
¥The default of skipSelf
is true
, So the resolveId
hook of the plugin from which this.resolve
is called will be skipped when resolving. When other plugins themselves also call this.resolve
in their resolveId
hooks with the exact same source
and importer
while handling the original this.resolve
call, then the resolveId
hook of the original plugin will be skipped for those calls as well. The rationale here is that the plugin already stated that it "does not know" how to resolve this particular combination of source
and importer
at this point in time. If you do not want this behaviour, set skipSelf
to false
and implement your own infinite loop prevention mechanism if necessary.
你还可以通过 custom
选项传递插件特定选项的对象,有关详细信息,请参阅 自定义解析器选项。
¥You can also pass an object of plugin-specific options via the custom
option, see custom resolver options for details.
你在此处传递的 isEntry
的值将传递到处理此调用的 resolveId
钩子,否则,如果有导入程序,则将传递 false
;如果没有,则将传递 true
。
¥The value for isEntry
you pass here will be passed along to the resolveId
hooks handling this call, otherwise false
will be passed if there is an importer and true
if there is not.
如果你传递 attributes
的对象,它将模拟使用断言解析导入,例如 attributes: {type: "json"}
模拟解析 import "foo" assert {type: "json"}
。这将被传递给任何处理此调用的 resolveId
钩子,并可能最终成为返回对象的一部分。
¥If you pass an object for attributes
, it will simulate resolving an import with an assertion, e.g. attributes: {type: "json"}
simulates resolving import "foo" assert {type: "json"}
. This will be passed to any resolveId
hooks handling this call and may ultimately become part of the returned object.
从 resolveId
钩子调用此函数时,你应该始终检查传递 isEntry
、custom
和 attributes
选项是否有意义。
¥When calling this function from a resolveId
hook, you should always check if it makes sense for you to pass along the isEntry
, custom
and attributes
options.
resolvedBy
的值指的是哪个插件解析了这个源。如果是 Rollup 自己解决的,则该值为 "Rollup"。如果插件中的 resolveId
钩子解析此源,则该值将是插件的名称,除非它返回 resolvedBy
的显式值。该标志仅用于调试和文档目的,不会由 Rollup 进一步处理。
¥The value of resolvedBy
refers to which plugin resolved this source. If it was resolved by Rollup itself, the value will be "rollup". If a resolveId
hook in a plugin resolves this source, the value will be the name of the plugin unless it returned an explicit value for resolvedBy
. This flag is only for debugging and documentation purposes and is not processed further by Rollup.
this.setAssetSource
类型: | (referenceId: string, source: string | Uint8Array) => void |
---|
设置资源的延迟来源。请注意,你还可以将节点 Buffer
作为 source
传递,因为它是 Uint8Array
的子类。
¥Set the deferred source of an asset. Note that you can also pass a Node Buffer
as source
as it is a sub-class of Uint8Array
.
this.warn
类型: | (log: string | RollupLog | (() => RollupLog | string), position?: number | { column: number; line: number }) => void |
---|
使用此方法将生成构建警告,这些警告是日志级别 "warn"
的日志。有关 RollupLog
类型的信息,请参阅 onLog
选项。要生成其他日志,另请参阅 this.info
和 this.debug
。要生成错误,请参阅 this.error
。
¥Using this method will generate warnings for a build, which are logs with log level "warn"
. See the onLog
option for information about the RollupLog
type. To generate other logs, see also this.info
and this.debug
. To generate errors, see this.error
.
就像内部生成的警告一样,这些日志将首先传递到插件 onLog
钩子并由其过滤,然后再转发到自定义 onLog
或 onwarn
处理程序或打印到控制台。
¥Just like internally generated warnings, these logs will be first passed to and filtered by plugin onLog
hooks before they are forwarded to custom onLog
or onwarn
handlers or printed to the console.
warning
参数可以是 string
或具有(至少)message
属性的对象:
¥The warning
argument can be a string
or an object with (at minimum) a message
property:
js
this.warn('hmm...');
// is equivalent to
this.warn({
message: 'hmm...',
pluginCode: 'CODE_TO_IDENTIFY_LOG',
meta: 'Additional plugin specific information'
});
我们鼓励你使用具有 pluginCode
属性的对象,因为这将允许用户在 onLog
处理程序中轻松过滤这些日志。如果需要添加其他信息,可以使用 meta
属性。如果日志包含 code
并且还没有 pluginCode
属性,它将被重命名为 pluginCode
,因为插件警告始终会获得由 Rollup 添加的 code
或 PLUGIN_WARNING
。为了防止这种行为,插件可以使用传递给 buildStart
钩子的规范化 onLog
选项。将日志传递给插件 onLog
处理程序和 onLog
或 onwarn
处理程序时,从插件调用此选项不会更改属性。
¥We encourage you to use objects with a pluginCode
property as that will allow users to easily filter for those logs in an onLog
handler. If you need to add additional information, you can use the meta
property. If the log contains a code
and does not yet have a pluginCode
property, it will be renamed to pluginCode
as plugin warnings always get a code
of PLUGIN_WARNING
added by Rollup. To prevent this behavior, plugins can instead use the normalized onLog
option passed to the buildStart
hook. Calling this option from a plugin will not change properties when passing the log to plugin onLog
handlers and onLog
or onwarn
handlers.
如果你需要进行昂贵的计算来生成日志,你还可以传递一个返回 string
或 RollupLog
对象的函数。仅当日志未通过 logLevel
选项过滤时才会调用此函数。
¥If you need to do expensive computations to generate a log, you can also pass a function returning either a string
or a RollupLog
object. This function will only be called if the log is not filtered by the logLevel
option.
js
// This will only run if the logLevel is set to "debug"
this.debug(() => generateExpensiveDebugLog());
当在 transform
钩子中使用时,当前模块的 id
也会被添加,并且可以提供 position
。这是一个字符索引或文件位置,将用于使用 pos
、loc
(标准 { file, line, column }
对象)和 frame
(显示位置的代码片段)来扩充日志。
¥When used in the transform
hook, the id
of the current module will also be added and a position
can be supplied. This is a character index or file location which will be used to augment the log with pos
, loc
(a standard { file, line, column }
object) and frame
(a snippet of code showing the location).
如果 logLevel
选项设置为 "silent"
,则此方法将不执行任何操作。
¥If the logLevel
option is set to "silent"
, this method will do nothing.
文件网址
¥File URLs
要从 JS 代码中引用文件 URL 引用,请使用 import.meta.ROLLUP_FILE_URL_referenceId
替换。这将生成取决于输出格式的代码,并生成指向目标环境中触发的文件的 URL。请注意,除 CommonJS 和 UMD 之外的所有格式都假定它们在 URL
和 document
可用的浏览器环境中运行。
¥To reference a file URL reference from within JS code, use the import.meta.ROLLUP_FILE_URL_referenceId
replacement. This will generate code that depends on the output format and generates a URL that points to the emitted file in the target environment. Note that all formats except CommonJS and UMD assume that they run in a browser environment where URL
and document
are available.
以下示例将检测 .svg
文件的导入,将导入的文件作为资源触发,并返回要使用的 URL,例如 作为 img
标签的 src
属性:
¥The following example will detect imports of .svg
files, emit the imported files as assets, and return their URLs to be used e.g. as the src
attribute of an img
tag:
js
function svgResolverPlugin() {
return {
name: 'svg-resolver',
resolveId(source, importer) {
if (source.endsWith('.svg')) {
return path.resolve(path.dirname(importer), source);
}
},
load(id) {
if (id.endsWith('.svg')) {
const referenceId = this.emitFile({
type: 'asset',
name: path.basename(id),
source: fs.readFileSync(id)
});
return `export default import.meta.ROLLUP_FILE_URL_${referenceId};`;
}
}
};
}
用法:
¥Usage:
js
import logo from '../images/logo.svg';
const image = document.createElement('img');
image.src = logo;
document.body.appendChild(image);
有时,引用此资源的代码仅有条件地使用,如下例所示:
¥Sometimes, the code which referenced this asset is only used conditionally like in the following example:
js
import logo from '../images/logo.svg';
if (COMPILER_FLAG) {
const image = document.createElement('img');
image.src = logo;
document.body.appendChild(image);
}
如果一个插件将 COMPILER_FLAG
替换为 false
,那么我们会得到意想不到的结果:未引用的资源仍会触发但未使用。我们可以通过在调用 this.emitFile
时将 needsCodeReference
设置为 true 来解决这个问题,如下代码:
¥If a plugin replaces COMPILER_FLAG
with false
, then we will get an unexpected result: The unreferenced asset is still emitted but unused. We can resolve this problem by setting needsCodeReference
to true when calling this.emitFile
, like in the following code:
js
function svgResolverPlugin() {
return {
/* ... */
load(id) {
if (id.endsWith('.svg')) {
const referenceId = this.emitFile({
type: 'asset',
name: path.basename(id),
needsCodeReference: true,
source: fs.readFileSync(id)
});
return `export default import.meta.ROLLUP_FILE_URL_${referenceId};`;
}
}
};
}
现在,只有在代码中实际使用引用 import.meta.ROLLUP_FILE_URL_referenceId
时,资源才会添加到打包包中。
¥Now the asset will only be added to the bundle if the reference import.meta.ROLLUP_FILE_URL_referenceId
is actually used in the code.
与资源类似,触发的块也可以通过 import.meta.ROLLUP_FILE_URL_referenceId
从 JS 代码中引用。
¥Similar to assets, emitted chunks can be referenced from within JS code via import.meta.ROLLUP_FILE_URL_referenceId
as well.
以下示例将检测以 register-paint-worklet:
为前缀的导入,并生成必要的代码和单独的块以生成 CSS 绘制工作集。请注意,这仅适用于现代浏览器,并且仅在输出格式设置为 es
时才有效。
¥The following example will detect imports prefixed with register-paint-worklet:
and generate the necessary code and separate chunk to generate a CSS paint worklet. Note that this will only work in modern browsers and will only work if the output format is set to es
.
js
const REGISTER_WORKLET = 'register-paint-worklet:';
function registerPaintWorkletPlugin() {
return {
name: 'register-paint-worklet',
load(id) {
if (id.startsWith(REGISTER_WORKLET)) {
return `CSS.paintWorklet.addModule(import.meta.ROLLUP_FILE_URL_${this.emitFile(
{
type: 'chunk',
id: id.slice(REGISTER_WORKLET.length)
}
)});`;
}
},
resolveId(source, importer) {
// We remove the prefix, resolve everything to absolute ids and
// add the prefix again. This makes sure that you can use
// relative imports to define worklets
if (source.startsWith(REGISTER_WORKLET)) {
return this.resolve(
source.slice(REGISTER_WORKLET.length),
importer
).then(resolvedId => REGISTER_WORKLET + resolvedId.id);
}
return null;
}
};
}
用法:
¥Usage:
js
// main.js
import 'register-paint-worklet:./worklet.js';
import { color, size } from './config.js';
document.body.innerHTML += `<h1 style="background-image: paint(vertical-lines);">color: ${color}, size: ${size}</h1>`;
// worklet.js
import { color, size } from './config.js';
registerPaint(
'vertical-lines',
class {
paint(ctx, geom) {
for (let x = 0; x < geom.width / size; x++) {
ctx.beginPath();
ctx.fillStyle = color;
ctx.rect(x * size, 0, 2, geom.height);
ctx.fill();
}
}
}
);
// config.js
export const color = 'greenyellow';
export const size = 6;
如果你构建此代码,主块和工作集都将通过共享块共享 config.js
中的代码。这使我们能够利用浏览器缓存来减少传输的数据并加快工作集的加载速度。
¥If you build this code, both the main chunk and the worklet will share the code from config.js
via a shared chunk. This enables us to make use of the browser cache to reduce transmitted data and speed up loading the worklet.
转换器
¥Transformers
Transformer 插件(即那些返回 transform
函数的插件,例如用于转译非 JS 文件的插件)应该支持 options.include
和 options.exclude
,这两个插件都可以是迷你匹配模式或迷你匹配模式数组。如果省略 options.include
或长度为零,则默认包含文件;否则,仅当 ID 与其中一种模式匹配时才应包含它们。
¥Transformer plugins (i.e. those that return a transform
function for e.g. transpiling non-JS files) should support options.include
and options.exclude
, both of which can be a minimatch pattern or an array of minimatch patterns. If options.include
is omitted or of zero length, files should be included by default; otherwise they should only be included if the ID matches one of the patterns.
transform
钩子如果返回对象,还可以包含 ast
属性。仅当你知道自己在做什么时才使用此功能。请注意,只会使用转换链中的最后一个 AST(如果存在转换,则对于转换后的模块,load
钩子生成的任何 AST 都将被丢弃。)
¥The transform
hook, if returning an object, can also include an ast
property. Only use this feature if you know what you're doing. Note that only the last AST in a chain of transforms will be used (and if there are transforms, any ASTs generated by the load
hook will be discarded for the transformed modules.)
转换器示例
¥Example Transformer
(使用 @rollup/pluginutils 来实现常用功能,并以推荐的方式实现转换器。)
¥(Use @rollup/pluginutils for commonly needed functions, and to implement a transformer in the recommended manner.)
js
import { createFilter } from '@rollup/pluginutils';
function transformCodePlugin(options = {}) {
const filter = createFilter(options.include, options.exclude);
return {
name: 'transform-code',
transform(code, id) {
if (!filter(id)) return;
// proceed with the transformation...
return {
code: generatedCode,
map: generatedSourceMap
};
}
};
}
源代码转换
¥Source Code Transformations
如果插件转换源代码,它应该自动生成源映射,除非有特定的 sourceMap: false
选项。Rollup 只关心 mappings
属性(其他所有内容都会自动处理)。魔术弦 提供了一种简单的方法来生成此类映射以进行基本转换(例如添加或删除代码片段)。
¥If a plugin transforms source code, it should generate a sourcemap automatically, unless there's a specific sourceMap: false
option. Rollup only cares about the mappings
property (everything else is handled automatically). magic-string provides a simple way to generate such a map for elementary transformations like adding or removing code snippets.
如果生成源映射没有意义(例如 rollup-plugin-string),则返回空源映射:
¥If it doesn't make sense to generate a sourcemap, (e.g. rollup-plugin-string), return an empty sourcemap:
js
return {
code: transformedCode,
map: { mappings: '' }
};
如果转换不移动代码,你可以通过返回 null
来保留现有的源映射:
¥If the transformation does not move code, you can preserve existing sourcemaps by returning null
:
js
return {
code: transformedCode,
map: null
};
如果你创建了一个你认为对其他人有用的插件,请将其发布到 NPM 并添加提交到 github.com/rollup/awesome!
¥If you create a plugin that you think would be useful to others, please publish it to NPM and add submit it to github.com/rollup/awesome!
综合命名导出
¥Synthetic named exports
通过在 resolveId
、load
或 transform
钩子中为模块设置 syntheticNamedExports
选项,可以为丢失的导出指定后备导出。如果字符串值用于 syntheticNamedExports
,则此模块会将任何缺失的命名导出的解析回退到给定名称的命名导出的属性:
¥It is possible to designate a fallback export for missing exports by setting the syntheticNamedExports
option for a module in the resolveId
, load
or transform
hook. If a string value is used for syntheticNamedExports
, this module will fallback the resolution of any missing named exports to properties of the named export of the given name:
dep.js:({syntheticNamedExports: '__synthetic'}
)
js
export const foo = 'explicit';
export const __synthetic = {
foo: 'foo',
bar: 'bar'
};
main.js:
js
import { foo, bar, baz, __synthetic } from './dep.js';
// logs "explicit" as non-synthetic exports take precedence
console.log(foo);
// logs "bar", picking the property from __synthetic
console.log(bar);
// logs "undefined"
console.log(baz);
// logs "{foo:'foo',bar:'bar'}"
console.log(__synthetic);
当用作入口点时,只会公开显式导出。合成后备导出(即示例中的 __synthetic
)不会针对 syntheticNamedExports
的字符串值公开。但是,如果值为 true
,则会暴露默认导出。这是 syntheticNamedExports: true
和 syntheticNamedExports: 'default'
之间唯一显着的区别。
¥When used as an entry point, only explicit exports will be exposed. The synthetic fallback export, i.e. __synthetic
in the example, will not be exposed for string values of syntheticNamedExports
. However, if the value is true
, the default export will be exposed. This is the only notable difference between syntheticNamedExports: true
and syntheticNamedExports: 'default'
.
插件间通信
¥Inter-plugin communication
在使用许多专用插件时的某些时候,可能需要不相关的插件能够在构建过程中交换信息。Rollup 通过多种机制使这成为可能。
¥At some point when using many dedicated plugins, there may be the need for unrelated plugins to be able to exchange information during the build. There are several mechanisms through which Rollup makes this possible.
自定义解析器选项
¥Custom resolver options
假设你有一个插件,该插件应根据另一个插件生成导入的方式来解析对不同 id 的导入。实现此目的的一种方法是重写导入以使用特殊的代理 ID,例如 CommonJS 文件中通过 require("foo")
进行的转译导入可以成为具有特殊 id import "foo?require=true"
的常规导入,以便解析器插件知道这一点。
¥Assume you have a plugin that should resolve an import to different ids depending on how the import was generated by another plugin. One way to achieve this would be to rewrite the import to use special proxy ids, e.g. a transpiled import via require("foo")
in a CommonJS file could become a regular import with a special id import "foo?require=true"
so that a resolver plugin knows this.
然而,这里的问题是,这个代理 ID 在传递给其他解析器时可能会也可能不会导致意外的副作用,因为它并不真正对应于文件。此外,如果 id 是由插件 A
创建的,并且解析发生在插件 B
中,则会在这些插件之间创建依赖,以便在没有 B
的情况下 A
无法使用。
¥The problem here, however, is that this proxy id may or may not cause unintended side effects when passed to other resolvers because it does not really correspond to a file. Moreover, if the id is created by plugin A
and the resolution happens in plugin B
, it creates a dependency between these plugins so that A
is not usable without B
.
自定义解析器选项在这里提供了一个解决方案,允许在通过 this resolve
手动解析模块时传递插件的附加选项。发生这种情况时不会更改 id,因此如果预期的目标插件不存在,也不会影响其他插件正确解析模块的能力。
¥Custom resolver option offer a solution here by allowing to pass additional options for plugins when manually resolving a module via this resolve
. This happens without changing the id and thus without impairing the ability for other plugins to resolve the module correctly if the intended target plugin is not present.
js
function requestingPlugin() {
return {
name: 'requesting',
async buildStart() {
const resolution = await this.resolve('foo', undefined, {
custom: { resolving: { specialResolution: true } }
});
console.log(resolution.id); // "special"
}
};
}
function resolvingPlugin() {
return {
name: 'resolving',
resolveId(id, importer, { custom }) {
if (custom.resolving?.specialResolution) {
return 'special';
}
return null;
}
};
}
请注意,应使用与解析插件的插件名称相对应的属性来添加自定义选项。解析插件有责任指定它尊重哪些选项。
¥Note the convention that custom options should be added using a property corresponding to the plugin name of the resolving plugin. It is responsibility of the resolving plugin to specify which options it respects.
自定义模块元数据
¥Custom module meta-data
插件可以使用自定义元数据来注释模块,这些元数据可以由它们自己和其他插件通过 resolveId
、load
和 transform
钩子设置,并通过 this.getModuleInfo
、this.load
和 moduleParsed
钩子访问。此元数据应始终为 JSON.stringifyable 并将保留在缓存中,例如 在监视模式下。
¥Plugins can annotate modules with custom meta-data which can be set by themselves and other plugins via the resolveId
, load
, and transform
hooks and accessed via this.getModuleInfo
, this.load
and the moduleParsed
hook. This meta-data should always be JSON.stringifyable and will be persisted in the cache e.g. in watch mode.
js
function annotatingPlugin() {
return {
name: 'annotating',
transform(code, id) {
if (thisModuleIsSpecial(code, id)) {
return { meta: { annotating: { special: true } } };
}
}
};
}
function readingPlugin() {
let parentApi;
return {
name: 'reading',
buildEnd() {
const specialModules = Array.from(this.getModuleIds()).filter(
id => this.getModuleInfo(id).meta.annotating?.special
);
// do something with this list
}
};
}
请注意,添加或修改数据的插件应使用与插件名称相对应的属性(在本例中为 annotating
)。另一方面,任何插件都可以通过 this.getModuleInfo
从其他插件读取所有元数据。
¥Note the convention that plugins that add or modify data should use a property corresponding to the plugin name, in this case annotating
. On the other hand, any plugin can read all meta-data from other plugins via this.getModuleInfo
.
如果多个插件添加元数据或者元数据添加在不同的钩子中,那么这些 meta
对象将被浅层合并。这意味着如果插件 first
在 resolveId 钩子中添加 {meta: {first: {resolved: "first"}}}
,在 load 钩子中添加 {meta: {first: {loaded: "first"}}}
,而插件 second
在 transform
钩子中添加 {meta: {second: {transformed: "second"}}}
,那么生成的 meta
对象将是 {first: {loaded: "first"}, second: {transformed: "second"}}
。这里 resolveId
钩子的结果将被 load
钩子的结果覆盖,因为插件都将它们存储在其 first
顶层属性下。另一方面,另一个插件的 transform
数据将放置在它旁边。
¥If several plugins add meta-data or meta-data is added in different hooks, then these meta
objects will be merged shallowly. That means if plugin first
adds {meta: {first: {resolved: "first"}}}
in the resolveId hook and {meta: {first: {loaded: "first"}}}
in the load hook while plugin second
adds {meta: {second: {transformed: "second"}}}
in the transform
hook, then the resulting meta
object will be {first: {loaded: "first"}, second: {transformed: "second"}}
. Here the result of the resolveId
hook will be overwritten by the result of the load
hook as the plugin was both storing them under its first
top-level property. The transform
data of the other plugin on the other hand will be placed next to it.
模块的 meta
对象在 Rollup 开始加载模块时立即创建,并针对模块的每个生命周期钩子进行更新。如果你存储对此对象的引用,你还可以手动更新它。要访问尚未加载的模块的元对象,可以通过 this.load
触发其创建并加载模块:
¥The meta
object of a module is created as soon as Rollup starts loading a module and is updated for each lifecycle hook of the module. If you store a reference to this object, you can also update it manually. To access the meta object of a module that has not been loaded yet, you can trigger its creation and loading the module via this.load
:
js
function plugin() {
return {
name: 'test',
buildStart() {
// trigger loading a module. We could also pass an initial
// "meta" object here, but it would be ignored if the module
// was already loaded via other means
this.load({ id: 'my-id' });
// the module info is now available, we do not need to await
// this.load
const meta = this.getModuleInfo('my-id').meta;
// we can also modify meta manually now
meta.test = { some: 'data' };
}
};
}
直接插件通信
¥Direct plugin communication
对于任何其他类型的插件间通信,我们推荐以下模式。请注意,api
永远不会与任何即将推出的插件钩子发生冲突。
¥For any other kind of inter-plugin communication, we recommend the pattern below. Note that api
will never conflict with any upcoming plugin hooks.
js
function parentPlugin() {
return {
name: 'parent',
api: {
//...methods and properties exposed for other plugins
doSomething(...args) {
// do something interesting
}
}
// ...plugin hooks
};
}
function dependentPlugin() {
let parentApi;
return {
name: 'dependent',
buildStart({ plugins }) {
const parentName = 'parent';
const parentPlugin = plugins.find(
plugin => plugin.name === parentName
);
if (!parentPlugin) {
// or handle this silently if it is optional
throw new Error(
`This plugin depends on the "${parentName}" plugin.`
);
}
// now you can access the API methods in subsequent hooks
parentApi = parentPlugin.api;
},
transform(code, id) {
if (thereIsAReasonToDoSomething(id)) {
parentApi.doSomething(id);
}
}
};
}