Skip to content

feat(core): Adds @defer retry for failed dependency loads#68738

Open
SkyZeroZx wants to merge 1 commit into
angular:mainfrom
SkyZeroZx:feature/defer-error-retry
Open

feat(core): Adds @defer retry for failed dependency loads#68738
SkyZeroZx wants to merge 1 commit into
angular:mainfrom
SkyZeroZx:feature/defer-error-retry

Conversation

@SkyZeroZx
Copy link
Copy Markdown
Contributor

@SkyZeroZx SkyZeroZx commented May 14, 2026

Introduces support for retrying failed @defer block dependency loads via a new @error (retry N) parameter. This feature allows applications to automatically recover from transient network failures or intermittent issues by re-attempting the chunk download up to N times. Each retry attempt automatically applies cache-busting to bypass browser caching of failed dynamic imports.

A new provideDeferBlockRetryHandler public API enables customization of the retry mechanism. This hook empowers advanced use cases such as exponential backoff.

Compiler changes wrap dynamic imports in "thunks," allowing the DeferBlockRetryHandler to access the original import function for re-invocation and URL inspection.

Closes #52800

Other information

The proposed syntax

 @defer (on idle) {
   <app-large-flaky />
 } @loading (minimum 200ms) {
    <p>Loading… </p>
 } @error (retry 3) {
    <p>All retries exhausted </p>
 }

Another alternative could be

 @defer (on idle) {
   <app-large-flaky />
 } @loading (minimum 200ms) {
    <p>Loading… </p>
 } @error ({retry:3 , otherParamsHere... }) {
    <p>All retries exhausted </p>
 }

However, considering we can customize with a provider, it might not be worthwhile atm.

Customizing retry behavior

I was also inspired by Vue, which has a similar API, defineAsyncComponent.

import {provideDeferBlockRetryHandler} from '@angular/core';

bootstrapApplication(App, {
  providers: [
    provideDeferBlockRetryHandler(async (load, ctx) => {
      if (ctx.attempt === 0) {
        return load();
      }
      // Exponential backoff before each retry.
      await new Promise((resolve) => setTimeout(resolve, 2 ** ctx.attempt * 100));
      // `ctx.retry()` re-issues the chunk download with cache-busting applied,
      // so you don't have to parse import URLs yourself.
      return ctx.retry();
    }),
  ],
});

Repository as a Proof of Concept : https://github.com/SkyZeroZx/defer-retry-poc

retry.demo.mp4

Introduces support for retrying failed `@defer` block dependency loads via a new `@error` (retry N) parameter. This feature allows applications to automatically recover from transient network failures or intermittent issues by re-attempting the chunk download up to N times. Each retry attempt automatically applies cache-busting to bypass browser caching of failed dynamic imports.

A new `provideDeferBlockRetryHandler` public API enables customization of the retry mechanism. This hook empowers advanced use cases such as exponential backoff.

Compiler changes wrap dynamic imports in "thunks," allowing the `DeferBlockRetryHandler` to access the original import function for re-invocation and URL inspection.

Closes angular#52800
@angular-robot angular-robot Bot added detected: feature PR contains a feature commit area: core Issues related to the framework runtime labels May 14, 2026
@ngbot ngbot Bot added this to the Backlog milestone May 14, 2026
//
// `@vite-ignore` must stay as its own exact comment so Vite suppresses the
// "dynamic import cannot be analyzed" warning.
return import(/* @vite-ignore */ retryUrl).then((mod) => {
Copy link
Copy Markdown
Contributor Author

@SkyZeroZx SkyZeroZx May 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An additional point is that this will only work with EsBuild/Vite; in the case of webpack, since it uses a global variable, it's a bit more complex (and considering it's been deprecated, I don't think it's worth adding support for it).

And a patch will probably be needed to keep the vite-ignore comment, otherwise we'll get a warning on the dev server.

Copy link
Copy Markdown
Contributor

@arturovt arturovt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome!

@SkyZeroZx SkyZeroZx marked this pull request as ready for review May 15, 2026 20:34
@pullapprove pullapprove Bot requested review from JeanMeche and JoostK May 15, 2026 20:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: core Issues related to the framework runtime detected: feature PR contains a feature commit

Projects

None yet

Development

Successfully merging this pull request may close these issues.

@defer additional support for "error" and "retry" options for the "@error" block

2 participants