如何在Parcel插件中获取当前构建的target名称
Parcel 的 Transformer 运行在资产通用处理阶段,同一个资产可能被多个构建 target 复用,这个阶段还没完成 target 维度的拆分,所以你在asset.env里拿不到 target 名称是正常的。以下三种方案都能实现 manifest 按 target 合并的需求,按推荐优先级排序:
方案1:通过 browsers 配置反推 target(改动最小)
你已经给每个 target 配置了专属的 browserslist 规则,直接从asset.env.engines.browsers读取配置判断当前所属 target 即可,不需要获取显式的 target 名称。
核心 Transformer 逻辑参考:async transform({ asset }) { const browsers = asset.env.engines.browsers; let targetSuffix = ""; if (browsers.some(item => item.toLowerCase().includes("firefox"))) { targetSuffix = "firefox"; } else if (browsers.some(item => item.toLowerCase().includes("chrome"))) { targetSuffix = "chrome"; } const baseManifest = JSON.parse(await asset.getCode()); let targetManifest = {}; if (targetSuffix) { const targetPath = await asset.resolve(`./manifest.${targetSuffix}.json`); targetManifest = JSON.parse(await asset.fs.readFile(targetPath, "utf8")); } // 注意针对manifest的数组类型字段做专门合并,避免被全量覆盖 const merged = { ...baseManifest, ...targetManifest, permissions: [...new Set([...(baseManifest.permissions || []), ...(targetManifest.permissions || [])])], host_permissions: [...new Set([...(baseManifest.host_permissions || []), ...(targetManifest.host_permissions || [])])], content_scripts: [...(baseManifest.content_scripts || []), ...(targetManifest.content_scripts || [])] }; asset.setCode(JSON.stringify(merged, null, 2)); return [asset]; }这个方案不需要改动你现有插件结构,完全在 Transformer 生命周期内完成,适配你“收集依赖前合并”的需求。
方案2:用 Packager 插件获取精确 target 名
如果你需要严格读取package.json里定义的 target 名称,改用 Packager 类型的插件即可。Packager 运行在 target 拆分完成之后,每个 bundle 对应唯一 target,package方法入参里的bundle.target.name就是你定义的firefox/chrome字段。
你可以把自定义 Packager 注册为manifest.json的专属处理器,在打包输出阶段完成文件合并,合并逻辑和上面的代码一致,不需要反推 target,准确性更高。方案3:构建命令注入环境变量(不推荐)
你也可以拆分构建命令,分别执行单 target 构建,每次执行前注入对应TARGET_NAME环境变量,在 Transformer 里直接读取process.env.TARGET_NAME即可。但这个方案没法利用 Parcel 多 target 并行构建的能力,构建效率更低。
注意:不要尝试在 Transformer 里通过缓存全局 target 列表的方式硬匹配 target,Parcel 多 target 构建是并行运行的,这种写法很容易出现资产串 target 的问题,导致 manifest 合并错误。
内容的提问来源于stack exchange,提问作者Melted Away

