错误:未找到“[object Object]”的 NgModule 元数据

fro*_*tme 5 angular-cli angular-universal angular

我正在尝试将我的 angular 6 应用程序转换为服务器端渲染(用于 SEO 目的),并且一切似乎都编译无误。除了当我实际导航到本地主机时,我得到了完整的错误

Error: No NgModule metadata found for '[object Object]'.
at NgModuleResolver.resolve (/execroot/angular/packages/compiler/src/ng_module_resolver.ts:31:15)
at CompileMetadataResolver.getNgModuleMetadata (/execroot/angular/packages/compiler/src/metadata_resolver.ts:509:41)
at JitCompiler._loadModules (/execroot/angular/packages/compiler/src/jit/compiler.ts:127:49)
at JitCompiler._compileModuleAndComponents (/execroot/angular/packages/compiler/src/jit/compiler.ts:107:32)
at JitCompiler.compileModuleAsync (/execroot/angular/packages/compiler/src/jit/compiler.ts:61:33)
at CompilerImpl.compileModuleAsync (/execroot/angular/packages/platform-browser-dynamic/src/compiler_factory.ts:57:27)
at /execroot/nguniversal/modules/express-engine/src/main.ts:130:16
at new ZoneAwarePromise (/Users/melliotfrost/projects/myapp/node_modules/zone.js/dist/zone-node.js:891:29)
at getFactory (/execroot/nguniversal/modules/express-engine/src/main.ts:115:10)
at View.engine (/execroot/nguniversal/modules/express-engine/src/main.ts:92:7)
Run Code Online (Sandbox Code Playgroud)

我正在运行命令 npm run build:ssr && npm run serve:ssr

app.module.ts(主模块)

Error: No NgModule metadata found for '[object Object]'.
at NgModuleResolver.resolve (/execroot/angular/packages/compiler/src/ng_module_resolver.ts:31:15)
at CompileMetadataResolver.getNgModuleMetadata (/execroot/angular/packages/compiler/src/metadata_resolver.ts:509:41)
at JitCompiler._loadModules (/execroot/angular/packages/compiler/src/jit/compiler.ts:127:49)
at JitCompiler._compileModuleAndComponents (/execroot/angular/packages/compiler/src/jit/compiler.ts:107:32)
at JitCompiler.compileModuleAsync (/execroot/angular/packages/compiler/src/jit/compiler.ts:61:33)
at CompilerImpl.compileModuleAsync (/execroot/angular/packages/platform-browser-dynamic/src/compiler_factory.ts:57:27)
at /execroot/nguniversal/modules/express-engine/src/main.ts:130:16
at new ZoneAwarePromise (/Users/melliotfrost/projects/myapp/node_modules/zone.js/dist/zone-node.js:891:29)
at getFactory (/execroot/nguniversal/modules/express-engine/src/main.ts:115:10)
at View.engine (/execroot/nguniversal/modules/express-engine/src/main.ts:92:7)
Run Code Online (Sandbox Code Playgroud)

主文件

//import modules
import { BrowserModule } from '@angular/platform-browser';
import { NgModule, APP_INITIALIZER, PLATFORM_ID, APP_ID, Inject } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { ColorPickerModule } from 'ngx-color-picker';
import { SortablejsModule } from 'angular-sortablejs';
import { FroalaEditorModule, FroalaViewModule } from 'angular-froala-wysiwyg';
import { Ng2SearchPipeModule } from 'ng2-search-filter';
import { MomentModule } from 'angular2-moment';
import { UIView } from '@uirouter/angular'
import { FileUploadModule } from 'ng2-file-upload';
import { CustomFormsModule } from 'ng4-validators';
import { NgSelectModule } from '@ng-select/ng-select';
import { NgPipesModule } from 'angular-pipes';
import { NgxPaginationModule } from 'ngx-pagination';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { BusyModule } from 'angular2-busy';
import { CookieModule } from 'ngx-cookie';

//TODO will be fixed shortly
//import { TextareaAutosizeModule } from 'ngx-textarea-autosize';
import { Location, LocationStrategy, HashLocationStrategy, isPlatformBrowser } from '@angular/common';
import * as _ from 'lodash';

