Angular-cli: Why does prerendering create NamedChunks?

Created on 14 Feb 2020  Β·  26Comments  Β·  Source: angular/angular-cli

🐞 Bug report

What modules are related to this issue?

  • [ ] aspnetcore-engine
  • [X] builders
  • [ ] common
  • [x] express-engine
  • [ ] hapi-engine
  • [ ] module-map-ngfactory-loader

Is this a regression?

I don't know cause i was not using the previous version

Description

Prerendering always creates named chunks. If i run ng run app:build:production everything builds correctly https://prnt.sc/r2dytb , but if i run it with ng run app:prerender:production the lazy loaded modules are still named based on the module name https://prnt.sc/r2dzp1

πŸ”¬ Minimal Reproduction

  1. Create angular app (v9)
  2. ng add @nguniversal/express-engine
  3. create a module to lazy load
  4. run ng run app:prerender:production

🌍 Your Environment


Angular CLI: 9.0.2
Node: 12.14.1
OS: win32 x64

Angular: 9.0.1
... animations, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... platform-server, router
Ivy Workspace: Yes

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.900.2
@angular-devkit/build-angular     0.900.2
@angular-devkit/build-optimizer   0.900.2
@angular-devkit/build-webpack     0.900.2
@angular-devkit/core              9.0.2
@angular-devkit/schematics        9.0.2
@angular/cli                      9.0.2
@ngtools/webpack                  9.0.2
@nguniversal/builders             9.0.0
@nguniversal/common               9.0.0
@nguniversal/express-engine       9.0.0
@schematics/angular               9.0.2
@schematics/update                0.900.2
rxjs                              6.5.4
typescript                        3.7.5
webpack                           4.41.2


devkiarchitect high broken bufix

Most helpful comment

Hi all, we didn't forget about this issue.

It's just that it taking more time to find the root cause of the problem.

All 26 comments

@alan-agius4 This is interesting because the browser target we are passing to the prerender builder is app:build:production. See add/index.ts. Do you have any idea why this happens?

Will need some debugging, I am also noticing that in one of screenshots sources are emitted while in the other screenshots they are not.

I also noticed that the file sizes are not the same (which they probably should be) so i am guessing that it runs the serverTarget instead of browserTarget.

