Kompilasi Angular 5 AOT gagal

Saya memiliki aplikasi Angular 5 yang berfungsi tanpa masalah ketika saya menjalankannya dalam mode uji, yaitu ketika saya menjalankan aplikasi secara lokal menggunakan perintah ng serve. Namun, ketika saya menerapkan aplikasi dalam mode produksi, yaitu melalui perintah ng build --prod, aplikasi mengekspor tanpa masalah, tetapi ketika saya menggunakan aplikasi di lingkungan produktif, masalah ini muncul: (ini adalah gambar dari konsol browser dari google dan safari)

Konsol Google Chrome:

masukkan deskripsi gambar di sini

Konsol Safari:

masukkan deskripsi gambar di sini

Namun, jika sekarang saya mengekspor aplikasi menggunakan perintah berikut ng build --prod --aot false, aplikasi akan berfungsi tanpa masalah.

Selanjutnya saya akan menunjukkan komponen yang terlibat dalam kesalahan yang dikomentari:

pengguna-online-quote.component.html

<app-navbar [loggedIn]=loggedIn></app-navbar>
<app-dynamic-form [answers$]="answers$"></app-dynamic-form>

pengguna-online-quote.component.ts

import { Component, OnInit } from '@angular/core';
import { DynamicFormService } from '../_services/dynamic-form.service';
import { RadioQuestion }  from '../shared/_shared/answer-radio';
import { Observable } from "rxjs/Rx";
import { AuthService } from '../_services/auth.service';
import { Router, ActivatedRoute, Params } from '@angular/router';

@Component({
  selector: 'app-user-online-quote',
  templateUrl: './user-online-quote.component.html',
  styleUrls: ['./user-online-quote.component.css'],
  providers:  [DynamicFormService, AuthService]
})
export class UserOnlineQuoteComponent implements OnInit {
  totalPage:number;
  actualPage:number;
  percentageCompletion:number;
  currentQuestion:string;
  selectedOption:string;
  imageSource:string;
  loggedIn:boolean;
  formId:string;
  //public answers: any[];

  //Signo $ porque es un observable
  public answers$: Observable<any[]>;

  constructor(private service: DynamicFormService, private authService: AuthService,
    private activatedRoute: ActivatedRoute) {

   }

  ngOnInit() {
    this.loggedIn=this.authService.isLoggedIn();
    this.activatedRoute.queryParams.subscribe((params: Params) => {
      this.formId=params['form'];
      this.answers$=this.service.getAnswers(this.formId);
    });
    //this.answers=this.service.getAnswers("CAR00PR");
    this.totalPage=4;
    this.actualPage=1;
    this.calculateAdvancePercentage();
    this.currentQuestion="¿Pregunta de prueba?";
  }

  calculateAdvancePercentage(){
    this.percentageCompletion=(this.actualPage/this.totalPage)*100;
  }

  next(){
    this.actualPage=(this.actualPage+1);
    this.calculateAdvancePercentage();
  }

  back(){
    this.actualPage=(this.actualPage-1);
    this.calculateAdvancePercentage();
  }

}

bentuk-dinamis.component.html

<div class="space"></div>
<ngx-loading [show]="loading" [config]="{ backdropBorderRadius: '0px', fullScreenBackdrop:true }"></ngx-loading>
<div *ngIf="submitted===false" class="container">
  <div class="row">
  <div class="col-lg-2">
    <div class="mx-2"></div>
  </div>
  <div class="col-lg-8">
    <div>
      <p>{{currentQuestion.description}}</p>
    </div>
    <div class="progress">
      <div class="progress-bar" role="progressbar" [style.width]="percentageCompletion + '%'" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100"></div>
    </div>
      <hr> 
      <div>
        <form [formGroup]="form">
          <div *ngFor="let answer of answers$ | async">
            <div [ngSwitch]="answer.controlType">
              <div *ngSwitchCase="'radio'">
                <div class="radios checkbox-group">
                  <div [hidden]="!(currentQuestion.id===answer.parent)" class="col-lg-12">
                    <input [formControlName]="answer.controlName" [id]="answer.id" type="radio" [value]="answer.label" (click)="next(null,answer.child)">
                      <label [for]="answer.id" class="button-label">
                        {{answer.label}}  
                      </label>
                  </div>
                </div>
              </div>
              <div *ngSwitchCase="'radio_textbox'">
                <div class="radios checkbox-group">
                  <div [hidden]="!(currentQuestion.id===answer.parent)" class="col-lg-12">
                    <input [formControlName]="answer.controlName" [id]="answer.id" type="radio" (click)="showTextbox ? showTextbox = false : showTextbox = true;">
                      <label [for]="answer.id" class="button-label">
                        {{answer.label}}  
                      </label>
                  </div>
                </div>
                  <div [hidden]="!(currentQuestion.id===answer.parent)" class="input-group mb-3 col-lg-12">
                    <input [hidden]="!showTextbox" type="text" class="form-control" [placeholder]="answer.placeholder" [formControlName]="answer.controlName" [id]="answer.id">
                      <div class="input-group-append">
                        <button [hidden]="!showTextbox" class="btn btn-outline-secondary" type="button" (click)="next(null,answer.child)">Siguiente</button>
                      </div>
                  </div>
              </div>
              <div *ngSwitchCase="'file'">
                <div [hidden]="!(currentQuestion.id===answer.parent)" class="col-lg-12">
                    <div class="form-group">
                        <label [for]="answer.id">{{answer.label}}</label>
                        <div class="custom-file">
                            <input [formControlName]="answer.controlName" type="file" class="custom-file-input" [id]="answer.id" lang="es" (change)="onFileChange($event)" #fileInput>
                            <label class="custom-file-label" for="customFileLang">{{fileName}}</label>
                        </div>
                        <div *ngIf="answer.required===true">
                          <small *ngIf="form.get(answer.controlName).status=='INVALID'" class="form-text text-muted-error">Debes tener una imagen de referencia para poder continuar</small>
                        </div>
                    </div>
                  <div class="my-4"></div>
                </div>
              </div>    
              <div *ngSwitchCase="'file_next'">
                <div [hidden]="!(currentQuestion.id===answer.parent)" class="col-lg-12">
                    <div class="form-group">
                        <label [for]="answer.id">{{answer.label}}</label>
                        <div class="custom-file">
                            <input [formControlName]="answer.controlName" type="file" class="custom-file-input" [id]="answer.id" lang="es" (change)="onFileChange($event)" #fileInput>
                            <label class="custom-file-label" for="customFileLang">{{fileName}}</label>
                        </div>
                        <div *ngIf="answer.required===true">
                          <small *ngIf="form.get(answer.controlName).status=='INVALID'" class="form-text text-muted-error">Debes tener una imagen de referencia para poder continuar</small>
                        </div>
                    </div>
                    <div class="my-4"></div>
                    <div class="text-center">
                      <button
                        (click)='next(answer.validations,answer.next)'
                        class="btn btn-outline-secondary">
                        Siguiente
                      </button>
                    </div>
                </div>
              </div>
              <div *ngSwitchCase="'textbox'" [hidden]="!(currentQuestion.id===answer.parent)" class="col-md-6 mb-3">
                <label [for]="answer.id">{{answer.label}}</label>
                <input [formControlName]="answer.controlName" type="text" class="form-control" [id]="answer.id" [placeholder]="answer.placeholder">
                <div *ngIf="answer.required===true">
                  <small *ngIf="form.get(answer.controlName).status=='INVALID'" class="form-text text-muted-error">Este campo es obligatorio</small>
                </div>
              </div>
              <div *ngSwitchCase="'textbox_next'" [hidden]="!(currentQuestion.id===answer.parent)">
                <div class="col-md-6 mb-3">
                  <label [for]="answer.id">{{answer.label}}</label>
                  <input [formControlName]="answer.controlName" type="text" class="form-control" [id]="answer.id" [placeholder]="answer.placeholder">
                  <div *ngIf="answer.required===true">
                    <small *ngIf="form.get(answer.controlName).status=='INVALID'" class="form-text text-muted-error">Este campo es obligatorio</small>
                  </div>
                </div>
                <div class="my-4"></div>
                <div class="text-center">
                  <button
                    (click)='next(answer.validations,answer.next)'
                    class="btn btn-outline-secondary">
                    Siguiente
                  </button>
                </div>
              </div>
              <div *ngSwitchCase="'textarea'">
                <div class="form-group col-lg-12" [hidden]="!(currentQuestion.id===answer.parent)">
                  <label for="description">{{answer.label}}</label>
                  <textarea [formControlName]="answer.controlName" class="form-control" id="description" rows="3"></textarea>
                </div>
                <div class="my-4"></div>
              </div>
            </div>
          </div>

        </form>

      </div>

      <div class="my-4"></div>
      <div class="text-center">
        <button 
          (click)='back()' 
          class="btn btn btn-outline-secondary">
            Atrás
        </button>
        <button 
          [hidden]="currentQuestion.last==true"
          (click)='cancel()' 
          class="btn btn btn-outline-secondary">
            Cancelar
        </button>
        <button 
          [hidden]="currentQuestion.last==false"
          [disabled]="form.invalid"
          type="submit"
          class="btn btn-outline-success"
          (click)="onSubmit()">
            Enviar Solicitud
        </button>
      </div>
  </div>
  <div class="col-lg-2">
      <div class="mx-2"></div>
  </div>
</div>
</div>
<div *ngIf="submitted==true" class="container">
  <div class="space">
      <div class="container">
          <div class="row">
              <div class="col-lg-1"></div>
              <div class="col-lg-10 justify">
                <p>Tu solicitud se ha enviado correctamente, debes esperar un máximo de 2 días para que el experto elabore una cotización
                  de acuerdo a tus requerimientos. 
                </p>
                <div class="d-flex justify-content-center">
                  <a [routerLink]="['/dashboard_usuario/negociaciones/en_proceso']">Ver negociación</a>
                </div>
              </div>
              <div class="col-lg-1"></div>
          </div>
      </div>
  </div>
</div>

bentuk-dinamis.component.ts

import { Component, Input, OnInit, ChangeDetectorRef }  from '@angular/core';
import { FormGroup }                 from '@angular/forms';
import { AnswerBase }              from '../shared/_shared/answer-base';
import { AnswerControlService }    from '../_services/answer-control.service';
import { DynamicFormService } from '../_services/dynamic-form.service';
import { Question } from '../_models/question';
import { Observable } from "rxjs/Rx"
import { Router, ActivatedRoute, Params } from '@angular/router';
import { QuoteDto } from "../_dtos/quoteDto";
import { HttpClient, HttpResponse } from '@angular/common/http';
import {Location} from '@angular/common';


@Component({
  selector: 'app-dynamic-form',
  templateUrl: './dynamic-form.component.html',
  styleUrls: ['./dynamic-form.component.css'],
  providers: [ AnswerControlService ]
})
export class DynamicFormComponent implements OnInit {
  @Input() answers$: Observable<AnswerBase<any>[]>;
  form: FormGroup;
  payLoad = '';
  questionsList : Map<string, Question>;
  totalPage:number;
  actualPage:number;
  percentageCompletion:number;
  currentQuestion:Question;
  previousQuestion:Question;
  backwardQuestions:Array<string>;
  loading:boolean;
  fileName:string;
  photo:File;
  image:any;
  nextDisable:boolean;
  userId:string;
  providerId:string;
  formId:string;
  submitted:boolean;


  constructor(private qcs: AnswerControlService, 
    private dynamicFormervice: DynamicFormService,
    private activatedRoute: ActivatedRoute, 
    private location:Location,
    private router:Router) {  }

