Skip to content

feat: add webpackPrefetch/webpackPreload/webpackFetchPriority support for URL-based assets#19695

Open
3ru wants to merge 23 commits into
webpack:mainfrom
3ru:feature/worker-prefetch-preload-support
Open

feat: add webpackPrefetch/webpackPreload/webpackFetchPriority support for URL-based assets#19695
3ru wants to merge 23 commits into
webpack:mainfrom
3ru:feature/worker-prefetch-preload-support

Conversation

@3ru
Copy link
Copy Markdown
Member

@3ru 3ru commented Jul 13, 2025

PR Description

This PR refreshes prefetch/preload support across Worker chunks and new URL() assets, aligns the behavior with dynamic import(), and introduces new runtime helpers.

fixes

What kind of change does this PR introduce?

Adds magic comment support to configure resource hints:

  • Worker chunks (numeric ordering + fetch priority)
  • new URL() assets (boolean flags + fetch priority + explicit preload attribute overrides)
  • Introduces runtime helpers to inject <link> elements at runtime:
  • prefetchAsset and preloadAsset

Supported magic comments

  • Worker chunks (new Worker / SharedWorker / service worker register):
    • /* webpackPrefetch: true | number */
    • /* webpackPreload: true | number */
    • /* webpackFetchPriority: "high" | "low" | "auto" */
  • new URL() assets:
    • /* webpackPrefetch: true */
    • /* webpackPreload: true */
    • /* webpackFetchPriority: "high" | "low" | "auto" */
    • /* webpackPreloadAs: "<request-destination>" */
    • /* webpackPreloadType: "<mime/type>" */
    • /* webpackPreloadMedia: "<media-query>" */

Notes:

  • Worker accepts number ordering (same as import()), URL assets do not.
  • Explicit webpackPreloadAs/webpackPreloadType/webpackPreloadMedia override the auto-detected defaults for URL assets.
  • The as attribute accepts Fetch Standard request destinations. Allowed values include: audio, audioworklet, document, embed, fetch, font, image, manifest, object, paintworklet, report, script, sharedworker, serviceworker, style, track, video, worker, xslt.
  • Warnings are emitted for invalid values.

Example Usage

// Prefetch an asset for future use
const imageUrl = new URL(
  /* webpackPrefetch: true */
  './assets/hero.jpg',
  import.meta.url
);

// Preload with high priority
const criticalFont = new URL(
  /* webpackPreload: true */
  /* webpackFetchPriority: "high" */
  './fonts/main.woff2',
  import.meta.url
);

// Works with Worker syntax
const worker = new Worker(
  new URL(
    /* webpackPrefetch: true */
    './heavy-computation.worker.js',
    import.meta.url
  )
);

// Override as/type/media explicitly (defaults are auto-detected)
const fontUrl = new URL(
  /* webpackPreload: true */
  /* webpackPreloadAs: "font" */
  /* webpackPreloadType: "font/woff2" */
  /* webpackPreloadMedia: "(max-width: 600px)" */
  './fonts/heading.woff2',
  import.meta.url
);

// Accepts Fetch Request Destinations (e.g., sharedworker)
const helperUrl = new URL(
  /* webpackPreload: true */
  /* webpackPreloadAs: "sharedworker" */
  './scripts/worker-helper.js',
  import.meta.url
);

Did you add tests for your changes?

Yes

Does this PR introduce a breaking change?

No

What needs to be documented once your changes are merged?

  • Worker: true | number for webpackPrefetch/webpackPreload, fetchpriority supported.
  • URL:
    • webpackPrefetch: true / webpackPreload: true
    • webpackFetchPriority: "high" | "low" | "auto"
    • Auto-detected as (based on file type), with explicit overrides:
      • webpackPreloadAs: "<request-destination>" (Fetch Request Destinations; includes audio, audioworklet, document, embed, fetch, font, image, manifest, object, paintworklet, report, script, sharedworker, serviceworker, style, track, video, worker, xslt)
      • webpackPreloadType: "<mime/type>"
      • webpackPreloadMedia: "<media-query>"
    • Invalid values emit warnings.

rel

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Jul 13, 2025

CodSpeed Performance Report

Merging #19695 will improve performances by 20.58%

Comparing 3ru:feature/worker-prefetch-preload-support (aaae36e) with main (42ed7bc)

Summary

⚡ 1 improvement
✅ 68 untouched

Benchmarks breakdown

Benchmark BASE HEAD Change
benchmark "json-modules", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 40.4 ms 33.5 ms +20.58%

@3ru 3ru force-pushed the feature/worker-prefetch-preload-support branch from 329587d to 13027da Compare July 13, 2025 08:02
Comment thread test/configCases/worker/worker-prefetch-preload/index.js Outdated
Comment thread test/configCases/worker/worker-prefetch-preload/index.js Outdated
@3ru 3ru force-pushed the feature/worker-prefetch-preload-support branch from f0ffcb7 to 2bb3de1 Compare July 21, 2025 06:39
@3ru 3ru changed the title feat: add webpackPrefetch / webpackPreload / webpackFetchPriority support for Worker syntax feat: add webpackPrefetch/webpackPreload/webpackFetchPriority support for URL-based assets Jul 21, 2025
@3ru 3ru force-pushed the feature/worker-prefetch-preload-support branch from 2bb3de1 to 3cc5c91 Compare July 21, 2025 07:07
@3ru
Copy link
Copy Markdown
Member Author

3ru commented Jul 21, 2025

Standards and constraints

  • URL prefetch/preload only accept boolean true.
  • Fetch priority accepts only "high" | "low" | "auto".
  • The as attribute is auto-detected from the filename/extension (image, font, style, script, track, or fallback fetch).
  • MIME types (e.g., link.type="text/css") are intentionally not set in this PR.

Why numeric order is only for Worker (not URL)

  • Worker and dynamic import() create async chunks and chunk groups. Webpack can attach prefetchOrder/preloadOrder to these groups and deterministically schedule resource hints after the parent chunk has loaded.
  • new URL() is a single-asset link injection with no chunk graph ordering semantics. Even if Webpack tried to impose an order, browsers schedule link fetches independently, so numeric values would be misleading and fragile.
  • Therefore:
    • Worker: numeric order is meaningful and matches existing import() semantics.
    • URL: boolean-only prefetch/preload for clarity and standards alignment; use fetchpriority for relative urgency instead.

Comment thread lib/dependencies/URLDependency.js Outdated
Comment thread lib/runtime/AssetPrefetchPreloadRuntimeModule.js Outdated
Comment thread lib/url/URLParserPlugin.js
Comment thread lib/url/URLParserPlugin.js
Comment thread test/configCases/asset-modules/url-prefetch-preload-fetchpriority/index.js Outdated
Comment thread test/dependencies/URLDependency.unittest.js Outdated
Comment thread lib/dependencies/URLDependency.js Outdated
@3ru 3ru force-pushed the feature/worker-prefetch-preload-support branch 4 times, most recently from e059f1b to 9ff7ec7 Compare July 27, 2025 20:50
@3ru 3ru force-pushed the feature/worker-prefetch-preload-support branch 4 times, most recently from 76d6374 to 270fdeb Compare August 10, 2025 02:50
@3ru
Copy link
Copy Markdown
Member Author

3ru commented Aug 10, 2025

rebased

@3ru 3ru force-pushed the feature/worker-prefetch-preload-support branch from 270fdeb to a84e769 Compare August 10, 2025 03:47
Comment thread lib/asset/AssetResourcePrefetchPlugin.js Outdated
Comment thread lib/asset/AssetResourcePrefetchPlugin.js Outdated
@3ru 3ru force-pushed the feature/worker-prefetch-preload-support branch from a84e769 to f7283bc Compare August 10, 2025 09:08
Comment thread lib/dependencies/URLDependency.js Outdated
Comment thread lib/url/URLParserPlugin.js
@evenstensberg
Copy link
Copy Markdown
Member

Let's try to get this reviewd, patched and merged soon.

