react-in-angular icon indicating copy to clipboard operation
react-in-angular copied to clipboard

Building with AOT breaks

Open mkeith121 opened this issue 5 years ago • 7 comments

Hi there. I was wondering if you had any input or suggestions when trying to run ng serve --prod. At present, this breaks with the current implementation. I was attempting to use your solution (something similar) for my project, but am running up against this [probably] AOT issue.

Any help would be greatly appreciated.

The simple repro is to try to run ng serve --prod in this project.

Thank you

mkeith121 avatar Nov 04 '20 15:11 mkeith121

@zackypick Even I am facing same issue when trying to run the app in prod mode. Getting Error as follows:

ERROR ReferenceError: React is not defined render http://localhost:4300/main.a3a651f148906b293118.js:1 ngOnChanges http://localhost:4300/main.a3a651f148906b293118.js:1 checkAndUpdateNode http://localhost:4300/main.a3a651f148906b293118.js:1 checkAndUpdateNode http://localhost:4300/main.a3a651f148906b293118.js:1 checkAndUpdateNode http://localhost:4300/main.a3a651f148906b293118.js:1 prodCheckAndUpdateNode http://localhost:4300/main.a3a651f148906b293118.js:1 View_AppComponent_0 http://localhost:4300/main.a3a651f148906b293118.js:1 updateDirectives http://localhost:4300/main.a3a651f148906b293118.js:1 checkAndUpdateView http://localhost:4300/main.a3a651f148906b293118.js:1 callViewAction http://localhost:4300/main.a3a651f148906b293118.js:1 execComponentViewsAction http://localhost:4300/main.a3a651f148906b293118.js:1 checkAndUpdateView http://localhost:4300/main.a3a651f148906b293118.js:1 detectChanges http://localhost:4300/main.a3a651f148906b293118.js:1 main.a3a651f148906b293118.js:1:353090

@mkeith121 @zackypick Any help on this? Please let me know how to fix this.

nethravikram avatar Nov 12 '20 14:11 nethravikram

@nethravikram @zackypick I found a solution in our project and I'd be happy to create a PR with those updates.

The solution I found was to dynamically import React at the point at which it's used. So instead of importing React at the top like: import { React } from 'react';

You would use the module import in the render function like so:

import(react).then(({React}) => {
   // Do something with the React object
})

I will try to make a PR today with my proposed changes. @nethravikram, let me know if you have any questions about this.

Here is a quick and dirty rewrite of the original render function with changes:

private render() {
    const {counter} = this;
    const reactImport = import('react').then((React) => React);
    const reactDomImport = import('react-dom').then((ReactDOM) => ReactDOM);

    Promise.all([reactImport, reactDomImport]).then(
      ([React, ReactDOM]) => {
          ReactDOM.render(<div className={'i-am-classy'}>
          <MyReactComponent counter={counter} onClick={this.handleDivClicked}/>
         </div>, this.containerRef.nativeElement);
    })
  }

I didn't test the above yet, just trying to be helpful until I have time to push a PR. This approach does work for me on Angular 9 prod builds (AOT, Ivy, etc).

mkeith121 avatar Nov 12 '20 15:11 mkeith121

@mkeith121 I am getting the compiler issue with above code.

src/components/my-react-component/MyReactComponentWrapper.tsx:69:20 - error TS2339: Property 'render' does not exist on type 'typeof React'.

69           ReactDOM.render(<div className={'i-am-classy'}>
                      ~~~~~~

Thanks!

nethravikram avatar Nov 12 '20 15:11 nethravikram

@nethravikram I updated my original comment to fix the issue. The order of the Promises in the invocation were wrong, so ReactDOM was a variable representing React. If you update your code with what I've corrected it to, it should work.

It wasn't intended to be used as a directy copy/paste, but I'm glad it looks like it should work.

mkeith121 avatar Nov 12 '20 15:11 mkeith121

@mkeith121 This solution works. Thank you so much for the help!!

nethravikram avatar Nov 12 '20 15:11 nethravikram

@nethravikram @zackypick I found a solution in our project and I'd be happy to create a PR with those updates.

The solution I found was to dynamically import React at the point at which it's used. So instead of importing React at the top like: import { React } from 'react';

You would use the module import in the render function like so:

import(react).then(({React}) => {
   // Do something with the React object
})

I will try to make a PR today with my proposed changes. @nethravikram, let me know if you have any questions about this.

Here is a quick and dirty rewrite of the original render function with changes:

private render() {
    const {counter} = this;
    const reactImport = import('react').then((React) => React);
    const reactDomImport = import('react-dom').then((ReactDOM) => ReactDOM);

    Promise.all([reactImport, reactDomImport]).then(
      ([React, ReactDOM]) => {
          ReactDOM.render(<div className={'i-am-classy'}>
          <MyReactComponent counter={counter} onClick={this.handleDivClicked}/>
         </div>, this.containerRef.nativeElement);
    })
  }

I didn't test the above yet, just trying to be helpful until I have time to push a PR. This approach does work for me on Angular 9 prod builds (AOT, Ivy, etc).

It worked with ng build --prod but still not working with server-side rendering, even though I checked isPlatformBrowser before rendering.

PuriaRad avatar Jan 03 '21 12:01 PuriaRad

@nethravikram @zackypick I found a solution in our project and I'd be happy to create a PR with those updates.

The solution I found was to dynamically import React at the point at which it's used. So instead of importing React at the top like: import { React } from 'react';

You would use the module import in the render function like so:

import(react).then(({React}) => {
   // Do something with the React object
})

I will try to make a PR today with my proposed changes. @nethravikram, let me know if you have any questions about this.

Here is a quick and dirty rewrite of the original render function with changes:

private render() {
    const {counter} = this;
    const reactImport = import('react').then((React) => React);
    const reactDomImport = import('react-dom').then((ReactDOM) => ReactDOM);

    Promise.all([reactImport, reactDomImport]).then(
      ([React, ReactDOM]) => {
          ReactDOM.render(<div className={'i-am-classy'}>
          <MyReactComponent counter={counter} onClick={this.handleDivClicked}/>
         </div>, this.containerRef.nativeElement);
    })
  }

I didn't test the above yet, just trying to be helpful until I have time to push a PR. This approach does work for me on Angular 9 prod builds (AOT, Ivy, etc).

It works, thanks for sharing it!

lucasfsousa avatar Feb 16 '21 19:02 lucasfsousa