//pipes
import { AppPipes } from './pipes/pipes';
//Directives
import { AppDirectives } from './directives/directives';
//Components
import { AppComponents, ModalComponents } from './components/components';
import { AppComponent } from'./app.component';
//Services
import { AppResources } from './components/resources';
import { AppServices } from './services/services';
import { AppLoadService } from '../config/app.load.service';
//HTTP Interceptors
import { APIInterceptor } from './services/api.interceptor';
const interceptors = [
  { provide: HTTP_INTERCEPTORS, useClass: APIInterceptor, multi: true }
];

//States
import { AppRoutingModule } from './app-routing.module';

export function init_app(appLoadService: AppLoadService) {
  return () => appLoadService.load();
}

//Platform Info

const IMPORTS =  [
  BrowserModule.withServerTransition({ appId: 'myapp' }),
  FormsModule,
  BrowserAnimationsModule,
  HttpClientModule,
  NgbModule.forRoot(),
  ColorPickerModule,
  SortablejsModule.forRoot({ animation: 150 }),
  FroalaEditorModule.forRoot(),
  FroalaViewModule.forRoot(),
  Ng2SearchPipeModule,
  MomentModule,
  FileUploadModule,
  AppRoutingModule,
  CustomFormsModule,
  NgSelectModule,
  NgPipesModule,
  NgxPaginationModule,
  BusyModule,
  CookieModule.forRoot()
  //TextareaAutosizeModule
];


const DECLARATIONS = [
  AppPipes, 
  AppDirectives,
  AppComponents
];

const PROVIDERS = [
  AppResources,
  AppServices,
  interceptors,
  Location,
  AppLoadService,
  { provide: APP_INITIALIZER, useFactory: init_app, deps: [AppLoadService], multi: true },
];

@NgModule({
  declarations:  DECLARATIONS,
  imports: IMPORTS,
  providers: PROVIDERS,
  entryComponents: ModalComponents,
  bootstrap: [ AppComponent ],
})
export class AppModule { 
  constructor(
    @Inject(PLATFORM_ID) private platformId: Object,
    @Inject(APP_ID) private appId: string) {
    const platform = isPlatformBrowser(platformId) ?  'in the browser' : 'on the server';
    console.log(`Running ${platform} with appId=${appId}`);
  }
}
Run Code Online (Sandbox Code Playgroud)

tsconfig.app.json

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

if (environment.production) {
  enableProdMode();
}

platformBrowserDynamic().bootstrapModule(AppModule).catch(err => console.log(err));
Run Code Online (Sandbox Code Playgroud)

app.server.module.ts(服务器模块)

{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "outDir": "../out-tsc/app",
    "baseUrl": "./",
    "module": "es2015",
    "types": []
  },
  "exclude": [
    "test.ts",
    "**/*.spec.ts"
  ]
}
Run Code Online (Sandbox Code Playgroud)

服务器.main.ts

tsconfig.server.json

import { enableProdMode } from '@angular/core';
export { AppServerModule } from './app/app.server.module';

enableProdMode();
Run Code Online (Sandbox Code Playgroud)

server.ts(服务器)

webpackage.server.config.js(生成server.js的webpack配置)

{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "outDir": "../out-tsc/server",
    "baseUrl": "./",
    "module": "commonjs",
    "types": []
  },
  "exclude": [
    "test.ts",
    "**/*.spec.ts"
  ],
  "angularCompilerOptions": {
    "entryModule": "app/app.server.module#AppServerModule"
  }
}
Run Code Online (Sandbox Code Playgroud)

//******************** BEGING deps *******************//
import 'zone.js/dist/zone-node';
import 'reflect-metadata';
import express = require('express');
import path    = require('path');
import compression = require('compression');
import fs = require('fs');
import http = require('http');
import https = require('https');
import git = require('git-rev');
import request = require('request');
import fallback = require('express-history-api-fallback');
import bodyParser = require('body-parser');
import sslRedirect = require('heroku-ssl-redirect');
import { join } from 'path';
const ejs = require('ejs');

//******************** END deps *******************//
//

//******************** BEGING angular deps *******************//
 
import { enableProdMode } from '@angular/core';
import { ngExpressEngine } from '@nguniversal/express-engine';
import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';
//
//******************** END angular deps *******************//


//******************** BEGING constants *******************//
//
require('dotenv').config();
enableProdMode();
const app     = express();
const API_URL = {
  dev: 'https://dev-api.myapp.com',
  feature: 'https://localhost:1337',
  stage: 'https://test-api.myapp.com',
  demo: 'https://demo-api.myapp.com',
  prod: 'https://api.myapp.com'
};
const root = 'dist';
const DIST_FOLDER = join(process.cwd(), 'dist');

//******************** END constants *******************//
//
//****************** BEGIN ANGULAR UNIVERSAL CONFIG *****************//
const domino = require('domino');
const template = fs.readFileSync(path.join(root + '/browser', 'index.html')).toString();
const win = domino.createWindow(template);

global['window'] = win;
global['document'] = win.document;
global['DOMTokenList'] = win.DOMTokenList;
global['Node'] = win.Node;
global['Text'] = win.Text;
global['HTMLElement'] = win.HTMLElement;
global['navigator'] = win.navigator;
global['MutationObserver'] = getMockMutationObserver();

function getMockMutationObserver() {
  return class {
    observe(node, options) {
    }
    disconnect() {
    }
    takeRecords() {
      return [];
    }
  };
}
var { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main');

console.log(LAZY_MODULE_MAP);
console.log(AppServerModuleNgFactory);

//****************** END ANGULAR UNIVERSAL CONFIG *****************//

//******************** BEGING server configs *******************//
app.use(sslRedirect());
app.use(bodyParser.json())

//view enginer
app.engine('html', ngExpressEngine({
  bootstrap: AppServerModuleNgFactory,
  providers: [
    provideModuleMap(LAZY_MODULE_MAP)
  ]
}));
app.set('view engine', 'html');
app.set('views', join(DIST_FOLDER, 'browser'));

//******************** END server configs *******************//

//************* BEGIN ROUTES *****************/
//server initial page
//app.get('/', function(req, res){
  //res.sendFile(path.join(__dirname + '/dist/index.html'));
//});

app.get('/polyfills.bundle.js', (req, res) => {
  res.sendFile(path.join(__dirname + '/dist/polyfills.bundle.js'));
});

app.get('/styles.bundle.js', (req, res) => {
  res.sendFile(path.join(__dirname + '/dist/styles.bundle.js'));
});

app.get('/scripts.bundle.js', (req, res) => {
  res.sendFile(path.join(__dirname + '/dist/scripts.bundle.js'));
});

app.get('/vendor.bundle.js', (req, res) => {
  res.sendFile(path.join(__dirname + '/dist/vendor.bundle.js'));
});

app.get('/main.bundle.js', (req, res) => {
  res.sendFile(path.join(__dirname + '/dist/main.bundle.js'));
});

app.get('/inline.bundle.js', (req, res) => {
  res.sendFile(path.join(__dirname + '/dist/inline.bundle.js'));
});


//API routes
app.get('/api/envInfo', function(req, res){
  git.branch(function(branch){
    git.short(function(hash){
      res.json({
        env: process.env.APP_ENV || 'dev',
        hash: hash,
        branch: branch
      });
    });
  });
});

app.get('/api/badge/:id', function(req, res){
  var badgeUrl = API_URL[process.env.APP_ENV || 'dev'] + '/badge/' + req.params.id + '?withuser=true';

  request.get(badgeUrl, (err, response, body) => {
    ejs.renderFile('./views/badge.ejs', { cert: JSON.parse(body) }, (err, html) => {
      res.send(html);
    });
  });
});

app.get('/api/microcourse/:id', function(req, res){
  var microcourseUrl = API_URL[process.env.APP_ENV || 'dev'] + '/earnedMicrocourse/' + req.params.id;

  request.get(microcourseUrl, (err, response, body) => {
    ejs.renderFile('./views/badge.ejs', { cert: JSON.parse(body) }, (err, html) => {
      res.send(html);
    });
  });
});

app.get('/api/user/:id', function(req, res){
  var userUrl = API_URL[process.env.APP_ENV || 'dev'] + '/user/' + req.params.id;
  request.get(userUrl, (err, response, body) => {
    var user = JSON.parse(body);
    if(user.profileVisible){
      ejs.renderFile('./views/user.ejs', { user: JSON.parse(body) }, (err, html) => {
        res.send(html);
      });
    } else {
      res.redirect('/#/');
    }
  });
});

app.get('/api/badge/:id/share', function(req, res){
  var badgeUrl = API_URL[process.env.APP_ENV || 'dev'] + '/badge/' + req.params.id + '?withuser=true&hide=true';

  request.get(badgeUrl, (err, response, body) => {
    ejs.renderFile('./views/badge.ejs', { badge: JSON.parse(body) }, (err, html) => {
      res.send(html);
    });
  });
});

app.post('/api/theme', require('./routes/generateTheme'));

//Angular Routes
//
app.get('*.*', express.static(join(DIST_FOLDER, 'browser')));


app.get('*', (req, res) => {
  res.render('index', {
    req: req,
    res: res,
    providers: [
      {
        provide: 'REQUEST', useValue: (req)
      },
      {
        provide: 'RESPONSE', useValue: (res)
      }
    ]
  });
});

//***************** END Routes *****************//
//

//***************BEGIN app configurations *******************//
//server gzipped content
app.use(compression());
app.use('/images', express.static('images'));
app.use('/assets', express.static('assets'));
app.use('/dist', express.static('dist'));
app.use('/node_modules', express.static('node_modules'));
app.use('/app', express.static('app'));
app.use('/public', express.static('public'));
app.use(fallback('index.htm', { root: root }));

//*************** END app configurations *******************//


//*************** BEGIN server instantiation *******************//
//SSL termination for heroku is handled by the load balancer
//but locally is handled by node
if(!process.env.APP_ENV || (process.env.APP_ENV === 'feature')){
  var credentials = {
    key: fs.readFileSync(path.join('ssl', 'certs', 'server', 'privkey.pem')),
    cert: fs.readFileSync(path.join('ssl', 'certs', 'server', 'fullchain.pem')),
    ca: fs.readFileSync(path.join('ssl', 'certs', 'ca', 'my-root-ca.crt.pem'))
  };
  var httpsServer = https.createServer(credentials, app);
  httpsServer.listen(process.env.PORT || 8080);
} else {
  var httpServer = http.createServer(app);
  httpServer.listen(process.env.PORT || 8080);
}

//*************** END server instantiation *******************//
Run Code Online (Sandbox Code Playgroud)

angular.json(cli 配置)

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "browser": {
      "root": "",
      "sourceRoot": "src",
      "projectType": "application",
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "dist/browser",
            "index": "src/index.html",
            "main": "src/main.ts",
            "tsConfig": "src/tsconfig.app.json",
            "polyfills": "src/polyfills.ts",
            "assets": [
              "src/assets"
            ],
            "styles": [
              "src/styles.scss",
              "node_modules/froala-editor/css/froala_editor.pkgd.min.css",
              "node_modules/froala-editor/css/froala_style.min.css",
              "node_modules/sweetalert2/dist/sweetalert2.min.css",
              "node_modules/pnotify/dist/pnotify.css",
              "node_modules/@ng-select/ng-select/themes/default.theme.css",
              "node_modules/angular2-busy/build/style/busy.css"
            ],
            "scripts": [
              "node_modules/sweetalert2/dist/sweetalert2.min.js",
              "node_modules/lodash/lodash.min.js",
              "node_modules/jquery-watch/jquery-watch.min.js",
              "node_modules/bootstrap/dist/js/bootstrap.min.js",
              "node_modules/socket.io-client/dist/socket.io.js"
            ]
          },
          "configurations": {
            "production": {
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "extractCss": true,
              "namedChunks": false,
              "aot": true,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true,
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ]
            },
            "demo": {
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "extractCss": true,
              "namedChunks": false,
              "aot": true,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true,
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.demo.ts"
                }
              ]
            },
            "feature": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.feature.ts"
                }
              ]
            },
            "stage": {
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "extractCss": true,
              "namedChunks": false,
              "aot": true,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true,
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.staging.ts"
                }
              ]
            }
          }
        },
        "server": {
          "builder": "@angular-devkit/build-angular:server",
          "options": {
            "outputPath": "dist/server",
            "main": "src/server.main.ts",
            "tsConfig": "src/tsconfig.server.json",
            "bundleDependencies": "all"
          },
          "configurations": {
            "production": {
              "browserTarget": "browser:build:production"
            },
            "demo": {
              "browserTarget": "browser:build:demo"
            },
            "feature": {
              "browserTarget": "browser:build:feature"
            },
            "stage": {
              "browserTarget": "browser:build:stage"
            }
          }
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browse

Copyright Info

© Copyright 2013-2021 admin@qa.1r1g.com

如未特别说明,本网站的内容使用如下协议:
Creative Commons Atution-NonCommercial-ShareAlike 4.0 International license
.

用以下方式浏览
回到顶部