Skip to content

<script type="module" src="..."> is fetched twice in published MVC apps when importmap is present #66553

@AslanAmca

Description

@AslanAmca

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

In an ASP.NET Core MVC project using MapStaticAssets() with WithStaticAssets(), the JavaScript file referenced via <script type="module" src="..."> is fetched twice when:

  • The application has been published, and
  • The page is loaded for the first time, or the browser cache is disabled, or a hard reload (Ctrl+F5) is performed

In development, the issue does not occur regardless of cache state.

Modules imported transitively from the entry script (via import statements inside JS) are fetched only once. The duplicate is specifically on the script directly referenced by the src attribute on a <script type="module"> tag.

I am not sure whether this is a bug or intentional behavior. Either way, clarification or documentation would be appreciated, since the workaround (inline import statement) is non-obvious and the bandwidth cost is real on cold loads.

Expected Behavior

<script type="module" src="..."> should result in a single network request, matching the behavior of:

  • The same setup in development
  • Modules imported via import statements
  • Non-module scripts (<script>, <script defer>)

Steps To Reproduce

  1. dotnet new mvc -n ImportMapRepro
  2. Configure Program.cs:
app.MapStaticAssets();
// NOTE: WithStaticAssets() does not work with MapControllerRoute()
// (see #59003), so MapControllers + MapDefaultControllerRoute is used instead.
app.MapControllers().WithStaticAssets();
app.MapDefaultControllerRoute();
  1. Add wwwroot/js/dependency.js:
export const value = 42;
  1. Add wwwroot/js/entry.js:
import { value } from './dependency.js';
console.log(value);
  1. In _Layout.cshtml's <head>:
<base href="~/" />
<script type="importmap"></script>
  1. In _Layout.cshtml's <body>:
<script type="module" src="~/js/entry.js"></script>
  1. Publish the app and run it from the publish output.
  2. Open the app, DevTools → Network → enable "Disable cache" → reload.

Result:

  • entry.{hash}.js appears twice (HTTP 200, same URL, same ETag)
  • dependency.{hash}.js appears once

Exceptions (if any)

None

.NET Version

.NET 10 (also reproducible on .NET 9)

Anything else?

Observations narrowing down the trigger

The duplicate occurs only when all of the following are true:

  • The application has been published (not development)
  • A <script type="importmap"></script> tag is rendered in the layout
  • The script is loaded via <script type="module" src="...">

Changing any one eliminates the duplicate:

  • Removing the importmap tag → single fetch (but disables JS module fingerprinting)
  • Loading the entry via inline import instead of src -> single fetch:
<script type="module">
    import "/js/entry.js";
</script>
  • Using a non-module <script src="..."> → single fetch

Difference between dev and publish importmaps

In development the rendered importmap contains only the imports field. After publish it also contains an integrity field with hashes for each asset. This is the most visible difference between the two modes; whether it relates to the issue is unclear.

Network tab screenshot
Image

The entry module loaded via <script type="module" src> is fetched twice (red box). The dependency imported from inside that entry is fetched once (red underline).

For a page loading 10–20 module scripts, the cold load and Ctrl+F5 cost is doubled. There is no clear reason why a module script loaded via src should be fetched differently from one loaded via import. If this is intentional, it would help to document it — the workaround is not discoverable.

Note: This issue was drafted with assistance from an AI assistant based on observations from my own testing. The reproduction steps and behavior described have been verified by me.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-middlewareIncludes: URL rewrite, redirect, response cache/compression, session, and other general middlewaresbugThis issue describes a behavior which is not expected - a bug.

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions