Server side rendering with universal

We should explore server-side rendering options with universal. IMO we should be in a pretty good shape to support it as we are not doing anything too crazy. There is direct DOM access in few places but it shouldn’t be too hard to remove it.

Anyway, after we release a version with full AoT support (already in master) we should check what it means to support universal. Probably a good starting point would be to use the https://github.com/angular/universal-starter


Widgets confirmed to work with Angular 6+:

  • Accordion
  • Alert
  • Buttons
  • Carousel (fix in #2494)
  • Collapse
  • Datepicker*
  • Dropdown
  • Modal*
  • Pagination
  • Popover*
  • Progressbar
  • Rating
  • Tabs
  • Timepicker
  • Tooltip*
  • Typeahead*

7 thoughts on “Server side rendering with universal

  1. Ha! One more update: progressbar works as well, another user error 🙂

    Conclusion => fixing carousel will make the entire library universal-compatible 😃

  2. I tried the angular-cli guide to enable universal on an Angular app using ng-bootstrap, I get the following error:

    $ node server.js 
    /myapp/node_modules/@ng-bootstrap/ng-bootstrap/alert/alert.js:1
    (function (exports, require, module, __filename, __dirname) { import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, } from '@angular/core';
                                                                  ^^^^^^
    
    SyntaxError: Unexpected token import
        at createScript (vm.js:74:10)
        at Object.runInThisContext (vm.js:116:10)
        at Module._compile (module.js:533:28)
        at Object.Module._extensions..js (module.js:580:10)
        at Module.load (module.js:503:32)
        at tryModuleLoad (module.js:466:12)
        at Function.Module._load (module.js:458:3)
        at Module.require (module.js:513:17)
        at require (internal/module.js:11:18)
        at Object.2RxQ (/myapp/dist-server/main.bf83d26d1ade1e6a9a5a.bundle.js:1:65363)
    

    I can work around the problem using webpack to whitelist ng-boostrap with an additional compilation step but I guess this is not the recommended practice.
    Note: this is on @angular/cli@1.3.0-rc.3 and @ng-bootstrap/ng-bootstrap@1.0.0-alpha.29.

  3. Hi folks,

    The modal service is currently breaking universal builds when injected into components. The issue can be reproduced by cloning the universal-starter repo and injecting the service into any component.

    I have written more detail about it in #1968, which has been closed as a duplicate.

    Thanks for all your hard work!

  4. @ilasw
    Can you confirm that this fixed the issue ? Did you take any aditionnal steps ?
    I’ve just updated the project from Universal with ang4 to ang5 and now i’m getting :
    ” No component factory found for NgbModalBackdrop. Did you add it to @NgModule.entryComponents? ” on the prod build.

  5. Are there any updates on this? This is breaking my app completely, and preventing me from upgrading to Angular 6. I somehow got it working with Angular 5 and webpack, but on 6 it’s breaking all over the place:

    With the CLI, I get the “Unexpected token import” error.
    With custom Webpack config (working with Angular5) I get “Cannot read property ‘forRoot’ of undefined”.

    This is a huge issue and I’ll have to resort to another lib if it’s not resolved soon. This turned out to be a very buggy lib for anything related to SSR or AOT. Do you have some ETA at least?

    EDIT:
    I’ve removed ng-bootstrap from webpack threeshakable list, and now I get a step further.
    “Prerendering failed because of error: ReferenceError: Document is not defined”
    I tracked it down to this code (webpack generated):

    var NgbFocusTrapFactory = /** @class */ (function () {
        function NgbFocusTrapFactory(_document, _ngZone) {
            this._document = _document;
            this._ngZone = _ngZone;
        }
        /**
         * Create an instance of {@link NgbFocusTrap} and return it
         * @param element HTMLElement to trap focus inside
         * @param autofocus Whether the focustrap should automatically move focus into the trapped element upon
         * initialization and return focus to the previous activeElement upon destruction.
         */
        NgbFocusTrapFactory.prototype.create = function (element, autofocus) {
            if (autofocus === void 0) { autofocus = false; }
            return new NgbFocusTrap(element, autofocus, this._document, this._ngZone);
        };
        NgbFocusTrapFactory = __decorate([
            core_1.Injectable(),
            __param(0, core_1.Inject(common_1.DOCUMENT)),
            __metadata("design:paramtypes", [Document, core_1.NgZone])
        ], NgbFocusTrapFactory);
        return NgbFocusTrapFactory;
    }());
    

    This line is causing the issue, it can’t find Document:
    __metadata(“design:paramtypes”, [Document, core_1.NgZone])

    When I comment it out manually, it works.
    I’ve seen similar bugs reported for other projects, it usually points to the lack of universal support.

    As a workaround, I can fake it with webpack DefinePlugin
    new webpack.DefinePlugin({ 'Document': null })