Search code examples
angularjsexpressangularangular2-universaltrailsjs

No Directive annotation found on TodoApp Server Rendering


I'm trying to do server rendering with angular2-universal. I copy paste the example todo app of the official repo https://github.com/angular/universal/tree/master/examples/src/universal/todo into my own Trails/Express server.

I manage to start my server but when I call http://localhost:3000 I have the following error :

Error: No Directive annotation found on TodoApp
    at new BaseException (/Users/jaumard/IdeaProjects/trails-angular2-isomorphic/node_modules/@angular/compiler/src/facade/exceptions.js:17:23)
    at DirectiveResolver.resolve (/Users/jaumard/IdeaProjects/trails-angular2-isomorphic/node_modules/@angular/compiler/src/directive_resolver.js:31:15)
    at CompileMetadataResolver.getDirectiveMetadata (/Users/jaumard/IdeaProjects/trails-angular2-isomorphic/node_modules/@angular/compiler/src/metadata_resolver.js:55:51)
    at RuntimeCompiler.resolveComponent (/Users/jaumard/IdeaProjects/trails-angular2-isomorphic/node_modules/@angular/compiler/src/runtime_compiler.js:34:47)
    at /Users/jaumard/IdeaProjects/trails-angular2-isomorphic/node_modules/@angular/core/src/application_ref.js:99:37
    at /Users/jaumard/IdeaProjects/trails-angular2-isomorphic/node_modules/@angular/core/src/application_ref.js:292:26
    at ZoneDelegate.invoke (/Users/jaumard/IdeaProjects/trails-angular2-isomorphic/node_modules/zone.js/dist/zone-node.js:281:29)
    at Object.NgZoneImpl.inner.inner.fork.onInvoke (/Users/jaumard/IdeaProjects/trails-angular2-isomorphic/node_modules/@angular/core/src/zone/ng_zone_impl.js:45:41)
    at ZoneDelegate.invoke (/Users/jaumard/IdeaProjects/trails-angular2-isomorphic/node_modules/zone.js/dist/zone-node.js:280:35)
    at Zone.run (/Users/jaumard/IdeaProjects/trails-angular2-isomorphic/node_modules/zone.js/dist/zone-node.js:174:44)
    at NgZoneImpl.runInner (/Users/jaumard/IdeaProjects/trails-angular2-isomorphic/node_modules/@angular/core/src/zone/ng_zone_impl.js:76:71)
    at NgZone.run (/Users/jaumard/IdeaProjects/trails-angular2-isomorphic/node_modules/@angular/core/src/zone/ng_zone.js:223:66)
    at ApplicationRef_.run (/Users/jaumard/IdeaProjects/trails-angular2-isomorphic/node_modules/@angular/core/src/application_ref.js:290:14)
    at Object.coreLoadAndBootstrap (/Users/jaumard/IdeaProjects/trails-angular2-isomorphic/node_modules/@angular/core/src/application_ref.js:96:19)
    at /Users/jaumard/IdeaProjects/trails-angular2-isomorphic/node_modules/angular2-universal/dist/node/bootloader.js:186:34
    at Array.map (native)

The example of the universal repo is working so I don't understand why it's not working for me. I don't change anything on the angular2 sources.

All my code is here https://github.com/jaumard/trails-angular2-isomorphic with the configuration here https://github.com/jaumard/trails-angular2-isomorphic/blob/master/api/controllers/ViewController.js#L58 for the route and here for the template engine https://github.com/jaumard/trails-angular2-isomorphic/blob/master/config/web.js#L76


Solution

  • Your problem is that you're working with different packages angular2 at the same time.

    You start server with modules from ./node_modules/ folder but your component TodoApp will be decorated by instance ComponentMetadata (extends DirectiveMetadata) from ./dist/src/node_modules/@angular/core/ folder. enter image description here

    I think that first you need to transfer packages to dist folder and then run server. And you have to use the same path to angular2 modules (./dist/src/node_modules)

    For example you can try something like this:

    server.js

    'use strict'
    
    const gulp = require('gulp');
    const rimraf = require('gulp-rimraf');
    const path = require('path');
    const dest = './dist';  
    
    gulp.task('clean', (cb) => {
      return gulp.src(dest).pipe(rimraf())
    });
    
    gulp.task('prerun', ['clean'], () => {
      return gulp.src([
        'node_modules/rxjs/**/*',
        'node_modules/zone.js/**/*',
        'node_modules/core-js/**/*',
        'node_modules/reflect-metadata/**/*',
        'node_modules/systemjs/**/*',
        'node_modules/@angular/**/*',
        'node_modules/angular2-universal/**/*',
        'node_modules/angular2-universal-polyfills/**/*',
        'node_modules/angular2-express-engine/**/*',
        'node_modules/angular2-hapi-engine/**/*'
      ], { base: './' })
        .pipe(gulp.dest(path.join(dest, 'src')))
    });
    
    
    gulp.start('prerun', run)
    
    function run() {
      require('./dist//src/node_modules/angular2-universal/polyfills')
      const app = require('./')
      const TrailsApp = require('trails')
      const server = new TrailsApp(app)
    
      server.start().catch(err => server.stop(err))
    }
    

    I added reflect-metadata in package.json. Also you need to change a bit componentUrl like this:

    ViewController.js

    module.exports = class ViewController extends Controller {
      helloWorld(req, res) {
        const todoApp = require('../../dist/src/todo/app')
        let queryParams = ng2U.queryParamsToBoolean(req.query);
        let options = Object.assign(queryParams , {
          // client url for systemjs
          buildClientScripts: true,
          systemjs: {
            componentUrl: 'todo/browser', <== remove src/
            map: {
              'angular2-universal': 'node_modules/angular2-universal',
              '@angular': 'node_modules/@angular'
            },
            packages: PACKAGES
          },
          ...
    

    Then you can see the following error:

    enter image description here

    So you need to add rxjs in your configuration: ViewController.js

    const PACKAGES = {
      'angular2-universal/polyfills': {
        format: 'cjs',
        main: 'dist/polyfills',
        defaultExtension: 'js'
      },
      ...
      rxjs: {  <== this property
        defaultExtension: 'js'
      }
    };
    
    ...
    systemjs: {
      componentUrl: 'todo/browser',
      map: {
        'angular2-universal': 'node_modules/angular2-universal',
        '@angular': 'node_modules/@angular',
        'rxjs': 'node_modules/rxjs' <== this line
      },
      packages: PACKAGES
    },
    

    See also the full list of changes here https://github.com/alexzuza/trails-angular2-isomorphic/commit/45f2e59529821757f6a6c03c5872e08fdce3f3e7

    Hope it helps you!