Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable integration with 3rd party assets management solutions #38445

Open
Tracked by #47254
mkArtakMSFT opened this issue Nov 16, 2021 · 12 comments
Open
Tracked by #47254

Enable integration with 3rd party assets management solutions #38445

mkArtakMSFT opened this issue Nov 16, 2021 · 12 comments
Labels
area-blazor Includes: Blazor, Razor Components enhancement This issue represents an ask for new feature or an enhancement to an existing one feature-blazor-client-assets Pillar: Complete Blazor Web Priority:1 Work that is critical for the release, but we could probably ship without
Milestone

Comments

@mkArtakMSFT
Copy link
Member

Consider productionizing Microsoft.AspNetCore.ClientAssets package

@mkArtakMSFT mkArtakMSFT added enhancement This issue represents an ask for new feature or an enhancement to an existing one area-blazor Includes: Blazor, Razor Components triaged Priority:2 Work that is important, but not critical for the release labels Nov 16, 2021
@mkArtakMSFT mkArtakMSFT added this to the .NET 7 Planning milestone Nov 16, 2021
@mkArtakMSFT mkArtakMSFT added Priority:1 Work that is critical for the release, but we could probably ship without and removed Priority:2 Work that is important, but not critical for the release labels Nov 16, 2021
@javiercn
Copy link
Member

Here is a draft of the design:

Productionizing the client assets package

There are several challenges integrating third-party tools that produce or transform web assets as part of the build process:

  • Developers need to write MSBuild targets to invoke their tools.
  • Developers do not generally run their custom targets at the right point during the build.
  • Developers generate the output into the wwwroot folder of the app, which then causes it to be considered as an input in the next build.
  • Developers don't account for inputs and outputs for the tools, which means the tools always run and add time to the build even if the outputs are up to date.

Goals

  • Simplify the integration of third-party tooling with static web asssets.

Out of scope

  • Solutions for complex scenarios like dealing with NPM workspaces and other mono-repo setups.
  • Orchestrating invocation in sequence for third-party dependency tools beyond installing tools and running them.
  • Watch support (if the tool has support for watch that is something we might consider in the future)

Technical design

We want to offer a declarative model where customers can indicate what tool to run, the inputs and the outputs and we take care of the rest.

We will likely need a couple of "phases" or extensibility points in the pipeline.

One initial phase to ensure that any third-party dependency toolchain (like npm or yarn) had a chance to run.

A second phase where we invoke whatever tool or script we are given.

Ideally, we want this to be a collaborative process where multiple tools can be added provided they don't depend on each other.

That allows packages to include a command for their toolchain as long as it doesn't depend on the outputs of any other tools.

One way we can make this work is by defining the invocations inside an item group as follows:

<ItemGroup>
  <ClientAssetTool Include="InstallNpmDependencies">
    <Stage>Dependencies</Stage>
    <Command>npm install</Command>
    <Directory>assets</Directory>
    <Inputs>assets\package.json;assets\package-lock.json</Inputs>
    <ExcludeInputs></ExcludeInputs>
    <Outputs>assets\node_modules\package-lock.json</Outputs>
    <ExcludeOutputs></ExcludeOutputs>
  </ClientAssetTool>

  <ClientAssetTool Include="RunNpmBuildScript">
    <Stage>Generation</Stage>
    <Command>npm run build:$(Configuration)</Command>
    <Directory>assets</Directory>
    <Inputs>assets\**</Inputs>
    <ExcludeInputs></ExcludeInputs>
    <Outputs>*.js</Outputs>
    <ExcludeOutputs>*.map.js</ExcludeOutputs>
  </ClientAssetTool>
</ItemGroup>

The metadata included in the item group defines all the aspects of how and when the tool needs to run:

  • Stage indicates when to run the tool:
    • Dependencies: This stage is intented to restore/install/retrieve required packages.
      • I want to avoid calling it Restore to avoid confusion as this will only run as part of build.
    • Generation: This stage is intended to run whatever commands need to run to generate the asset outputs.
      • If a set of tools need to be run sequentially the correct approach is to use a script, we won't handle ordering the different tools meant to run at a given stage.
  • Command indicates the command to run.
  • Directory indicates the directory from where to run the command from.
  • Inputs, ExcludeInputs: Allows defining patterns to compute the inputs for a tool.
  • Outputs, ExcludeOutputs: Allows defining patterns to compute the outputs for a tool.

With this metadata we will do as follows:

  • Add a Target to static web assets:
    • ResolveGeneratedStaticWebAssetsInputs that will run before resolving assets for the current project.
  • Create a new task RunClientAssetsTool that handles executing the client assets commands:
    • Resolves the inputs and outputs for a given entry.
    • Determines if it needs to run the tool.
    • Runs the tool.
    • Captures the outputs.
    • Returns the outputs.
  • The Dependencies stage doesn't add any output to the build (only captures them for incrementalism).
  • The Generation stage adds the outputs as ContentItems with the Link to the wwwroot folder.
  • During each stage, we log in the inputs, outputs, and the decissions we make along the way to make troubleshooting inside MSBuild easy.

