From ff8d262204915ec100b3ee45ad69a42ab562a9c6 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig <4586894+mischnic@users.noreply.github.com> Date: Fri, 5 Aug 2022 11:58:04 +0200 Subject: [PATCH] Different API for config loading --- packages/core/core/src/PackagerRunner.js | 166 +++++++++++++----- packages/core/core/src/ParcelConfig.js | 8 +- .../core/core/src/requests/ConfigRequest.js | 17 ++ .../core/src/requests/WriteBundlesRequest.js | 5 +- packages/core/plugin/src/PluginAPI.js | 4 +- packages/core/types/index.js | 22 ++- 6 files changed, 167 insertions(+), 55 deletions(-) diff --git a/packages/core/core/src/PackagerRunner.js b/packages/core/core/src/PackagerRunner.js index 3c18a16c10b..350471229f1 100644 --- a/packages/core/core/src/PackagerRunner.js +++ b/packages/core/core/src/PackagerRunner.js @@ -50,7 +50,7 @@ import { loadPluginConfig, getConfigHash, getConfigRequests, - type PluginWithLoadConfig, + type PluginWithLoadConfigGlobalInfo, } from './requests/ConfigRequest'; import { createDevDependency, @@ -143,12 +143,20 @@ export default class PackagerRunner { ): Promise { invalidateDevDeps(invalidDevDeps, this.options, this.config); - let configs = await this.loadConfigs(bundleGraph, bundle); + let {configs, globalInfos} = await this.loadConfigs(bundleGraph, bundle); let bundleInfo = - (await this.getBundleInfoFromCache(bundleGraph, bundle, configs)) ?? - (await this.getBundleInfo(bundle, bundleGraph, configs)); - - let configRequests = getConfigRequests([...configs.values()]); + (await this.getBundleInfoFromCache( + bundleGraph, + bundle, + configs, + globalInfos, + )) ?? + (await this.getBundleInfo(bundle, bundleGraph, configs, globalInfos)); + + let configRequests = getConfigRequests([ + ...configs.values(), + ...globalInfos.values(), + ]); let devDepRequests = getWorkerDevDepRequests([ ...this.devDepRequests.values(), ]); @@ -164,70 +172,108 @@ export default class PackagerRunner { async loadConfigs( bundleGraph: InternalBundleGraph, bundle: InternalBundle, - ): Promise> { + ): Promise<{| + configs: Map, + globalInfos: Map, + |}> { let configs = new Map(); + let globalInfos = new Map(); - await this.loadConfig(bundle, configs); + await this.loadConfig(bundleGraph, bundle, configs, globalInfos); for (let inlineBundle of bundleGraph.getInlineBundles(bundle)) { - await this.loadConfig(inlineBundle, configs); + await this.loadConfig(bundleGraph, inlineBundle, configs, globalInfos); } - return configs; + return {configs, globalInfos}; } async loadConfig( + bundleGraph: InternalBundleGraph, bundle: InternalBundle, configs: Map, + globalInfos: Map, ): Promise { let name = nullthrows(bundle.name); let plugin = await this.config.getPackager(name); - await this.loadPluginConfig(plugin, configs); + await this.loadPluginConfig( + bundleGraph, + bundle, + plugin, + configs, + globalInfos, + ); let optimizers = await this.config.getOptimizers(name, bundle.pipeline); - for (let optimizer of optimizers) { - await this.loadPluginConfig(optimizer, configs); + await this.loadPluginConfig( + bundleGraph, + bundle, + optimizer, + configs, + globalInfos, + ); } } - async loadPluginConfig( + async loadPluginConfig( + bundleGraph: InternalBundleGraph, + bundle: InternalBundle, plugin: LoadedPlugin, configs: Map, + globalInfos: Map, ): Promise { - if (configs.has(plugin.name)) { - return; - } + if (!configs.has(plugin.name)) { + // Only load config for a plugin once per build. + let existing = pluginConfigs.get(plugin.name); + if (existing != null) { + configs.set(plugin.name, existing); + } else { + if (plugin.plugin.loadConfig != null) { + let config = createConfig({ + plugin: plugin.name, + searchPath: toProjectPathUnsafe('index'), + }); + + await loadPluginConfig(plugin, config, this.options); + + for (let devDep of config.devDeps) { + let devDepRequest = await createDevDependency( + devDep, + this.previousDevDeps, + this.options, + ); + let key = `${devDep.specifier}:${fromProjectPath( + this.options.projectRoot, + devDep.resolveFrom, + )}`; + this.devDepRequests.set(key, devDepRequest); + } - // Only load config for a plugin once per build. - let existing = pluginConfigs.get(plugin.name); - if (existing != null) { - configs.set(plugin.name, existing); - return; + pluginConfigs.set(plugin.name, config); + configs.set(plugin.name, config); + } + } } - if (plugin.plugin.loadConfig != null) { + let loadGlobalInfo = plugin.plugin.loadGlobalInfo; + if (!globalInfos.has(plugin.name) && loadGlobalInfo != null) { let config = createConfig({ plugin: plugin.name, searchPath: toProjectPathUnsafe('index'), }); - - await loadPluginConfig(plugin, config, this.options); - - for (let devDep of config.devDeps) { - let devDepRequest = await createDevDependency( - devDep, - this.previousDevDeps, + config.result = await loadGlobalInfo({ + bundle: NamedBundle.get(bundle, bundleGraph, this.options), + bundleGraph: new BundleGraph( + bundleGraph, + NamedBundle.get.bind(NamedBundle), this.options, - ); - let key = `${devDep.specifier}:${fromProjectPath( - this.options.projectRoot, - devDep.resolveFrom, - )}`; - this.devDepRequests.set(key, devDepRequest); - } - - pluginConfigs.set(plugin.name, config); - configs.set(plugin.name, config); + ), + options: new PluginOptions(this.options), + logger: new PluginLogger({origin: plugin.name}), + }); + // TODO expose config and let plugin set key? + config.cacheKey = hashString(JSON.stringify(config.result) ?? ''); + globalInfos.set(plugin.name, config); } } @@ -235,6 +281,7 @@ export default class PackagerRunner { bundleGraph: InternalBundleGraph, bundle: InternalBundle, configs: Map, + globalInfos: Map, ): Async { if (this.options.shouldDisableCache) { return; @@ -244,6 +291,7 @@ export default class PackagerRunner { bundle, bundleGraph, configs, + globalInfos, this.previousInvalidations, ); let infoKey = PackagerRunner.getInfoKey(cacheKey); @@ -254,17 +302,23 @@ export default class PackagerRunner { bundle: InternalBundle, bundleGraph: InternalBundleGraph, configs: Map, + globalInfos: Map, ): Promise { let {type, contents, map} = await this.getBundleResult( bundle, bundleGraph, configs, + globalInfos, ); // Recompute cache keys as they may have changed due to dev dependencies. - let cacheKey = await this.getCacheKey(bundle, bundleGraph, configs, [ - ...this.invalidations.values(), - ]); + let cacheKey = await this.getCacheKey( + bundle, + bundleGraph, + configs, + globalInfos, + [...this.invalidations.values()], + ); let cacheKeys = { content: PackagerRunner.getContentKey(cacheKey), map: PackagerRunner.getMapKey(cacheKey), @@ -278,12 +332,18 @@ export default class PackagerRunner { bundle: InternalBundle, bundleGraph: InternalBundleGraph, configs: Map, + globalInfos: Map, ): Promise<{| type: string, contents: Blob, map: ?string, |}> { - let packaged = await this.package(bundle, bundleGraph, configs); + let packaged = await this.package( + bundle, + bundleGraph, + configs, + globalInfos, + ); let type = packaged.type ?? bundle.type; let res = await this.optimize( bundle, @@ -292,6 +352,7 @@ export default class PackagerRunner { packaged.contents, packaged.map, configs, + globalInfos, ); let map = @@ -319,6 +380,7 @@ export default class PackagerRunner { internalBundle: InternalBundle, bundleGraph: InternalBundleGraph, configs: Map, + globalInfos: Map, ): Promise { let bundle = NamedBundle.get(internalBundle, bundleGraph, this.options); this.report({ @@ -332,6 +394,7 @@ export default class PackagerRunner { try { return await plugin.package({ config: configs.get(name)?.result, + globalInfo: globalInfos.get(name)?.result, bundle, bundleGraph: new BundleGraph( bundleGraph, @@ -358,6 +421,7 @@ export default class PackagerRunner { // $FlowFixMe bundleGraphToInternalBundleGraph(bundleGraph), configs, + globalInfos, ); return {contents: res.contents}; @@ -395,6 +459,7 @@ export default class PackagerRunner { contents: Blob, map?: ?SourceMap, configs: Map, + globalInfos: Map, ): Promise { let bundle = NamedBundle.get( internalBundle, @@ -430,6 +495,7 @@ export default class PackagerRunner { try { let next = await optimizer.plugin.optimize({ config: configs.get(optimizer.name)?.result, + globalInfo: globalInfos.get(optimizer.name)?.result, bundle, bundleGraph, contents: optimized.contents, @@ -535,6 +601,7 @@ export default class PackagerRunner { bundle: InternalBundle, bundleGraph: InternalBundleGraph, configs: Map, + globalInfos: Map, invalidations: Array, ): Promise { let configResults = {}; @@ -547,6 +614,16 @@ export default class PackagerRunner { ); } } + let globalInfoResults = {}; + for (let [pluginName, config] of globalInfos) { + if (config) { + globalInfoResults[pluginName] = await getConfigHash( + config, + pluginName, + this.options, + ); + } + } let devDepHashes = await this.getDevDepHashes(bundle); for (let inlineBundle of bundleGraph.getInlineBundles(bundle)) { @@ -565,6 +642,7 @@ export default class PackagerRunner { bundle.target.publicUrl + bundleGraph.getHash(bundle) + JSON.stringify(configResults) + + JSON.stringify(globalInfoResults) + this.options.mode, ); } diff --git a/packages/core/core/src/ParcelConfig.js b/packages/core/core/src/ParcelConfig.js index cec4ebd4f0a..c69a5f0a9a0 100644 --- a/packages/core/core/src/ParcelConfig.js +++ b/packages/core/core/src/ParcelConfig.js @@ -253,7 +253,7 @@ export default class ParcelConfig { async getPackager( filePath: FilePath, - ): Promise>> { + ): Promise>> { let packager = this.matchGlobMap( toProjectPathUnsafe(filePath), this.packagers, @@ -265,7 +265,7 @@ export default class ParcelConfig { '/packagers', ); } - return this.loadPlugin>(packager); + return this.loadPlugin>(packager); } _getOptimizerNodes( @@ -298,13 +298,13 @@ export default class ParcelConfig { getOptimizers( filePath: FilePath, pipeline: ?string, - ): Promise>>> { + ): Promise>>> { let optimizers = this._getOptimizerNodes(filePath, pipeline); if (optimizers.length === 0) { return Promise.resolve([]); } - return this.loadPlugins>(optimizers); + return this.loadPlugins>(optimizers); } async getCompressors( diff --git a/packages/core/core/src/requests/ConfigRequest.js b/packages/core/core/src/requests/ConfigRequest.js index 86861d2c7bd..6cbf0ef4101 100644 --- a/packages/core/core/src/requests/ConfigRequest.js +++ b/packages/core/core/src/requests/ConfigRequest.js @@ -4,6 +4,8 @@ import type { Config as IConfig, PluginOptions as IPluginOptions, PluginLogger as IPluginLogger, + NamedBundle as INamedBundle, + BundleGraph as IBundleGraph, } from '@parcel/types'; import type { Config, @@ -32,6 +34,21 @@ export type PluginWithLoadConfig = { ... }; +export type PluginWithLoadConfigGlobalInfo = { + loadConfig?: ({| + config: IConfig, + options: IPluginOptions, + logger: IPluginLogger, + |}) => Async, + loadGlobalInfo?: ({| + bundle: INamedBundle, + bundleGraph: IBundleGraph, + options: IPluginOptions, + logger: IPluginLogger, + |}) => Async, + ... +}; + export type ConfigRequest = { id: string, invalidateOnFileChange: Set, diff --git a/packages/core/core/src/requests/WriteBundlesRequest.js b/packages/core/core/src/requests/WriteBundlesRequest.js index bdfcbcf1360..e0ae4a09fd7 100644 --- a/packages/core/core/src/requests/WriteBundlesRequest.js +++ b/packages/core/core/src/requests/WriteBundlesRequest.js @@ -92,7 +92,10 @@ async function run({input, api, farm, options}: RunInput) { bundleGraphReference: ref, optionsRef, }); - let info = await api.runRequest(request); + + // TODO remove? + // force to ensure that loadConfig runs for all packagers/optimizers + let info = await api.runRequest(request, {force: true}); bundleInfoMap[bundle.id] = info; if (!info.hashReferences.length) { diff --git a/packages/core/plugin/src/PluginAPI.js b/packages/core/plugin/src/PluginAPI.js index 07d7ea1a0e5..d0bcd49f7f0 100644 --- a/packages/core/plugin/src/PluginAPI.js +++ b/packages/core/plugin/src/PluginAPI.js @@ -58,14 +58,14 @@ export class Validator { } export class Packager { - constructor(opts: PackagerOpts) { + constructor(opts: PackagerOpts) { // $FlowFixMe this[CONFIG] = opts; } } export class Optimizer { - constructor(opts: OptimizerOpts) { + constructor(opts: OptimizerOpts) { // $FlowFixMe this[CONFIG] = opts; } diff --git a/packages/core/types/index.js b/packages/core/types/index.js index 29aa68ee9fd..aa2236f5317 100644 --- a/packages/core/types/index.js +++ b/packages/core/types/index.js @@ -1591,18 +1591,25 @@ export type Runtime = {| /** * @section packager */ -export type Packager = {| +export type Packager = {| loadConfig?: ({| config: Config, options: PluginOptions, logger: PluginLogger, - |}) => Promise | ConfigType, + |}) => Async, + loadGlobalInfo?: ({| + bundle: NamedBundle, + bundleGraph: BundleGraph, + options: PluginOptions, + logger: PluginLogger, + |}) => Async, package({| bundle: NamedBundle, bundleGraph: BundleGraph, options: PluginOptions, logger: PluginLogger, config: ConfigType, + globalInfo: GlobalInfoType, getInlineBundleContents: ( Bundle, BundleGraph, @@ -1614,12 +1621,18 @@ export type Packager = {| /** * @section optimizer */ -export type Optimizer = {| +export type Optimizer = {| loadConfig?: ({| config: Config, options: PluginOptions, logger: PluginLogger, - |}) => Promise | ConfigType, + |}) => Async, + loadGlobalInfo?: ({| + bundle: NamedBundle, + bundleGraph: BundleGraph, + options: PluginOptions, + logger: PluginLogger, + |}) => Async, optimize({| bundle: NamedBundle, bundleGraph: BundleGraph, @@ -1628,6 +1641,7 @@ export type Optimizer = {| options: PluginOptions, logger: PluginLogger, config: ConfigType, + globalInfo: GlobalInfoType, getSourceMapReference: (map: ?SourceMap) => Async, |}): Async, |};