This is the output for the files if i run it with the serverTarget configuration (https://prnt.sc/r2mwif). Which is close to being the same as on my second screenshot when i ran app:prerender:production https://prnt.sc/r2dzp1 (based on file size)

I looked at this briefly and it seems that this is a bug related to Angular Devkit architect.

Did a small test to confirm

I did a custom builder that calls the browser target;


const { createBuilder, targetFromTargetString } = require("@angular-devkit/architect");

async function execute(options, context) {
  const browserTarget = targetFromTargetString(options.browserTarget);
  console.log(
    'getTargetOptions', await context.getTargetOptions(browserTarget)
  );

  const browserTargetRun = await context.scheduleTarget(browserTarget);
  await browserTargetRun.result;
  await browserTargetRun.stop();

  return { success: true };
}

exports.default = createBuilder(execute);

Executing the above will return the below (Note: while sourceMaps is false, they are still generated)

getTargetOptions {
  outputPath: 'dist/uni-pre/browser',
  index: 'src/index.html',
  main: 'src/main.ts',
  polyfills: 'src/polyfills.ts',
  tsConfig: 'tsconfig.app.json',
  aot: true,
  assets: [ 'src/favicon.ico', 'src/assets' ],
  styles: [ 'src/styles.css' ],
  scripts: [],
  fileReplacements: [
    {
      replace: 'src/environments/environment.ts',
      with: 'src/environments/environment.prod.ts'
    }
  ],
  optimization: true,
  outputHashing: 'all',
  sourceMap: false,
  extractCss: true,
  namedChunks: false,
  extractLicenses: true,
  vendorChunk: false,
  buildOptimizer: true,
  budgets: [
    { type: 'initial', maximumWarning: '2mb', maximumError: '5mb' },
    {
      type: 'anyComponentStyle',
      maximumWarning: '6kb',
      maximumError: '10kb'
    }
  ]
}
Generating ES5 bundles for differential loading...
ES5 bundle generation complete.

chunk {3} polyfills-es5.041738d66a3982520e90.js, polyfills-es5.041738d66a3982520e90.js.map (polyfills-es5) 127 kB [initial] [rendered]
chunk {2} polyfills-es2015.db39b23daa8851ccf344.js, polyfills-es2015.db39b23daa8851ccf344.js.map (polyfills) 35.7 kB [initial] [rendered]
chunk {0} runtime-es2015.0811dcefd377500b5b1a.js, runtime-es2015.0811dcefd377500b5b1a.js.map (runtime) 1.51 kB [entry] [rendered]
chunk {0} runtime-es5.0811dcefd377500b5b1a.js, runtime-es5.0811dcefd377500b5b1a.js.map (runtime) 1.51 kB [entry] [rendered]
chunk {1} main-es2015.4da5b65032ea1b50beac.js, main-es2015.4da5b65032ea1b50beac.js.map (main) 27.1 kB [initial] [rendered]
chunk {1} main-es5.4da5b65032ea1b50beac.js, main-es5.4da5b65032ea1b50beac.js.map (main) 27.3 kB [initial] [rendered]
chunk {5} vendor-es2015.126aaec3f9743611b6ec.js, vendor-es2015.126aaec3f9743611b6ec.js.map (vendor) 215 kB [initial] [rendered]
chunk {5} vendor-es5.126aaec3f9743611b6ec.js, vendor-es5.126aaec3f9743611b6ec.js.map (vendor) 260 kB [initial] [rendered]
chunk {4} styles.8547d00c5fcaf5c47c33.css, styles.8547d00c5fcaf5c47c33.css.map (styles) 0 bytes [initial] [rendered]
Date: 2020-02-19T08:46:11.724Z - Hash: a4caaf1c847b94bf8394 - Time: 24565ms

The interesting part is that if we omit calling context.getTargetOptions prior to context.scheduleTarget the result is different,.

Let update our builder to;


const { createBuilder, targetFromTargetString } = require("@angular-devkit/architect");

async function execute(options, context) {
  const browserTarget = targetFromTargetString(options.browserTarget);
  // console.log(
  //   'getTargetOptions', await context.getTargetOptions(browserTarget)
  // );

  const browserTargetRun = await context.scheduleTarget(browserTarget);
  await browserTargetRun.result;
  await browserTargetRun.stop();

  return { success: true };
}

exports.default = createBuilder(execute);

Here's the result;

Generating ES5 bundles for differential loading...
ES5 bundle generation complete.

chunk {2} polyfills-es2015.ca64e4516afbb1b890d5.js (polyfills) 35.6 kB [initial] [rendered]
chunk {3} polyfills-es5.277e2e1d6fb2daf91a5c.js (polyfills-es5) 127 kB [initial] [rendered]
chunk {0} runtime-es2015.0811dcefd377500b5b1a.js (runtime) 1.45 kB [entry] [rendered]
chunk {0} runtime-es5.0811dcefd377500b5b1a.js (runtime) 1.45 kB [entry] [rendered]
chunk {1} main-es2015.be16c3d420978605e6ed.js (main) 216 kB [initial] [rendered]
chunk {1} main-es5.be16c3d420978605e6ed.js (main) 258 kB [initial] [rendered]
chunk {4} styles.3ff695c00d717f2d2a11.css (styles) 0 bytes [initial] [rendered]
Date: 2020-02-19T08:49:18.308Z - Hash: e6d6b1251cfe649fbfa7 - Time: 20023ms

Transferring to the CLI repo and chiming in @clydin

Now in prerender there is only dev assembly, and it is needed only for production

So any update on this?

Same issue. Also ngsw-worker.js isn't getting built during prerender, where it is within ng build.

Running into the same issue, appears it is generating a dev build for some reason. My work around, although very ugly is to build for prerender then build for prod and copy over the prerender html files over to the prod build. Then update the bundle paths in the html files for prod. Very ugly but only work around I could think of for right now just to have a solution.

Whatching on this beacuse this makes impossible to use ng service worker with prerender (So bad) @Exocomp please can you post some snippets on how to do your workaround?

@skyquartam

It's pretty ugly (I stress it again) but here is the general idea, however, I recommend just waiting for an actual fix:

  • Build for prerender

    • Afterwards rename the dist folder to something else (ex. dist_prerender)

  • Build for prod

    • Afterwards copy the .html files from dist_prerender over to dist

    • For each .html file modify the previous bundle paths to the prod bundle paths

Since you're working with a service worker you probably will have to update the service worker json file (ngsw.json) with the new file hashes (sha-1) or I think it will break how sw works.

Quick and dirty workaround if your dev workflow doesn't depend on named chunks:

  1. Open "node_modules/@angular-devkit/build-angular/src/angular-cli-files/plugins/named-chunks-plugin.js"
  2. Comment out "dependency.block.chunkName = Template.toPath(dependency.request);" (line 26)

This will prevent the named chunks plugin from renaming dependencies.

I think having named chunks is just the surface of the problem where the root problem is like @alan-agius4 mentioned that context.scheduleTarget isn't doing what it's supposed to do when building with a configuration target.

Common guys this has been opened for 2 months now, Universal prerendering is practically useless since it was released

Let's try to be nice and respectful to the people who work very hard on the tools we love πŸ˜€

But it is an issue in the milestone of 9.0.x... Maybe re-pinging @clydin and @alan-agius4 could help?

πŸ™ Thank you all!!

Hi all, we didn't forget about this issue.

It's just that it taking more time to find the root cause of the problem.

Thank you for the update!!
We really appreciate it and all your hard work!!

@alan-agius4 Alan, I rebuilt the 9.1.2 release with your fix and I'm able to produce a prerender build without the maps. Thank you!

Thank you guys β™₯

is this already released via npm? I updated to Angular CLI 9.1.2 but still get the maps and named chunks with the prerender

No, this will be released in version 9.1.3.

On Wed, 22 Apr 2020 at 09:47, Denis notifications@github.com wrote:

is this already released? I updated to Angular CLI 9.1.2 but still get the
maps and named chunks with the prerender

β€”
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/angular/angular-cli/issues/17021#issuecomment-617611732,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AEF74WSJU43FTUPDFUHFQCDRN2OJ3ANCNFSM4KXUTSLA
.

Ah, I see. Thanks a lot

And it just got released! What a speedy release πŸ˜†
(cc @denisyilmaz)
Thanks again to @alan-agius4 finding an easy solution to a difficult bug πŸ˜‚

Can confirm it works!! <3

Nice desu ne

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._

Was this page helpful?
0 / 5 - 0 ratings

Related issues

NCC1701M picture NCC1701M  Β·  3Comments

sysmat picture sysmat  Β·  3Comments

rwillmer picture rwillmer  Β·  3Comments

purushottamjha picture purushottamjha  Β·  3Comments

jmurphzyo picture jmurphzyo  Β·  3Comments