dotnet / dotnet/aspnetcore

[ClientAssets] Support automagically consuming npm dependencies installed from package.json

Open
#46,732 2 comments 1 reaction 0 assignees View on GitHub
area-blazor area-ui-rendering feature-static-web-assets
Dominant language
C#
Stars
38.4k
Forks
10.9k
Avg merge
2d 10h
Merged PRs (30d)
281

Description

The idea is that you can have a package.json file that only contains dependencies, and that can be consumed directly inside ASP.NET Core via static web assets.

Currently we support integrating with NPM, but we assume that you are going to have a build step (which typically bundles/copies files to an output folder) and we are going to expose these over the wwwroot folder.

However, if you just want to consume the files in the package directly (as you would do within the bundle) it becomes hard to do, as typically you need an extra step to copy the files and define them as assets.

Instead of that, we can build a "node resolver" (similar to the one every bundler has) that can automatically expose the contents of a package as if they were part of the wwwroot. The way this works is as follows:
* We detect package.json files in your app.
* We parse the json file and read the "dependencies" node.
* For each dependency:
* We start by looking for a "node_modules" folder side by side with the package.json.
* If we find it:
* We search for the package name inside.
* If we find a folder with the package name:
* We read the package.json for the package.
* We search for the "main" property in the package.
* If present, we map the path "package-name" to the full path of the file pointed by main.
* If not present, we map the path "package-name" to the full path of the file `index.js` if it exists.
* Additionally, if present, we map the contents of the "dist" folder of the package to "package-name/<>"
* We do not want to map the entire contents of the package because we do not have a way to trim them.
* We might alternatively, map the entire package, but use a pattern to filter that only covers "dist" by default.
* The strings we use to consume specific files from a package should match exactly those used when using an "import" in js.
* If we do not find a folder with the package name, we break
* If we do not find a node_modules folder, we try to find one in a directory above.

In addition to that, many packages ship source maps and minified versions of the files.

* We can have conventions that make sure that we pick the right file depending on whether we are publishing the app or developing.
* For example, if you add "jquery", the "jquery" package contains "jquery.js" and "jquery.min.js".
* Static web assets can automatically serve "jquery.js" (unminified) during development and copy "jquery.min.js" into wwwroot/jquery.js at publish time.
* In a similar way, it can automatically serve the source maps during development and avoid publishing those to the final output.
* This ensures that during development you get the best experience and during publish you get the minified asset.

A user can consume the file from a razor file by using `` or `` in a very similar way as if they were using "unpkg" (https://unpkg.com/jquery@3.6.3/dist/jquery.js)

This would potentially all work without configuration (you drop a package.json into your project and we do the rest), or we could additionally provide some config options that can be specified inside `package.json` or the csproj file (although it feels more natural to put it inside package.json). Some of this options could be:
* Common prefix to map the packages to, for example "vendors", "lib", etc.
* Configuration for what paths to include on a per package basis (everything else gets filtered out).

To give a full example. Let's say we have an MVC app and we want to consume the common JS libraries that MVC/Razor pages use. We drop a `package.json` file:
```json
{
"private": true,
"dependencies": {
"bootstrap": "^5.2.3",
"jquery": "^3.6.3",
"jquery-validation": "^1.19.5",
"jquery-validation-unobtrusive": "^4.0.0"
},
}
```

And we consume it from "_Layout.cshtml" as follows:
```html

```

Contributor guide

Open the contributing guide

Research direction

Start by reviewing the existing ASP.NET Core static web assets and NPM integration, then compare it with the package.json and _Layout.cshtml examples in the issue. Done should cover dependency discovery, node_modules resolution, main/index.js and dist mappings, and the proposed development-versus-publish handling for minified files and source maps.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp, javascript
Domain
build-system, web-dev
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.