angular / angular/angular-cli

Improve loading of 3P scripts

Offen
#21,229 3 Kommentare 5 Reaktionen 1 zugewiesene Person Beansprucht von @clydin Auf GitHub ansehen
area: @angular-devkit/build-angular devkit/build-angular:browser feature
Vorherrschende Sprache
TypeScript
Sterne
27k
Forks
11.8k
Ø Merge
14 Std. 23 Min.
Gemergte PRs (30 T.)
162

Beschreibung

# 🚀 Feature request

### Command (mark with an `x`)

- [ ] new
- [x] build
- [x] serve
- [ ] test
- [ ] e2e
- [ ] generate
- [ ] add
- [ ] update
- [ ] lint
- [ ] extract-i18n
- [ ] run
- [ ] config
- [ ] help
- [ ] version
- [ ] doc

### Description

Loading third-party scripts in a suboptimal way can cause performance regressions. A typical example is adding an SDK as script tag directly to the page head, which will block the loading of first-party scripts and delay hydration/CSR if done incorrectly.

### Describe the solution you'd like

Expand `scripts` the functionality already available in `angular.json`, allowing developers to configure different script loading strategies. Project [Aurora](https://web.dev/aurora) identified three script loading strategies that we can reuse:

- `afterInteractive` - this strategy would prioritize first-party scripts by executing third-party scripts after the page has been hydrated or client-side rendered.
- `beforeInteractive` - execute third-party scripts before first-party scripts. This strategy is particularly important for loading polyfills. Since we already have `polyfill.ts`, I'm a little hesitant to include it in the Angular CLI as part of the first feature iteration. I'd suggest keeping it out of scope and collecting feedback in the meantime.
- `lazyOnload` - lowest priority. We load these scripts and execute them in `requestIdleCallback`. Examples for libraries using this strategy for prefetching are [quicklink](https://github.com/GoogleChromeLabs/quicklink), [ngx-quicklink](https://github.com/mgechev/ngx-quicklink), and [guess-js](https://github.com/guess-js/guess).

We'd sometimes need a hook after the script has been loaded and executed if we load it asynchronously (`afterInteractive` or `lazyOnload`). For example, rendering a payment dialog after we've downloaded a third-party SDK.

Using `angular.json` does not provide an evident approach that would let us accomplish this. A lower-level API that would provide the necessary functionality is to allows developers to specify `id`'s in the script declaration. Using the `id`, developers will discover the `script` element in their code and hook to its `onload` event.

This way, the `scripts` property in `angular.json` would change from an array of strings or [objects](https://angular.io/guide/workspace-config#styles-and-scripts-configuration) to an array of strings or objects with the following properties:
- `input` - the source URL or path of the script. The CLI will perform different actions depending on whether `input` is a local path or a remote URL
- `strategy` - `afterInteractive`, `beforeInteractive`, or `lazyOnload`
- `inject` - specifies if the script should be injected or not. We preserve the current semantics of the `inject` property in the script object
- `bundleName` - applicable for local scripts only. For external scripts, we can throw an error
- `id` - an optional identifier that the developer can use to get a hold of the script and hook to its `onload` event

Suppose we find a string rather than an object for a given script. In that case, we can treat it as a script object with an `input` the specified string, `strategy` equal to `beforeInteractive` for the current major, or `afterInteractive` for the next major. Ideally, we'd want the default strategy to be `afterInteractive` to prevent folks from causing performance regressions, but since this would be a breaking change, we don't want to do this until v13.

In v13, we can migrate all the scripts from objects to strings using the `beforeInteractive` strategy.

### Describe alternatives you've considered

Project Aurora considered using a script component for alternative frameworks. Their approach easier accommodates the `onLoad` callback use case but seems to fit less naturally in the Angular CLI model.

Beitragsleitfaden

Beitragsleitfaden öffnen

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.