From bff8ccb454243991b8687a578eec59b71f28b99b Mon Sep 17 00:00:00 2001 From: Edward Faulkner Date: Sun, 21 May 2023 14:06:30 -0400 Subject: [PATCH] using RewrittenPackageCache in stage2 --- packages/compat/src/compat-app.ts | 41 +++++++++++++++---- packages/core/src/build-stage.ts | 16 ++------ packages/core/src/rewritten-package-cache.ts | 9 ++-- packages/core/src/stage.ts | 5 --- packages/core/src/to-broccoli-plugin.ts | 7 +--- .../shared-internals/src/package-cache.ts | 5 --- 6 files changed, 44 insertions(+), 39 deletions(-) diff --git a/packages/compat/src/compat-app.ts b/packages/compat/src/compat-app.ts index bffc12e00..7d851afc6 100644 --- a/packages/compat/src/compat-app.ts +++ b/packages/compat/src/compat-app.ts @@ -2,7 +2,6 @@ import { Node as BroccoliNode } from 'broccoli-node-api'; import mergeTrees from 'broccoli-merge-trees'; import { Stage, - PackageCache, OutputPaths, BuildStage, Asset, @@ -13,6 +12,7 @@ import { Package, AddonPackage, Engine, + RewrittenPackageCache, } from '@embroider/core'; import V1InstanceCache from './v1-instance-cache'; import V1App from './v1-app'; @@ -66,7 +66,8 @@ function setup(legacyEmberAppInstance: object, options: Required) { appBootTree, }; - let instantiate = async (root: string, appSrcDir: string, packageCache: PackageCache) => { + let instantiate = async (root: string, appSrcDir: string) => { + let packageCache = RewrittenPackageCache.shared('embroider', appSrcDir); let appPackage = packageCache.get(appSrcDir); let adapter = new CompatAppAdapter( root, @@ -180,12 +181,15 @@ class CompatAppAdapter implements AppAdapter { @Memoize() activeAddonChildren(pkg: Package = this.appPackage): AddonPackage[] { - let result = (pkg.dependencies.filter(this.isActiveAddon) as AddonPackage[]).filter( + let deps = this.appSpecialDependencies(pkg); + let result = (deps.filter(this.isActiveAddon) as AddonPackage[]).filter( // When looking for child addons, we want to ignore 'peerDependencies' of // a given package, to align with how ember-cli resolves addons. So here // we only include dependencies that definitely appear in one of the other // sections. - addon => pkg.packageJSON.dependencies?.[addon.name] || pkg.packageJSON.devDependencies?.[addon.name] + addon => + pkg.packageJSON.dependencies?.[addon.name] || + (pkg === this.appPackage && pkg.packageJSON.devDependencies?.[addon.name]) ); if (pkg === this.appPackage) { let extras = [this.synthVendor, this.synthStyles].filter(this.isActiveAddon) as AddonPackage[]; @@ -194,9 +198,27 @@ class CompatAppAdapter implements AppAdapter { return result.sort(this.orderAddons); } + private appSpecialDependencies(pkg: Package): Package[] { + if (pkg !== this.appPackage) { + return pkg.dependencies; + } + // the app package is special because at this stage we're still looking at + // the original app package, but its deps have been rewritten. + return pkg.dependencies.map(dep => RewrittenPackageCache.shared('embroider', this.appPackage.root).maybeMoved(dep)); + } + + private appSpecialDescendants(pkg: Package, filter?: (p: Package) => boolean) { + if (pkg !== this.appPackage) { + return pkg.findDescendants(filter); + } + // the app package is special because at this stage we're still looking at + // the original app package, but its deps have been rewritten. + return Package.prototype.findDescendants.call({ dependencies: this.appSpecialDependencies(pkg) }, filter); + } + @Memoize() get allActiveAddons(): AddonPackage[] { - let result = this.appPackage.findDescendants(this.isActiveAddon) as AddonPackage[]; + let result = this.appSpecialDescendants(this.appPackage, this.isActiveAddon) as AddonPackage[]; let extras = [this.synthVendor, this.synthStyles].filter(this.isActiveAddon) as AddonPackage[]; let extraDescendants = flatMap(extras, dep => dep.findDescendants(this.isActiveAddon)) as AddonPackage[]; result = [...result, ...extras, ...extraDescendants]; @@ -205,8 +227,13 @@ class CompatAppAdapter implements AppAdapter { @bind private isActiveAddon(pkg: Package): boolean { - // todo: filter by addon-provided hook - return pkg.isEmberPackage(); + // stage1 already took care of converting everything that's actually active + // into v2 addons. If it's not a v2 addon, we don't want it. + // + // We can encounter v1 addons here when there is inactive stuff floating + // around in the node_modules that accidentally satisfy something like an + // optional peer dep. + return pkg.isV2Addon(); } @bind diff --git a/packages/core/src/build-stage.ts b/packages/core/src/build-stage.ts index 35ac64f05..3031d4813 100644 --- a/packages/core/src/build-stage.ts +++ b/packages/core/src/build-stage.ts @@ -1,5 +1,4 @@ import WaitForTrees, { OutputPaths } from './wait-for-trees'; -import { PackageCache } from '@embroider/shared-internals'; import Stage from './stage'; import { Node } from 'broccoli-node-api'; import { Memoize } from 'typescript-memoize'; @@ -10,27 +9,21 @@ import { Memoize } from 'typescript-memoize'; export default class BuildStage implements Stage { private active: BuilderInstance | undefined; private outputPath: string | undefined; - private packageCache: PackageCache | undefined; constructor( private prevStage: Stage, private inTrees: NamedTrees, private annotation: string, - private instantiate: ( - root: string, - appSrcDir: string, - packageCache: PackageCache - ) => Promise> + private instantiate: (root: string, appSrcDir: string) => Promise> ) {} @Memoize() get tree(): Node { return new WaitForTrees(this.augment(this.inTrees), this.annotation, async treePaths => { if (!this.active) { - let { outputPath, packageCache } = await this.prevStage.ready(); + let { outputPath } = await this.prevStage.ready(); this.outputPath = outputPath; - this.packageCache = packageCache; - this.active = await this.instantiate(outputPath, this.prevStage.inputPath, packageCache); + this.active = await this.instantiate(outputPath, this.prevStage.inputPath); } delete (treePaths as any).__prevStageTree; await this.active.build(this.deAugment(treePaths)); @@ -42,11 +35,10 @@ export default class BuildStage implements Stage { return this.prevStage.inputPath; } - async ready(): Promise<{ outputPath: string; packageCache: PackageCache }> { + async ready(): Promise<{ outputPath: string }> { await this.deferReady.promise; return { outputPath: this.outputPath!, - packageCache: this.packageCache!, }; } diff --git a/packages/core/src/rewritten-package-cache.ts b/packages/core/src/rewritten-package-cache.ts index 55c0e0356..848107785 100644 --- a/packages/core/src/rewritten-package-cache.ts +++ b/packages/core/src/rewritten-package-cache.ts @@ -29,7 +29,7 @@ type PublicAPI = { [K in keyof T]: T[K] }; // TODO: as our refactor lands we should be able to remove these things from // PackageCache itself. -type PackageCacheTheGoodParts = Omit, 'basedir' | 'seed' | 'shareAs'>; +type PackageCacheTheGoodParts = Omit, 'basedir' | 'seed'>; export class RewrittenPackageCache implements PackageCacheTheGoodParts { constructor(private plainCache: PackageCache) {} @@ -65,8 +65,8 @@ export class RewrittenPackageCache implements PackageCacheTheGoodParts { return this.maybeMoved(oldDest); } - // ensure we have the moved version of the package - private maybeMoved(pkg: Package): Package { + // ensure we have the moved version of the package if it has been moved + maybeMoved(pkg: Package): Package { let newRoot = this.index.oldToNew.get(pkg.root); if (newRoot) { return this.get(newRoot); @@ -169,6 +169,7 @@ function castToPackage(m: MovedPackage): Package { } class MovedPackage implements PackageTheGoodParts { + debugMoved = true as const; // plainPkg is not the Package in the original un-moved location, it's the // plain representation of the moved location. That is, when you grab // plainPkg.root it will show the new location, and plainPkg.packageJSON shows @@ -281,7 +282,7 @@ class MovedPackage implements PackageTheGoodParts { hasDependency(name: string): boolean { // this is *not* extended because it's understood that the rewritten package // should explictly list the things that need extraResolutions in its own - // package.json.ß + // package.json. return this.plainPkg.hasDependency(name); } } diff --git a/packages/core/src/stage.ts b/packages/core/src/stage.ts index 8a9624ce6..b5c6e8616 100644 --- a/packages/core/src/stage.ts +++ b/packages/core/src/stage.ts @@ -1,5 +1,4 @@ import type { Node } from 'broccoli-node-api'; -import { PackageCache } from '@embroider/shared-internals'; // A build Stage is _kinda_ like a Broccoli transform, and it interoperates with // Broccoli, but it takes a different approach to how stages combine. @@ -27,9 +26,5 @@ export default interface Stage { // This is the actual directory in which the output will be. It's guaranteed // to not change once you get it. readonly outputPath: string; - - // Stages must propagate their PackageCache forward to the next stage so we - // don't repeat a lot of resolving work. - readonly packageCache: PackageCache; }>; } diff --git a/packages/core/src/to-broccoli-plugin.ts b/packages/core/src/to-broccoli-plugin.ts index a08af37ed..64a4cbd59 100644 --- a/packages/core/src/to-broccoli-plugin.ts +++ b/packages/core/src/to-broccoli-plugin.ts @@ -22,12 +22,7 @@ export default function toBroccoliPlugin( async build() { if (!this.packager) { - let { outputPath, packageCache } = await this.stage.ready(); - // We always register a shared stage3 packageCache so it can be used by - // things like babel plugins and template compilers. - if (packageCache) { - packageCache.shareAs('embroider-stage3'); - } + let { outputPath } = await this.stage.ready(); this.packager = new packagerClass( outputPath, this.outputPath, diff --git a/packages/shared-internals/src/package-cache.ts b/packages/shared-internals/src/package-cache.ts index 1c2fb8e07..549ea3af0 100644 --- a/packages/shared-internals/src/package-cache.ts +++ b/packages/shared-internals/src/package-cache.ts @@ -72,11 +72,6 @@ export default class PackageCache { } } - // register to be shared as the per-process package cache with the given name - shareAs(identifier: string) { - shared.set(identifier, this); - } - static shared(identifier: string, appRoot: string) { let pk = getOrCreate(shared, identifier + appRoot, () => new PackageCache(appRoot)); if (pk.appRoot !== appRoot) {