Skip to content
This repository was archived by the owner on Mar 20, 2024. It is now read-only.
This repository was archived by the owner on Mar 20, 2024. It is now read-only.

Illegal invocation calling window.getComputedStyle #135

Description

@leifmarcus

I included the PrebotModule in an Angular 12 project and I found that the following line breaks, because the call to getComputedStyle is Illegal.

const gcs = this.getWindow().getComputedStyle;

The getComputedStyle object is set here:

getComputedStyle: window.getComputedStyle,

  • I'm submitting a ...
  • bug report
  • feature request
  • Which parts of preboot are affected by this issue?
  • server side
  • client side
  • inline
  • build process
  • docs
  • tests
  • What is the current behavior?
    Currently it throws an error and breaks the swapping of the root application.

  • If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem by

  • What is the expected behavior?
    Should not fail when running in the browser. I would suggest to add .bind(window) to the declaration.

  • Please tell us about your environment:

  • Browser: [Chrome 92.0.4515.159]
  • Language: [TypeScript 4.3 | ES6/7 | ES5 ]
  • OS: [Mac OS X]

image

Activity

  1. kvirrik commented on Sep 1, 2021

    @kvirrik

    maybe this is caused by angular v.12.2.x. I have the same problem, after updating angular version

  2. jakubsobel commented on Sep 3, 2021

    @jakubsobel

    I have the same problem, after updating from Angular 11.2.5 to 12.2.0.

  3. boban100janovski commented on Sep 3, 2021

    @boban100janovski

    Solved it by using this hack.

    Install this package "replace-in-file",
    Then create a node script to execute before build.

    `const replace = require('replace-in-file');
    const options = {
    files: './node_modules/preboot/fesm2015/preboot.js',
    from: 'gcs(serverView).getPropertyValue('display') || 'block';',
    to: 'serverView ? (gcs(serverView).getPropertyValue('display') || 'block') : 'block';'
    };

    try {
    const results = replace.sync(options);
    console.log('Replacement results:', results);
    }
    catch (error) {
    console.error('Error occurred:', error);
    }
    `

    Then add a new command to package.json
    "fix_minify": "node ./node_scripts/fixMinify.js"

    Use it before the build
    "build:ssr": "npm run fix_minify && ng build --configuration production --localize && ng run URProject:server:production

    I think the issue is caused because Angular 12 uses another minifier, that is "Terser", before it was Uglify i think.

  4. maxisam commented on Sep 8, 2021

    @maxisam

    It is caused by 12.2.0. It was fine with 12.1.4.

  5. jsaguet-betclic commented on Sep 15, 2021

    @jsaguet-betclic

    I encountered the same issue when migrating to 12.2.5.

    @CaerusKaru, @alan-agius4 have you seen this issue ?

    For information:
    No error is present with "@angular-devkit/build-angular": "12.2.0-next.0"
    Error occurs starting from "@angular-devkit/build-angular": "12.2.0-next.2"

    Tested with all other packages set to 12.2.5

  6. dragonflypl commented on Sep 27, 2021

    @dragonflypl

    I have the same issue after migration to latest angular 12.2.x

  7. ns-rickvdmeij commented on Oct 12, 2021

    @ns-rickvdmeij

    Can confirm downgrading back to 12.1.4 solves the issue for me now, waiting for an update

  8. boban100janovski commented on Oct 21, 2021

    @boban100janovski

    Seems like "Preboot" is not maintained anymore

  9. lares83 commented on Oct 26, 2021

    @lares83

    any news about this issue?

  10. CaerusKaru commented on Oct 27, 2021

    @CaerusKaru
    Member

    Does anyone have a minimal reproduction we can investigate? We're in the process of cleaning up the repo and bringing it up to date, but it's hard to say what the issue is here without a firm reproduction.

  11. jakubsobel commented on Oct 27, 2021

    @jakubsobel

    Minimal reproduction: https://github.com/jakubsobel/angular12-preboot-issue
    I've created a new angular app using ng new. Then ng add @nguniversal/express-engine and then followed https://github.com/angular/preboot#installation.
    Running npm run build:ssr and then npm run serve:ssr is causing Illegal invocation:
    Screenshot 2021-10-27 at 13 11 20

  12. morghim commented on Nov 10, 2021

    @morghim

    any updates on this ?

  13. internalsystemerror commented on Nov 11, 2021

    @internalsystemerror

    Having the same issue here on 12.2.x.

  14. lares83 commented on Nov 19, 2021

    @lares83

    @CaerusKaru any update about this issue?

  15. jsaguet commented on Nov 22, 2021

    @jsaguet

    I submitted a fix in this PR: #146
    It seems the error comes from a scope issue.
    Something in the build must have changed starting from 12.2

    Let's hope it will be checked soon by @CaerusKaru as this error is also blocking for Angular 13 migration

  16. 1 remaining item

  17. webberig commented on Jan 8, 2022

    @webberig

    Problem still present in Angular 13

    @boban984 's replace script did not solve it, it does not contain the same replacement as PR #146 .

    This is an updated version of the script:

    fix_minify.js:

    const replace = require('replace-in-file');
    const options = {
      files: [
        './node_modules/preboot/__ivy_ngcc__/fesm2015/preboot.js',
        './node_modules/preboot/fesm2015/preboot.js',
        './node_modules/preboot/esm2015/api/event.replayer.js',
        './node_modules/preboot/bundles/preboot.umd.js',
        './node_modules/preboot/bundles/preboot.umd.min.js',
      ],
      from: `getComputedStyle: window.getComputedStyle`,
      to: `getComputedStyle: (element, pseudoElt) => window.getComputedStyle(element, pseudoElt)`
    };
    
    try {
      const results = replace.sync(options);
      console.log('Replacement results:', results);
    }
    catch (error) {
      console.error('Error occurred:', error);
    }
    

    Took a while. for me to figure out, but after installing this script, you need to clear an Angular build cache:

    rm -Rf .angular/cache
    node fix_minify.js
    

    After that, it worked for me (confirming #146 will provide the fix)

  18. Judp0m commented on Feb 5, 2022

    @Judp0m

    I can confirm that #146 and webberig's comment resolved the issue in my case.
    Hopefully it gets officially patched soon, so that the hacky node script can be removed from the codebase.

  19. lares83 commented on Feb 23, 2022

    @lares83

    any update about this issue?

  20. hiepxanh commented on Mar 9, 2022

    @hiepxanh

    I dont have problem with angular 13, can you test it again? what function do you call?

  21. hiepxanh commented on Mar 9, 2022

    @hiepxanh

    ok I see the problem now, basicly, the preboot canot useable sorry to say that

  22. pavelrazuvalau commented on Mar 29, 2022

    @pavelrazuvalau

    I removed preboot from my project as I used it only for fixing page flickering. Seems it doesn't actively maintained and instead of applying workarounds I just implemented my own solution for showing overlay. The idea is pretty simple:

    app.module.ts

    providers: [
        {
          provide: APP_INITIALIZER,
          useFactory: fixPageFlickering,
          deps: [PLATFORM_ID],
        },
      ],
    
    export function fixPageFlickering(platformId: string): () => void {
      return () => {
        if (isPlatformBrowser(platformId)) {
          const transitionStyles = Array.from(document.querySelectorAll('style[ng-transition]'));
    
          const serverRoot = document.body.querySelector('app-root') as HTMLElement;
          const clientRoot = serverRoot.cloneNode() as HTMLElement;
    
          serverRoot.setAttribute('ng-non-bindable', '');
          clientRoot.style.display = 'none';
    
          document.body.insertBefore(clientRoot, serverRoot);
    
          transitionStyles.forEach((element: HTMLElement) => {
            element.removeAttribute('ng-transition');
          });
    
          fromEvent(window, 'load').subscribe(() => {
            transitionStyles.forEach((el: HTMLElement) => el.remove());
    
            clientRoot.style.display = 'block';
            serverRoot.remove();
          });
        }
      };
    }
    
  23. hiepxanh commented on Mar 29, 2022

    @hiepxanh

    Good that really nice, i will try it

  24. rezonant commented on Apr 20, 2022

    @rezonant

    It's unclear how this is related to Angular versions, it is illegal to call getComputedStyle() with this other than window...

    > window.getComputedStyle(document.body)
    (No error)
    > window.getComputedStyle.apply({}, [document.body])
    Uncaught TypeError: Illegal invocation
    

    Perhaps this code path wasn't being hit at all before?

    In any case, I hope the PR can be merged soon. In the mean time, it is pretty easy to apply the fix and build the package yourself (just edit lib/package.json for your package name, run npm run build, and publish the dist folder). I've done so on @rezonant/preboot@8.0.0, feel free to use that if you wish.

  25. added a commit that references this issue on Apr 20, 2022
  26. added a commit that references this issue on May 6, 2022
    75563b6
  27. hiepxanh commented on May 6, 2022

    @hiepxanh

    @pavelrazuvalau your work is great, I used in my production build and it very smoooooooooooooooooooooooooooooooth

  28. lares83 commented on May 12, 2022

    @lares83

    any news about this issue?

  29. HamzaMoiyadi commented on Sep 6, 2022

    @HamzaMoiyadi

    I removed preboot from my project as I used it only for fixing page flickering. Seems it doesn't actively maintained and instead of applying workarounds I just implemented my own solution for showing overlay. The idea is pretty simple:

    app.module.ts

    providers: [
        {
          provide: APP_INITIALIZER,
          useFactory: fixPageFlickering,
          deps: [PLATFORM_ID],
        },
      ],
    
    export function fixPageFlickering(platformId: string): () => void {
      return () => {
        if (isPlatformBrowser(platformId)) {
          const transitionStyles = Array.from(document.querySelectorAll('style[ng-transition]'));
    
          const serverRoot = document.body.querySelector('app-root') as HTMLElement;
          const clientRoot = serverRoot.cloneNode() as HTMLElement;
    
          serverRoot.setAttribute('ng-non-bindable', '');
          clientRoot.style.display = 'none';
    
          document.body.insertBefore(clientRoot, serverRoot);
    
          transitionStyles.forEach((element: HTMLElement) => {
            element.removeAttribute('ng-transition');
          });
    
          fromEvent(window, 'load').subscribe(() => {
            transitionStyles.forEach((el: HTMLElement) => el.remove());
    
            clientRoot.style.display = 'block';
            serverRoot.remove();
          });
        }
      };
    }
    

    Can you explain the logic behind this? I have tried integrating the same, however post-deployment it fails to work. It works on local serving however.

  30. hiepxanh commented on Sep 7, 2022

    @hiepxanh

    it basicly do the same as preboot do:

    • render html with no js
    • angular jump in, remove previous html,
    • after some milisecond, rerender the html, and replace it => this cause flick
      The solution:
    • render html with no js
    • angular jump in, rerender the html
    • after some milisecond, rerender the html, and replace it => this cause flick
      ===> so we not remove it too soon, we just keep it there until angular ready

    tested on https://awread.vn using angular 14

  31. HamzaMoiyadi commented on Sep 15, 2022

    @HamzaMoiyadi

    Beautiful
    Thanks @hiepxanh !

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions