Angular 7 的生产构建,其中呈现 React 组件

Production build of Angular 7 with React component rendered within

我正在将现有的 Angular 应用程序逐个迁移到 React。查看了许多选项,包括 single-spa 和 nx,但它们不可行,因为现有的应用程序是一堆可怕的脚本注入疯狂。我选择了 Zacky Pickholz 所示的半手动选项:

https://medium.com/@zacky_14189/embedding-react-components-in-angular-the-easy-way-60f796b68aef

该项目成功地在 Angular 7 应用程序中渲染了一个 React 组件(耶!)。开发构建工作正常,但是生产构建在 tsx 包装器中抛出。

ERROR in ./src/app/components/my-wrapper-rct/my-wrapper-rct.tsx
Module parse failed: Unexpected character '@' (21:2)
You may need an appropriate loader to handle this file type.
|   const containerElementName = 'myWrapperRct';
|
|   @Component({
|     selector: 'my-wrapper-rct',
|     template: `<span #${containerElementName}></span>`,

包装器类似于 Zacky 存储库中的示例:
https://github.com/zackypick/react-in-angular

看起来生产转译器忽略了 tsx 包装器,所以当 JS 遇到 @Component 它不知道如何处理它。奇怪的是,这些包似乎是在此错误之前转换和生成的。希望有人对生产构建错误有所了解。

包装器代码:

import {
  AfterViewInit,
  Component,
  ElementRef,
  EventEmitter,
  Input,
  OnChanges,
  OnDestroy,
  Output,
  SimpleChanges,
  ViewChild,
  ViewEncapsulation
} from '@angular/core';
import { MyReactComponent } from 'src/components/my-react-component/MyReactComponent';
import * as React from 'react';

import * as ReactDOM from 'react-dom';

const containerElementName = 'myReactComponentContainer';

@Component({
  selector: 'app-my-component',
  template: `<span #${containerElementName}></span>`,
  styleUrls: ['./MyReactComponent.scss'],
  encapsulation: ViewEncapsulation.None,
})
export class MyComponentWrapperComponent implements OnChanges, OnDestroy, AfterViewInit {
  @ViewChild(containerElementName, {static: false}) containerRef: ElementRef;

  @Input() public counter = 10;
  @Output() public componentClick = new EventEmitter<void>();

  constructor() {
    this.handleDivClicked = this.handleDivClicked.bind(this);
  }

  public handleDivClicked() {
    if (this.componentClick) {
      this.componentClick.emit();
      this.render();
    }
  }

  ngOnChanges(changes: SimpleChanges): void {
    this.render();
  }

  ngAfterViewInit() {
    this.render();
  }

  ngOnDestroy() {
    ReactDOM.unmountComponentAtNode(this.containerRef.nativeElement);
  }

  private render() {
    const {counter} = this;

    ReactDOM.render(<div className={'i-am-classy'}>
      <MyReactComponent counter={counter} onClick={this.handleDivClicked}/>
    </div>, this.containerRef.nativeElement);
  }
}

搜索了天涯海角,没有发现任何人面临完全相同的错误。这个报告的问题让我找到了一些路径:

https://github.com/angular/angular-cli/issues/9244

经过一些实验,我需要将 aotbuildOptimizer 设置为 false。他们无法处理这种情况。

构建大小差异很小:8.3MB 对 8.4MB。由于目标是尽快放弃 Angular,所以我可以接受这种小幅增加。

React 在编译 tsx 后不会自动导入,因此 React 不会在生产构建(aot 或 buildoptimizer)中导入。因此,建议将以下内容添加到使用 React 组件的模块的根目录中。在我的例子中,它是一个通过路由延迟加载的模块。

import React from 'react'; 
window.React = React;

这会将 React 添加到您的全局命名空间,并使其在您的组件中可访问。