  ngOnInit() {
    this.loading=true;
    this.submitted=false;
    this.fileName="Seleccionar un archivo";
    this.nextDisable=true;
    this.backwardQuestions= new Array();
    this.currentQuestion=new Question('','',false);
    this.form= new FormGroup({});
    this.questionsList= new Map<string, Question>();
    this.activatedRoute.queryParams.subscribe((params: Params) => {
      this.userId=params['user'];
      this.providerId=params['provider'];
      this.formId=params['form'];
        this.dynamicFormervice.getTotalPages(this.formId).subscribe(total => {
          this.totalPage=total;
          this.actualPage=1;
          this.calculateAdvancePercentage();
            this.dynamicFormervice.getQuestions(this.formId).subscribe(items =>{
              items.map(item =>{
                this.questionsList.set(item.id,item);
              });
            this.dynamicFormervice.getInitialQuestionId(this.formId).subscribe(id =>{
              this.currentQuestion=this.questionsList.get(id);
              this.previousQuestion=this.currentQuestion;
              this.loading=false;
            });
          });
        });
    });
    this.answers$.subscribe(a=>{
      this.form = this.qcs.toFormGroup(a);
    });
  }

  onSubmit() {
    this.loading=true;
    this.payLoad=JSON.stringify(this.form.value);
    let quote:QuoteDto = new QuoteDto();
    quote.requirements= this.payLoad;
    this.dynamicFormervice.createQuote(quote,this.userId,this.providerId).subscribe((resp:HttpResponse<String>)=>{
      this.dynamicFormervice.uploadQuotationImage(this.photo,resp.body.substring(resp.body.indexOf(':')+1,resp.body.lastIndexOf('"'))).
      subscribe(resp => {
        this.submitted=true;
        this.loading=false;
      });
    });
  }

  calculateAdvancePercentage(){
    this.percentageCompletion=(this.actualPage/this.totalPage)*100;
  }

  next(validatios:string, childId:string){
    if(validatios!=null){
      let controlRestrictions:string[]=validatios.split(',');
      let validCount=0;
      for (let cr of controlRestrictions) {
        if(this.form.get(cr).status=='VALID'){
          validCount++;
        }
     }
     if(validCount==controlRestrictions.length){
       this.nextDisable=false;
       this.backwardQuestions.push(this.currentQuestion.id);
       this.currentQuestion=this.questionsList.get(childId);
       if(this.currentQuestion.last==true){
        this.percentageCompletion=100;
       }else{
        this.actualPage=(this.actualPage+1);
        this.calculateAdvancePercentage();
       }
     }
    }else{
      this.backwardQuestions.push(this.currentQuestion.id);
      this.currentQuestion=this.questionsList.get(childId);
      if(this.currentQuestion.last==true){
        this.percentageCompletion=100;
      }else{
       this.actualPage=(this.actualPage+1);
       this.calculateAdvancePercentage();
      }
    }
  }

  back(){
    if(this.actualPage==1){
      this.location.back();
    }
    else{
      let questionId:string = this.backwardQuestions.pop();
      this.currentQuestion=this.questionsList.get(questionId);
      this.actualPage=(this.actualPage-1);
      this.calculateAdvancePercentage();
    }
  }

  cancel(){
    this.navegateToProfessionForm();
  }

  navegateToProfessionForm(){
    switch (this.formId) {
      case 'ALB00PR':
        this.router.navigate(['/expertos'], { queryParams: { profession: '1' } });
        break;
      case 'CAR00PR':
        this.router.navigate(['/expertos'], { queryParams: { profession: '2' } });
        break;
      case 'DIS00PR':
        this.router.navigate(['/expertos'], { queryParams: { profession: '3' } });
        break;
      case 'ELE00PR':
        this.router.navigate(['/expertos'], { queryParams: { profession: '4' } });
        break;  
      case 'CLI00PR':
        this.router.navigate(['/expertos'], { queryParams: { profession: '5' } });
        break;
      case 'FUM00PR':
        this.router.navigate(['/expertos'], { queryParams: { profession: '6' } });
        break;
      case 'MAQ00PR':
        this.router.navigate(['/expertos'], { queryParams: { profession: '7' } });
        break;
      case 'PIN00PR':
        this.router.navigate(['/expertos'], { queryParams: { profession: '8' } });
        break;
      case 'PLO00PR':
        this.router.navigate(['/expertos'], { queryParams: { profession: '9' } });
        break;
      case 'JAR00PR':
        this.router.navigate(['/expertos'], { queryParams: { profession: '10' } });
        break;
      case 'SOL00PR':
        this.router.navigate(['/expertos'], { queryParams: { profession: '11' } });
        break;
      case 'TAP00PR':
        this.router.navigate(['/expertos'], { queryParams: { profession: '12' } });
        break;
      default:
  }
  }

