1

In Angular, it is quite easy to break lazy-loading. For example, all it takes is for someone to carelessly import something from a lazy-loaded module into the app module and this module is eagerly loaded. Therefore, I usually check for such errors when reviewing PRs. Currently, I do this manually by looking at the logs of ng build or by inspecting the network logs in the browser DevTools. However, I would like to automate this repetitive task in our CI pipeline.

After trying various methods, I can only think of two more or less suboptimal approaches:

  1. A script that builds the app and then checks if the expected number of lazy-loaded chunks is in the dist folder. However, this does not test when a chunk is loaded.
  2. E2e tests that assert that a specific .js chunk file is loaded when the browser navigates to a specific route.

Is there any better way to programmatically check if lazy-loading works for all lazy-loaded modules?

EDIT: To be more precise: there are some answers on StackOverflow regarding this topic, but they usually rely so heavily on stubbing and mocking that, in the end, they don't test the actual implementation.

Fody
  • 23,754
  • 3
  • 20
  • 37
georg-un
  • 1,123
  • 13
  • 24

3 Answers3

1

Maybe this is what you meant in option 2 - I would set up an intercept to verify the chunk is loaded after an action that invokes the lazy load.

cy.intercept('**/*.chunk.js', { times: 1 })       // one time only
  .as('chunk'); 
cy.visit('/orders');      
cy.wait('@chunk');                                // fails if not lazy loaded

I'm not sure if that minimatch pattern will catch the chunk, but you can also check using javascript.

cy.intercept('*', { times: 1 }, (req) => {
  if (req.url.includes('chunk')) {
    req.alias = 'chunk'
  }
});
Fody
  • 23,754
  • 3
  • 20
  • 37
1

Since this question is now active without answers for over a month, I will share how I was finally able to solve it. May it help someone in the future.

The solution was the following:

  1. In the angular.json set the build option namedChunks to true. This causes the lazy chunks to be named after their file path.
  2. For every lazy-loaded module, write an e2e test like so:
    // Assume our lazy-loaded chunk file is called `our_lazy_feature_module.js`
    
    
    it('should lazy-load /our-lazy-feature', () => {
    
      // set up the interceptor
      cy.intercept({ method: 'GET', url: /^.*our_lazy_feature.*$/g })
        .as('chunkFileRequests')
    
      // visit about page and assert that the chunk file has not yet been loaded
      cy.visit('/'); // navigate to a eagerly loaded route
      cy.get('@chunkFileRequests.all')
        .should('have.length', 0);
    
      // click on the link to the lazy-loaded page and assert that the chunk file gets loaded
      cy.contains('a', 'Link to our lazy feature')
        .click();
      cy.contains('h1', 'Welcome to our lazy feature')
        .should('be.visible');  // wait for the navigation to complete
      cy.get('@chunkFileRequests.all').should('have.length', 1);
    
    });
    
georg-un
  • 1,123
  • 13
  • 24
  • The only thing I would say is `cy.get('@chunkFileRequests.all')` is non-waiting, perhaps that test line passes before the chunk gets loaded? Not sure, I've not tested this. Did you red/green the test (i.e switch off `our_lazy_feature` and confirm the test fail)? – Fody Sep 09 '22 at 07:39
0

Use webpack-bundle-analyzer programmatically to verify that source files are split into different chunks! Note that this isn't really an Angular question, the same problem arises in any framework that uses webpack.

I've written a npm script to do the last step of turning the bundle analyzer output into CI tests, which you can find at https://www.npmjs.com/package/@talque/webpack-bundle-ci-test

To check that your feature modules are lazy loaded and split into different chunks you can just run (assuming your build output path is dist/app):

npx ng build --stats-json
npx webpack-bundle-analyzer /
      dist/app/stats.json --mode json /
      --report dist/app/report.json
npx webpack-bundle-ci-test /
      is-lazy /
      dist/app/report.json /
      'projects/features/**/*.ts'
npx webpack-bundle-ci-test /
      distinct-chunks /
      dist/app/report.json /
      'projects/features/*/src/lib/*.module.ts'

Don't forget to quote globstar (**) to prevent the shell from expanding it.

vbraun
  • 1,851
  • 17
  • 14