Skip to content

Improve support for Frontend monorepos #772

@KennethHoff

Description

@KennethHoff

Related to an existing integration?

Yes

Existing integration

Hosting.NodeJS.Extensions

Overview

If you use a monorepo solution like Nx or Turborepo packages will get installed at the top-level of a directory. If you then try to run multiple applications with AddYarnPackageInstallation for example then the same packages will be attempted to be installed multiple times, resulting in a race.

Every app needs the packages, but only one installer.

var app1 = builder.AddYarnApp("app-1", "./Frontend", args: ["app1"])
    .WithYarnPackageInstallation();
    
var app2 = builder.AddYarnApp("app-2", "./Frontend", args: ["app2"])
    .WithYarnPackageInstallation();
    
var app3 = builder.AddYarnApp("app-3", "./Frontend", args: ["app3"])
    .WithYarnPackageInstallation();

I have a couple of suggestions:

  1. Merge installers whose WorkingDirectory is the same into a single "monorepo installer". I don't know how this would look inside of Aspire now that they are dedicated resources ( Each app has the same reference? Is that even possible in Aspire?)
  2. Create a reference relationship inside the PackageInstallers themselves
  3. Create a AddNxMonoRepo and AddTurborepoMonoRepo wrapper resource that handles these sorts of things for us, kind of like how AddPostgres etc works.

Usage example

Suggestion 1

No API changes, the runtime just "figures it out" based on the WorkingDirectory property on the InstallerResource itself.

Suggestion 2

For suggestion 2 there is a new API; Something along the lines of this.

var app1 = builder.AddYarnApp("app-1", "./Frontend", args: ["app1"])
    .WithYarnPackageInstallation();

var app2 = builder.AddYarnApp("app-2", "./Frontend", args: ["app2"])
    .WithYarnPackageInstallation(app1);
    
var app3 = builder.AddYarnApp("app-3", "./Frontend", args: ["app3"])
    .WithYarnPackageInstallation(app1);

or

var app1 = builder.AddYarnApp("app-1", "./Frontend", args: ["app1"])
    .WithYarnPackageInstallation();

var app2 = builder.AddYarnApp("app-2", "./Frontend", args: ["app2"])
    .WithYarnPackageInstallation(x => x.WithSameInstaller(app1));
    
var app3 = builder.AddYarnApp("app-3", "./Frontend", args: ["app3"])
    .WithYarnPackageInstallation(x => x.WithSameInstaller(app1));

Suggestion 3

var nx = builder.AddNx("nx", "./Frontend")
    .WithYarnPackageInstallation();

var app1 = nx.AddApp("app-1", target: "app1");
var app1 = nx.AddApp("app-1", target: "app1");
var app1 = nx.AddApp("app-1", target: "app1");
var turbo = builder.AddTurborepo("nx", "./Frontend")
    .WithYarnPackageInstallation();

var app1 = turbo.AddApp("app-1", filter: "app1");
var app1 = turbo.AddApp("app-1", filter: "app1");
var app1 = turbo.AddApp("app-1", filter: "app1");

Breaking change?

I'm not sure

Alternatives

Instead of calling With{Yarn,Npm,Pnpm}PackageInstallation on every resource you can instead of WaitFor on the subsequent ones. This works but is not as obvious or clean.

var app1 = builder.AddYarnApp("app-1", "./Frontend", args: ["app1"])
    .WithYarnPackageInstallation();
    
var app2 = builder.AddYarnApp("app-2", "./Frontend", args: ["app2"])
    .WaitFor(app1)
    
var app3 = builder.AddYarnApp("app-3", "./Frontend", args: ["app3"])
    .WaitFor(app1);

Additional context

No response

Help us help you

No, just wanted to propose this

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions