# this.emitFile

类型:
(emittedFile: EmittedChunk | EmittedAsset) => string
interface EmittedChunk {
	type: 'chunk';
	id: string;
	name?: string;
	fileName?: string;
	implicitlyLoadedAfterOneOf?: string[];
	importer?: string;
	preserveSignature?: 'strict' | 'allow-extension' | 'exports-only' | false;
}

interface EmittedAsset {
	type: 'asset';
	name?: string;
	needsCodeReference?: boolean;
	fileName?: string;
	source?: string | Uint8Array;
}

emitFile 方法可以生成一个新的文件,并将其包含在构建输出中。同时,它会返回一个 referenceId,可以在各种地方使用该 referenceId 来引用生成的文件。你可以生成代码块或者资源文件。

在两种情况下,都可以提供 name 或 fileName。如果提供了 fileName,它将被直接用作生成文件的名称,如果这会导致冲突,则会抛出错误。否则,如果提供了name,则会将其用作相应的 output.chunkFileNames 或 output.assetFileNames 模式中的 [name] 的替换,可能会在文件名的末尾添加一个唯一的数字以避免冲突。如果既没有提供 name 也没有提供 fileName,则会使用默认名称。

你可以通过 import.meta.ROLLUP_FILE_URL_referenceId 在任何由 load 或 transform 插件钩子返回的代码中引用生成的文件的 URL。有关更多详细信息和示例,请参见 File URL。

替换 import.meta.ROLLUP_FILE_URL_referenceId 的生成代码可以通过 resolveFileUrl 插件钩子进行自定义。你也可以使用 this.getFileName(referenceId) 在文件名可用时确定文件名。如果没有显式设置文件名,则

  • 资源文件名从 renderStart 钩子开始可用。对于稍后生成的资源,文件名将在生成资源后立即可用。
  • 不包含哈希的代码块文件名在 renderStart 钩子后创建代码块后立即可用。
  • 如果代码块文件名包含哈希,则在 generateBundle 之前的任何钩子中使用 getFileName 将返回一个包含占位符而不是实际名称的名称。如果你在 renderChunk 中转换的代码块中使用了这个文件名或其中的部分,Rollup 将在 generateBundle 之前用实际哈希替换占位符,确保哈希反映最终生成的代码块的实际内容,包括所有引用的文件哈希。

如果 type 是 chunk,则会生成一个以给定模块 id 为入口点的新代码块。为了解析它,id 将通过构建钩子传递,就像常规入口点一样,从 resolveId 开始。如果提供了importer,它将作为 resolveId 的第二个参数,并且对于正确解析相对路径非常重要。如果没有提供它,路径将相对于当前工作目录解析。如果提供了 preserveSignature 的值,它将覆盖 preserveEntrySignatures 的值。

这不会导致图中出现重复的模块,而是如果必要的话,现有的代码块将被拆分或创建一个带有重新导出的外观代码块。具有指定 fileName 的代码块将始终生成单独的代码块,而其他生成的代码块可能会与现有的代码块进行去重,即使 name 不匹配。如果这样的代码块没有被去重,将使用 output.chunkFileNames 名称模式。

默认情况下,Rollup 假定生成的代码块独立于其他入口点执行,甚至可能在任何其他代码执行之前执行。这意味着如果生成的代码块与现有入口点共享依赖关系,Rollup 将为这些入口点之间共享的依赖项创建一个额外的代码块。提供一个非空的模块 id 数组作为 implicitlyLoadedAfterOneOf 的值将改变这种行为,通过为 Rollup 提供额外的信息,在某些情况下防止这种情况发生。这些 id 将像 id 属性一样被解析,如果提供了 importer 属性,则会尊重它。现在,Rollup 将假定生成的代码块仅在已经执行了至少一个导致 implicitlyLoadedAfterOneOf 中的一个 id 被加载的入口点时才会执行,创建与通过动态导入从 implicitlyLoadedAfterOneOf 中的模块到达新生成的代码块时相同的代码块。下面是一个使用此功能创建简单 HTML 文件的示例,其中包含多个脚本,创建优化的代码块以遵守它们的执行顺序:

// rollup.config.js
function generateHtmlPlugin() {
	let ref1, ref2, 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 的依赖项,这些依赖项不包含在第一个块中,并从第一个块中导入它们,第三个块也是同样的情况。

请注意,即使在 implicitlyLoadedAfterOneOf 中可以使用任何模块 ID,如果这样的 ID 不能与块唯一关联,例如因为 id 不能从现有的静态入口点隐式或显式地到达,或者因为文件被完全剪枝,Rollup 也会抛出错误。只使用入口点,无论是用户定义的还是先前发出的块,都将始终起作用。

如果 type 是 asset,则会发出一个具有给定 source 内容的任意新文件。可以通过 this.setAssetSource(referenceId, source) 推迟设置 source 到稍后的时间,以便在生成阶段期间能够引用文件,同时为每个输出单独设置源。具有指定 fileName 的资源将始终生成单独的文件,而其他发出的资源可能会与现有资源进行去重,即使 name 不匹配,但它们具有相同的源。如果没有 fileName 的资源没有被去重,则将使用 output.assetFileNames 名称模式。如果将 needsCodeReference 设置为 true ,并且此资源在输出中没有被任何代码引用,即没有通过 import.meta.ROLLUP_FILE_URL_referenceId 引用,则 Rollup 将不会发出它。这也尊重通过除屑优化除去的引用,即如果相应的 import.meta.ROLLUP_FILE_URL_referenceId 是源代码的一部分,但实际上没有使用并且引用被除屑优化除去,则不会发出该资源。

Last Updated: 6/14/2023, 8:56:23 AM