  onFileChange(event) {
    this.loading=true;
    if(event.target.files && event.target.files.length > 0) {
    let image:File = event.target.files[0];
    let reader=new FileReader();
    reader.readAsDataURL(image);
      reader.onload = (event:any) => {
        let base64=event.target.result
        let filename=image.name;
        let type=image.type;
        this.reduceQuality(base64,filename,type,(file)=>{
          this.photo = file;
          this.fileName=this.photo.name;
          this.loading=false;
        });
      }
    }
    else{
      this.loading=false;
    }
  }

  getBase64(file,callback) {
    var reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = function() {
      let result = reader.result;
      callback(result);
    };
    reader.onerror = function (error) {
      console.log('Error: ', error);
    };
 }

  reduceQuality(base64Image,filename,extension,callback){
    let canvas = document.createElement('canvas');
    let ctx=canvas.getContext("2d");
    var image = new Image();
   image.onload = ()=>{
    var width = image.width,
            height = image.height,
        canvas = document.createElement('canvas'),
            ctx = canvas.getContext("2d");

    // set proper canvas dimensions before transform & export
        canvas.width = width;
      canvas.height = height;

        // draw image
    ctx.drawImage(image, 0, 0);

    let url:string = '';
    if(extension=='image/jpeg'){
      url = canvas.toDataURL('image/jpeg', 0.1);
    }
    else{
      url = canvas.toDataURL();
    }
    let file:File=this.dataURLtoFile(url,filename);
    callback(file);
  };
    image.src = base64Image;  
  }
  dataURLtoFile(dataurl, filename) {
    let arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
        bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
    while(n--){
        u8arr[n] = bstr.charCodeAt(n);
    }
    return new File([u8arr], filename, {type:mime});
}

}

package.json

{
  "name": "front-end",
  "version": "0.0.0",
  "license": "MIT",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build --prod",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "^5.2.0",
    "@angular/common": "^5.2.0",
    "@angular/compiler": "^5.2.0",
    "@angular/core": "^5.2.0",
    "@angular/forms": "^5.2.0",
    "@angular/http": "^5.2.0",
    "@angular/platform-browser": "^5.2.0",
    "@angular/platform-browser-dynamic": "^5.2.0",
    "@angular/router": "^5.2.0",
    "angular2-text-mask": "^8.0.4",
    "angularfire2": "^5.0.0-rc.6",
    "bootstrap": "^4.1.0",
    "core-js": "^2.4.1",
    "firebase": "^4.12.1",
    "jquery": "^3.3.1",
    "moment": "^2.20.1",
    "mydatepicker": "^2.6.3",
    "ngx-loading": "^1.0.14",
    "offcanvas-bootstrap": "^2.5.2",
    "popper.js": "^1.14.3",
    "rxjs": "^5.5.6",
    "zone.js": "0.10.3"
  },
  "devDependencies": {
    "@angular/cli": "1.6.5",
    "@angular/compiler-cli": "^5.2.0",
    "@angular/language-service": "^5.2.0",
    "@types/jasmine": "~2.8.3",
    "@types/jasminewd2": "~2.0.2",
    "@types/node": "~6.0.60",
    "codelyzer": "^4.0.1",
    "jasmine-core": "~2.8.0",
    "jasmine-spec-reporter": "~4.2.1",
    "karma": "~2.0.0",
    "karma-chrome-launcher": "~2.2.0",
    "karma-cli": "~1.0.1",
    "karma-coverage-istanbul-reporter": "^1.2.1",
    "karma-jasmine": "~1.1.0",
    "karma-jasmine-html-reporter": "^0.2.2",
    "protractor": "~5.1.2",
    "ts-node": "~4.1.0",
    "tslint": "~5.9.1",
    "typescript": "~2.5.3"
  }
}

angular-cli.json

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "project": {
    "name": "front-end"
  },
  "apps": [
    {
      "root": "src",
      "outDir": "dist",
      "assets": [
        "assets",
        "favicon.ico"
      ],
      "index": "index.html",
      "main": "main.ts",
      "polyfills": "polyfills.ts",
      "test": "test.ts",
      "tsconfig": "tsconfig.app.json",
      "testTsconfig": "tsconfig.spec.json",
      "prefix": "app",
      "styles": [
        "styles-app-loading.scss",
        "styles.css",
        "../node_modules/font-awesome/css/font-awesome.css"
      ],
      "scripts": ["../node_modules/jquery/dist/jquery.slim.min.js",
        "../node_modules/popper.js/dist/umd/popper.min.js",
        "../node_modules/bootstrap/dist/js/bootstrap.min.js",
        "../node_modules/offcanvas-bootstrap/dist/js/bootstrap.offcanvas.min.js"],
      "environmentSource": "environments/environment.ts",
      "environments": {
        "dev": "environments/environment.ts",
        "prod": "environments/environment.prod.ts"
      }
    }
  ],
  "e2e": {
    "protractor": {
      "config": "./protractor.conf.js"
    }
  },
  "lint": [
    {
      "project": "src/tsconfig.app.json",
      "exclude": "**/node_modules/**"
    },
    {
      "project": "src/tsconfig.spec.json",
      "exclude": "**/node_modules/**"
    },
    {
      "project": "e2e/tsconfig.e2e.json",
      "exclude": "**/node_modules/**"
    }
  ],
  "test": {
    "karma": {
      "config": "./karma.conf.js"
    }
  },
  "defaults": {
    "styleExt": "css",
    "component": {}
  }

}

Pertanyaannya mengapa aplikasi saya hanya berfungsi dengan baik ketika saya tidak menggunakan fitur AOT? Mengapa ini sangat aneh?

Apa yang harus saya lakukan untuk mengatasi masalah ini dan saya dapat menggunakan fitur AOT, karena saya tidak ingin aplikasi saya mendapat penalti kinerja? Ada ide?

Penting: Sebelum memisahkan aplikasi berdasarkan modul, aplikasi bekerja dengan baik dalam produksi. Masalah yang dijelaskan muncul setelah memisahkan aplikasi saya berdasarkan modul, namun komponen yang bermasalah ini adalah bagian dari modul utama.


person AlejoDev    schedule 18.05.2020    source sumber
comment
Seperti apa angular.json Anda dan apakah ada properti Input loggedIn di komponen app-navbar?   -  person Gökhan Kurt    schedule 23.05.2020
comment
@GökhanKurt Saya telah memperbarui pertanyaannya   -  person AlejoDev    schedule 23.05.2020
comment
Bisakah Anda mereproduksi masalah ini di repo github dengan kode minimal?   -  person yurzui    schedule 23.05.2020
comment
Bisakah Anda menjelaskan bagaimana Anda memisahkan aplikasi berdasarkan modul? mungkin beberapa contoh modul/rute dapat memberikan gambaran yang lebih jelas untuk di-debug   -  person cerkiner    schedule 23.05.2020
comment
Untuk mendapatkan pesan kesalahan yang lebih detail, silakan jalankan ng serve --aot   -  person brandt.codes    schedule 28.05.2020
comment
apakah kamu menggunakan kendo ui?   -  person Aakash Garg    schedule 29.05.2020
comment
Versi Angula CLI Anda aneh, mungkin Anda perlu memperbarui @angula/cli?   -  person DMITRYTISHKIN    schedule 30.05.2020


Jawaban (2)


Coba tambahkan tanda itu ke build ng Anda untuk melihat apakah itu membantu. (--build-optimizer=salah)

person Dicekey    schedule 23.05.2020