Notes on testing

  • We don't have to use any third-party tool for testing this, we can use a cmd/powershell/bash script as long as we make it do whatever is needed to ensure it covers the scenarios we care about.

The biggest part in this aspect is the incrementalism. Some scenarios that I can enumerate:

  • Things that should trigger the tool to run:
    • An additional input was added.
    • An existing input was removed.
    • An existing input is newer than the last outputs.
    • Any information about the tool changed (command, input pattern, output pattern, exclusions, directory, etc.)
    • No outputs were found.
  • Things that should not trigger the tool to run again:
    • Inputs are the same and older than outputs.
    • Outputs didn't change after the tool ran (even if they are older).

Questions

  • Do we need a separate stage for preparing production level assets?
    • SPAs currently generate the production bundle only during publish.
    • Static Web Assets already supports the concept of Build and Publish assets, so we might want to levarage it here.
  • How do we pass the output folder information to a third-party tool?
    • We want to put the outputs in the intermediate output folder obj\clientassets\toolname to avoid them confliciting with the build.
    • We also want to support tools that put the output within the "source" tree and prevent those outputs from becoming inputs in the next build.
    • We can pass the output path as an environment variable, but some tools might only take command-line arguments.
      • We could have a token that we replace in the command before running it, like [TOOL_OUTPUTDIR] in addition to setting an environment variable when running the command.
  • Do we want to define the generated assets as static web assets directly or do we want to mark them as content.
    • I believe it is better to mark them as Content and use the Link functionality to define their relative paths in the project. Static web assets already takes that into account when discovering new assets and that automatically gets them to participate in other parts of the pipeline, like scoped CSS or JS modules. Alternatively, features like scoped CSS and JS modules would need to look at an additional item group.
  • Do we want to provide conventions for popular tools like NPM?
    • These can be on the SDK or in packages.

@MarkStega
Copy link

This is close to what I would like to see but I believe that there needs to be a way to have multiple sets of input & output specified. For example, I build both js & css; If a js source file changes I don't want to build css. As long as I can have multiple sections with generate and different commands/inputs/outputs I'd be covered

@javiercn
Copy link
Member

@MarkStega this design currently contemplates that.

You will create two separate item group items each one specifying a different command and a different set of inputs/outputs, one for your CSS and one for your JS

@MarkStega
Copy link

@TanayParikh I am very interested in using this feature so I will volunteer to test off of nightly builds when you get to that point.

@mkArtakMSFT
Copy link
Member Author

@TanayParikh please make sure this is also covered as part of the work: #42472

@MariovanZeist
Copy link
Contributor

@TanayParikh
I have been using this package for a while now. (Well a slightly modified version of this library to be fair)
The only problem I had with it was that when the path would include spaces, the output would not be generated
I created a PR to fix the issue aspnet/AspLabs#405, (And I have been using that modified version myself) but I must admit I am not a node nor an MSBuild specialist, so my fix could be wrong.

Do you have any insights into this?

@javiercn
Copy link
Member

javiercn commented Jul 27, 2022

@MariovanZeist we do not plan to move forward with the experimental package (as we are planning to integrate the functionality directly into the SDK). Being an experimental package, it was expected to have bugs. We plan to address things like this as part of moving the functionality to the SDK repo, as we have there the infrastructure to test it properly.

That said, the new functionality will give you the ability to define the command yourself, so you'll be responsible for things being quoted appropriately.

We might define some out of the box conventions either on the SDK or inside a new package to further streamline the scenario when following the conventions (so that basically you put assets in a specific folder, and everything magically works after that). In that case we would be taking care of the quoting.

@MariovanZeist
Copy link
Contributor

@javiercn Thanks for clearing it up, I was indeed under the mistaken assumption that this particular package would be used.
I prefer it being part of the SDK anyway, so thanks for the info.

@javiercn
Copy link
Member

javiercn commented Jul 27, 2022

@MariovanZeist yeah, the idea is that we make this process declarative, you get to say what commands to run, what inputs and outputs and we take care of making sure that they end up in the right place inside the wwwroot folder and that things are done incrementally (provided you correctly specify inputs and outputs).

It is much easier for us to test those things in the SDK repo because we have infrastructure that can create a project and run through different scenarios to make sure that stuff works, and it does not regress over time when changes are made.

@ghost
Copy link

ghost commented Oct 6, 2023

Thanks for contacting us.

We're moving this issue to the .NET 9 Planning milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s).
If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues.
To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

@ghost
Copy link

ghost commented Dec 19, 2023

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-blazor Includes: Blazor, Razor Components enhancement This issue represents an ask for new feature or an enhancement to an existing one feature-blazor-client-assets Pillar: Complete Blazor Web Priority:1 Work that is critical for the release, but we could probably ship without
Projects
None yet
Development

No branches or pull requests

6 participants