GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Excessive modulepreload Links in Angular 18.0.0-next.4 Affecting Performance Metrics · Issue #27490 · angular/angular-cli

Excessive modulepreload Links in Angular 18.0.0-next.4 Affecting Performance Metrics #27490

New issue
Copy link
New issue
Copy link
Closed
Closed
Excessive modulepreload Links in Angular 18.0.0-next.4 Affecting Performance Metrics#27490
Copy link
Labels
angular/build:applicationarea: @angular-devkit/build-angularneeds: more infoReporter must clarify the issueReporter must clarify the issueseverity4: memory/performance
Milestone
needsTriage

Description

@manzonif
manzonif
opened on Apr 17, 2024
Issue body actions

Which @angular/* package(s) are the source of the bug?

platform-server

Is this a regression?

No

Description

I recently upgraded my Angular application to version 18.0.0-next.4 and migrated to esbuild and the new integrated SSR. However, I've noticed a significant impact on performance metrics, particularly First Contentful Paint (FCP) and Largest Contentful Paint (LCP), when using the new version.

Upon further investigation, I found that Angular now splits all JavaScript code into chunks and adds a <link rel="modulepreload"> for each chunk in the <head> of the page. Although the scripts are loaded asynchronously with @defer method, the preloaded scripts seem to be affecting the rendering of critical content, delaying FCP and LCP.

I've conducted tests using Lighthouse, and the results show that removing the modulepreload links improves FCP and LCP metrics. This issue seems to be similar to what was reported in these GitHub discussions:

GoogleChrome/lighthouse#11960
vitejs/vite#5991
In both discussions, users reported improvements in FCP and LCP metrics after disabling or reducing the number of modulepreload links.

Unfortunately, I couldn't find a way to selectively disable modulepreload links in Angular 18.0.0-next.4 based on specific use cases. Therefore, I would like to seek clarification and guidance on how to address this issue to improve performance.

Steps to Reproduce:

Upgrade an Angular application to version 18.0.0-next.4.
Enable SSR and use esbuild.
Analyze performance metrics using Lighthouse with and without the modulepreload links.
Expected Behavior:
I expect to see improved FCP and LCP metrics when excessive modulepreload links are removed or selectively disabled.

Additional Information:
I have attached screenshots of the Lighthouse test results, showing the impact of modulepreload links on performance metrics.

Screenshots:

Screenshot 1 - Lighthouse Test with modulepreload links

Screenshot 2024-04-17 132612

Screenshot 2 - Lighthouse Test without modulepreload links
Performed by removing all modulepreload links server side:

        html = html.replace(
          /<link .?rel="modulepreload" .*?href="(?<href>.+?\.js)".*?>/g,
          ''
        );

Screenshot 2024-04-17 132254

Your assistance in resolving this issue would be greatly appreciated.

Thank you.

Please provide a link to a minimal reproduction of the bug

No response

Please provide the exception or error you saw

No response

Please provide the environment you discovered this bug in (run ng version)

Angular CLI: 18.0.0-next.2
Node: 20.11.1
Package Manager: yarn 1.22.21
OS: win32 x64

Angular: 18.0.0-next.4
... animations, cdk, common, compiler, compiler-cli, core, forms
... google-maps, language-service, localize, material
... platform-browser, platform-browser-dynamic, platform-server
... router, service-worker

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.1800.0-next.2
@angular-devkit/build-angular     18.0.0-next.2
@angular-devkit/build-optimizer   0.1302.1
@angular-devkit/core              18.0.0-next.2
@angular-devkit/schematics        17.1.2
@angular/cli                      18.0.0-next.2
@angular/ssr                      18.0.0-next.2
@schematics/angular               18.0.0-next.2
rxjs                              7.8.1
typescript                        5.4.5
zone.js                           0.14.4

Anything else?

No response

Activity

  1. ngbot
    added this to the needsTriage milestone on Apr 17, 2024
  2. atscott
    transferred this issue fromangular/angularon Apr 17, 2024
  3. alan-agius4 commented on Apr 18, 2024

    @alan-agius4
    alan-agius4
    on Apr 18, 2024
    Collaborator
    More actions

    You can disable to preload tags by using the preloadInitial option.

      "projects": {
        "test": {
          "projectType": "application",
          "schematics": {},
          "root": "",
          "sourceRoot": "src",
          "prefix": "app",
          "architect": {
            "build": {
              "builder": "@angular-devkit/build-angular:application",
              "options": {
                "outputPath": "dist/",
                "index": {
                  "input": "src/index.html",
                  "preloadInitial": false
                },
    Reacted by Martin Mueller
  4. alan-agius4
    added
    needs: investigationRequires some digging to determine if action is neededRequires some digging to determine if action is needed
    area: @angular-devkit/build-angular
    angular/build:application
    on Apr 18, 2024
  5. manzonif commented on Apr 18, 2024

    @manzonif
    manzonif
    on Apr 18, 2024
    Author
    More actions

    @alan-agius4 Thank you for your response and for providing the solution.

    I would appreciate it if you would consider implementing support for selective filtering of module preloading links. I believe a feature like this would be incredibly valuable, especially for larger applications where fine-grained control over resource loading can have a significant impact on performance.

    The implementation described in the Vite.js pull request #9938 seems to provide a robust solution by allowing users to define a resolveDependencies function to filter or modify the list of dependencies. This level of flexibility would empower developers to optimize resource loading based on specific use cases and performance requirements.

    Are you planning to incorporate this functionality into Angular in the near future?
    You might, for example, think about implementing it as part of the @defer block.

  6. alan-agius4 commented on Apr 18, 2024

    @alan-agius4
    alan-agius4
    on Apr 18, 2024
    Collaborator
    More actions

    @manzonif, I'm curious, how many preload links do you use?

    Generally, offering such options doesn't really align with our design goals. Instead, we aim to provide a more responsive default that can cater to applications of all sizes.

    There's definitely a correlation between Core Web Vitals (CWV) and preload tags. The more preload tags, the poorer the performance tends to becomes at least based on https://almanac.httparchive.org/en/2021/resource-hints#correlation-with-core-web-vitals

  7. manzonif commented on Apr 18, 2024

    @manzonif
    manzonif
    on Apr 18, 2024
    Author
    More actions

    I count about 50 modulepreload links, plus an image that is part of the LCP. Of course it depends on the page being examined.

    Furthermore, some of these modules, in turn, require the loading of third-party javascript (with the intention that they should be loaded late),perhaps making the situation even worse.

  8. alan-agius4
    added
    severity4: memory/performance
    on Apr 18, 2024
  9. manzonif commented on Apr 19, 2024

    @manzonif
    manzonif
    on Apr 19, 2024
    Author
    More actions

    @alan-agius4, I also noticed that Angular preloaded modules take precedence in the document head over those inserted inside a component. If what @patrickhulce reports here is correct, the order of the preload hints is also important. Therefore, it would be necessary to ensure that the insertion of the module preloads is postponed, at least until after the ngOnInit lifecycle hook of the components.

    If I add a preload for an LCP image, it should have high priority, IMO.

  10. sod commented on May 6, 2024

    @sod
    sod
    on May 6, 2024
    Contributor
    More actions

    Esbuild can dump a stats.json via ng build --stats-json that contains the information which files are required to load lazy loaded chunks. See https://esbuild.github.io/api/#metafile (the outputs part)

    Ssr could use the stats.json to only load the chunks required for the current route.

  11. alan-agius4 commented on May 6, 2024

    @alan-agius4
    alan-agius4
    on May 6, 2024
    Collaborator
    More actions

    The most recent RC version contains a change to only generate shallow preload links for initial files. You can find more details in PR #27581.

    @manzonif, could you please confirm if this resolves your issue?

    @sod, in this situation, the issue lies not in the absence of preloads, but rather in having more than approximately 5 preloads, even for files essential to the route. Essentially, including a substantial number of preload links could create a performance bottleneck, more so when using SSR, as it might disrupt the browser's fetch priority.

    Reacted by Alexander von Weiss
  12. alan-agius4
    added
    needs: more infoReporter must clarify the issueReporter must clarify the issue
    and removed
    needs: investigationRequires some digging to determine if action is neededRequires some digging to determine if action is needed
    on May 6, 2024
  13. manzonif commented on May 14, 2024

    @manzonif
    manzonif
    on May 14, 2024
    Author
    More actions

    Hi @alan-agius4,

    Sorry for the delay in replying.

    The PR certainly addresses the issue of excessive preload links. However, I have a couple of remaining concerns:

    1. If the order of links is important, I believe that those inserted by the component should take precedence over others. For example, in the case of an LCP (Largest Contentful Paint) image.

    2. Limiting the preloads to the first three chunks might sometimes produce unexpected results. In my case, importing utility functions from other .ts files into the main component results in these small files being the three preload links. While I imagine this issue could be resolved by restructuring the imports, I wanted to bring it to your attention.

    Below are some example images:

    Screenshot 2024-05-14 114606
    Screenshot 2024-05-14 114652

  14. alan-agius4 commented on Aug 30, 2024

    @alan-agius4
    alan-agius4
    on Aug 30, 2024
    Collaborator
    More actions

    I believe that the issue with the order of links has likely been resolved. However, if the problem persists, please provide a reproduction. As for the issue with small chunks, it is currently being tracked here: #27715.

    Reacted by manzonif
  15. alan-agius4
    closed this as completedon Aug 30, 2024
  16. angular-automatic-lock-bot commented on Sep 30, 2024

    @angular-automatic-lock-bot
    angular-automatic-lock-botBot
    on Sep 30, 2024
    More actions

    This issue has been automatically locked due to inactivity.
    Please file a new issue if you are encountering a similar or related problem.

    Read more about our automatic conversation locking policy.

    This action has been performed automatically by a bot.

  17. angular-automatic-lock-bot
    locked and limited conversation to collaborators on Sep 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    angular/build:applicationarea: @angular-devkit/build-angularneeds: more infoReporter must clarify the issueReporter must clarify the issueseverity4: memory/performance

    Type

    No type

    Projects

    No projects

      Milestone

      • needsTriageNo due date

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402503 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.