3ru added 23 commits October 30, 2025 06:00
- Consolidate multiple runtime modules into unified AssetResourcePrefetchPlugin
- Remove complex startup prefetch mechanism in favor of simpler inline approach
- Introduced `preloadAs`, `preloadType`, and `preloadMedia` properties to `URLDependency` for better control over asset preloading.
@3ru 3ru force-pushed the feature/worker-prefetch-preload-support branch from a8d39c0 to aaae36e Compare October 30, 2025 13:00
@3ru
Copy link
Copy Markdown
Member Author

3ru commented Oct 30, 2025

Rebased this on the latest.
@alexander-akait Let me know if you need anything else from my side!

@alexander-akait
Copy link
Copy Markdown
Member

@3ru Thanks, a lot of tasks, still in my TODO 😞

alexander-akait added a commit that referenced this pull request May 22, 2026
Add a single `output.resourceHints` config that controls
`<link rel="prefetch">` / `<link rel="preload">` injection for every
URL-referenced asset in the bundle. The link is emitted at chunk
startup by a small runtime module that runs before any user module in
the chunk evaluates — for both initial and async chunks — so the
browser already has the response in flight by the time user code
references it.

Honored from three sources:

- JavaScript — `new URL(/* webpackPrefetch: true */ "./img.png", import.meta.url)`
  and `new Worker(new URL(/* webpackPreload: true */ "./w.js", import.meta.url))`.
  The hint comment must sit inside the inner `new URL(...)`; comments
  anywhere else in `new Worker(...)` are ignored.
- CSS (`experiments.css`) — `/* webpackPreload: true */ url("./font.woff2")`.
- HTML (`experiments.html`) — `<!-- webpackPreload: true --> <img src="/asset?url=https%3A%2F%2Fgithub.com%2Fwebpack%2Fwebpack%2Fpull%2Fhero.png">`.

Recognized comment keys: `webpackPrefetch`, `webpackPreload`,
`webpackFetchPriority`, plus `webpackAs` / `webpackType` /
`webpackMedia` on JS `new URL(...)`. The `as` attribute is
auto-detected from the file extension when `webpackAs` is omitted.

Project-wide defaults via `output.resourceHints` (single rule or array
of rules; each rule accepts the standard webpack `test` / `include` /
`exclude` matchers):

    output: {
      resourceHints: [
        { test: /\.(png|jpg|webp)$/, prefetch: true, fetchPriority: "low"  },
        { test: /\.woff2$/,           preload:  true, fetchPriority: "high" }
      ]
    }

Per-call magic comments win over the project-wide default. CSP nonce
on the bundle's `<script>` tag is picked up automatically (via
`document.currentScript.nonce` for script output,
`document.querySelectorAll('script')` matched by `import.meta.url`
for `output.module: true`). Plugin authors can extend the generated
`<link>` markup via
`ResourceHintRuntimeModule.getCompilationHooks(compilation).linkPrefetch` /
`.linkPreload`, and new URL emitters can read the same project-wide
config via `ResourceHintPlugin.getCompilationResolver(compilation)`.

Tests under `test/configCases/asset-modules/url-prefetch-preload*` and
`test/configCases/worker/worker-prefetch-preload` cover JS / CSS / HTML
sources, single + array config form, ESM output, split-runtime,
CSP nonce, and per-call magic-comment overrides.

#19695
alexander-akait added a commit that referenced this pull request May 22, 2026
Add a single `output.resourceHints` config that controls
`<link rel="prefetch">` / `<link rel="preload">` injection for every
URL-referenced asset in the bundle. The link is emitted at chunk
startup by a small runtime module that runs before any user module in
the chunk evaluates — for both initial and async chunks — so the
browser already has the response in flight by the time user code
references it.

Honored from three sources:

- JavaScript — `new URL(/* webpackPrefetch: true */ "./img.png", import.meta.url)`
  and `new Worker(new URL(/* webpackPreload: true */ "./w.js", import.meta.url))`.
  The hint comment must sit inside the inner `new URL(...)`; comments
  anywhere else in `new Worker(...)` are ignored.
- CSS (`experiments.css`) — `/* webpackPreload: true */ url("./font.woff2")`.
- HTML (`experiments.html`) — `<!-- webpackPreload: true --> <img src="/asset?url=https%3A%2F%2Fgithub.com%2Fwebpack%2Fwebpack%2Fpull%2Fhero.png">`.

