Skip to content

Commit

Permalink
using RewrittenPackageCache in stage2
Browse files Browse the repository at this point in the history
  • Loading branch information
ef4 committed May 21, 2023
1 parent 8bccbd7 commit bff8ccb
Show file tree
Hide file tree
Showing 6 changed files with 44 additions and 39 deletions.
41 changes: 34 additions & 7 deletions packages/compat/src/compat-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { Node as BroccoliNode } from 'broccoli-node-api';
import mergeTrees from 'broccoli-merge-trees';
import {
Stage,
PackageCache,
OutputPaths,
BuildStage,
Asset,
Expand All @@ -13,6 +12,7 @@ import {
Package,
AddonPackage,
Engine,
RewrittenPackageCache,
} from '@embroider/core';
import V1InstanceCache from './v1-instance-cache';
import V1App from './v1-app';
Expand Down Expand Up @@ -66,7 +66,8 @@ function setup(legacyEmberAppInstance: object, options: Required<Options>) {
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,
Expand Down Expand Up @@ -180,12 +181,15 @@ class CompatAppAdapter implements AppAdapter<TreeNames, CompatResolverOptions> {

@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[];
Expand All @@ -194,9 +198,27 @@ class CompatAppAdapter implements AppAdapter<TreeNames, CompatResolverOptions> {
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];
Expand All @@ -205,8 +227,13 @@ class CompatAppAdapter implements AppAdapter<TreeNames, CompatResolverOptions> {

@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
Expand Down
16 changes: 4 additions & 12 deletions packages/core/src/build-stage.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -10,27 +9,21 @@ import { Memoize } from 'typescript-memoize';
export default class BuildStage<NamedTrees> implements Stage {
private active: BuilderInstance<NamedTrees> | 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<BuilderInstance<NamedTrees>>
private instantiate: (root: string, appSrcDir: string) => Promise<BuilderInstance<NamedTrees>>
) {}

@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));
Expand All @@ -42,11 +35,10 @@ export default class BuildStage<NamedTrees> 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!,
};
}

Expand Down
9 changes: 5 additions & 4 deletions packages/core/src/rewritten-package-cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ type PublicAPI<T> = { [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<PublicAPI<PackageCache>, 'basedir' | 'seed' | 'shareAs'>;
type PackageCacheTheGoodParts = Omit<PublicAPI<PackageCache>, 'basedir' | 'seed'>;

export class RewrittenPackageCache implements PackageCacheTheGoodParts {
constructor(private plainCache: PackageCache) {}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
}
5 changes: 0 additions & 5 deletions packages/core/src/stage.ts
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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;
}>;
}
7 changes: 1 addition & 6 deletions packages/core/src/to-broccoli-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,7 @@ export default function toBroccoliPlugin<Options>(

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,
Expand Down
5 changes: 0 additions & 5 deletions packages/shared-internals/src/package-cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down

0 comments on commit bff8ccb

Please sign in to comment.