Recognized comment keys: `webpackPrefetch`, `webpackPreload`,
`webpackFetchPriority`, plus `webpackAs` / `webpackType` /
`webpackMedia` on JS `new URL(...)`. The `as` attribute is
auto-detected from the file extension when `webpackAs` is omitted.

Project-wide defaults via `output.resourceHints` (single rule or array
of rules; each rule accepts the standard webpack `test` / `include` /
`exclude` matchers):

    output: {
      resourceHints: [
        { test: /\.(png|jpg|webp)$/, prefetch: true, fetchPriority: "low"  },
        { test: /\.woff2$/,           preload:  true, fetchPriority: "high" }
      ]
    }

Per-call magic comments win over the project-wide default. CSP nonce
on the bundle's `<script>` tag is picked up automatically (via
`document.currentScript.nonce` for script output,
`document.querySelectorAll('script')` matched by `import.meta.url`
for `output.module: true`). Plugin authors can extend the generated
`<link>` markup via
`ResourceHintRuntimeModule.getCompilationHooks(compilation).linkPrefetch` /
`.linkPreload`, and new URL emitters can read the same project-wide
config via `ResourceHintPlugin.getCompilationResolver(compilation)`.

Tests under `test/configCases/asset-modules/url-prefetch-preload*` and
`test/configCases/worker/worker-prefetch-preload` cover JS / CSS / HTML
sources, single + array config form, ESM output, split-runtime,
CSP nonce, and per-call magic-comment overrides.

#19695
alexander-akait added a commit that referenced this pull request Jun 4, 2026
Add a single `output.resourceHints` config that controls
`<link rel="prefetch">` / `<link rel="preload">` injection for every
URL-referenced asset in the bundle. The link is emitted at chunk
startup by a small runtime module that runs before any user module in
the chunk evaluates — for both initial and async chunks — so the
browser already has the response in flight by the time user code
references it.

Honored from three sources:

- JavaScript — `new URL(/* webpackPrefetch: true */ "./img.png", import.meta.url)`
  and `new Worker(new URL(/* webpackPreload: true */ "./w.js", import.meta.url))`.
  The hint comment must sit inside the inner `new URL(...)`; comments
  anywhere else in `new Worker(...)` are ignored.
- CSS (`experiments.css`) — `/* webpackPreload: true */ url("./font.woff2")`.
- HTML (`experiments.html`) — `<!-- webpackPreload: true --> <img src="/asset?url=https%3A%2F%2Fgithub.com%2Fwebpack%2Fwebpack%2Fpull%2Fhero.png">`.

Recognized comment keys: `webpackPrefetch`, `webpackPreload`,
`webpackFetchPriority`, plus `webpackAs` / `webpackType` /
`webpackMedia` on JS `new URL(...)`. The `as` attribute is
auto-detected from the file extension when `webpackAs` is omitted.

Project-wide defaults via `output.resourceHints` (single rule or array
of rules; each rule accepts the standard webpack `test` / `include` /
`exclude` matchers):

    output: {
      resourceHints: [
        { test: /\.(png|jpg|webp)$/, prefetch: true, fetchPriority: "low"  },
        { test: /\.woff2$/,           preload:  true, fetchPriority: "high" }
      ]
    }

Per-call magic comments win over the project-wide default. CSP nonce
on the bundle's `<script>` tag is picked up automatically (via
`document.currentScript.nonce` for script output,
`document.querySelectorAll('script')` matched by `import.meta.url`
for `output.module: true`). Plugin authors can extend the generated
`<link>` markup via
`ResourceHintRuntimeModule.getCompilationHooks(compilation).linkPrefetch` /
`.linkPreload`, and new URL emitters can read the same project-wide
config via `ResourceHintPlugin.getCompilationResolver(compilation)`.

Tests under `test/configCases/asset-modules/url-prefetch-preload*` and
`test/configCases/worker/worker-prefetch-preload` cover JS / CSS / HTML
sources, single + array config form, ESM output, split-runtime,
CSP nonce, and per-call magic-comment overrides.

#19695
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

support webpackPrefetch and webpackPreload for new Worker() chunk

5 participants