ng-lazyload-image: Angular Universal build prerender error

  • I’m submitting a …

    • bug report
    • feature request
    • support request
  • Do you want to request a feature or report a bug? Bug with your library and Angular Universal build prerender functionality

  • What is the current behavior? When you run the command: npm run build:prerender

it runs: "generate:prerender": "cd dist && node prerender",

Then fails with the error:

(function (exports, require, module, __filename, __dirname) { import { NgModule } from '@angular/core';
                                                              ^^^^^^

SyntaxError: Unexpected token import
    at createScript (vm.js:80:10)
    at Object.runInThisContext (vm.js:139:10)
    at Module._compile (module.js:617:28)
    at Object.Module._extensions..js (module.js:664:10)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12)
    at Function.Module._load (module.js:498:3)
    at Module.require (module.js:597:17)
    at require (internal/module.js:11:18)
    at Object.ng-lazyload-image/src/lazyload-image.module (/dist/server/main.js:1350:18)
  • provide the steps to reproduce
  1. Duplicate the Angular Universal starter project from: https://github.com/angular/universal-starter

  2. Add your library, following install instructions: https://github.com/tjoskar/ng-lazyload-image

  3. Run the Angular build command to see the error: npm run build:prerender

  • What is the expected behavior? No error, and to continue building.

  • What is the motivation / use case for changing the behavior? Otherwise your plugin cannot be used with Angular Universal, which means no static site generation 😦

  • Please tell us about your environment:

    • MacOS 10.13.6
    • node 8.9.1
    • ng-cli 6.0.0 and tested with 7.1.4
    • angular 6.0.0 and tested with 7.1.4
    • nguniversal 6.0.0 and tested with 7.0.2
  • Other information

Looks like other people have had similar problems with Angular Universal and third-party libraries such as yours: https://github.com/angular/angular-cli/issues/7200#issuecomment-329711848

They say the third-party libraries aren’t being built correctly, which means Angular Universal fails: https://github.com/angular/angular-cli/issues/7200#issuecomment-328991769

for example they suggest adding to your package.json

"module": "./quickstart-lib.es5.js",
"es2015": "./quickstart-lib.js",
"typings": "./quickstart-lib.d.ts",

Approach 1 Patch your plugin root: npm install @babel/cli @babel/core @babel/preset-env @babel/plugin-transform-modules-umd

Adding a .babelrc file in the root of your plugin folder:

{
  "plugins": [["@babel/plugin-proposal-decorators", { "decoratorsBeforeExport": true }]],
  "presets": ["@babel/preset-env"]
}

Updating your plugins package.json

"main": "./lib-umd/index.js",
"module": "./lib-es5/index.js",
"es2015": "./lib/index.js",
"typings": "./lib/index.d.ts",
"scripts": {
  "build:umd": "babel ./lib/*.js --out-dir ./lib-umd --plugins @babel/plugin-transform-modules-umd",
  "build:es5": "babel ./lib/*.js --out-dir ./lib-es5"
}

Then running the build: npm run build:es5 && npm run build:umd

And adding to my own project tsconfig.json

"compilerOptions": {
  "paths": { "@angular/*": ["../node_modules/@angular/*"] },
}

But still getting the same error with Angular Universal 😦

Approach 2 Use the Typescript build options for the example project at: https://github.com/filipesilva/angular-quickstart-lib

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 3
  • Comments: 23 (9 by maintainers)

Commits related to this issue

Most upvoted comments

I experience the same issue while trying to build with angular universal. @tjoskar have you thought about using ng-packagr to build your library? You could build and bundle your library in FESM2015, FESM5, and UMD formats. Have a look here: https://github.com/ng-packagr/ng-packaged/blob/master/package.json#L11 (example project using ng-packagr).

I ended up writing my own directive which works with Universal:

import { Directive, ElementRef, Inject, Input, OnInit, PLATFORM_ID} from '@angular/core';
import { isPlatformBrowser } from '@angular/common';

@Directive({
  selector: '[appLazyLoadImage]'
})
export class LazyLoadImageDirective implements OnInit {
  @Input() srcLazy: string;

  constructor(
    private el: ElementRef,
    @Inject(PLATFORM_ID) private platformId: Object,
  ) { }

  ngOnInit() {
    // only run lazy image loading in the browser
    if (isPlatformBrowser(this.platformId)) {
      // if browser supports IntersectionObserver
      if ('IntersectionObserver' in window) {
        const lazyImageObserver = new IntersectionObserver((entries, observer) => {
          entries.forEach((entry) => {
            if (entry.isIntersecting) {
              entry.target.setAttribute('src', this.srcLazy);
              entry.target.classList.add('lazy-loaded');
              lazyImageObserver.unobserve(entry.target);
            }
          });
        });
        lazyImageObserver.observe(this.el.nativeElement);
      } else {
        // Otherwise replace image by default
        this.el.nativeElement.setAttribute('src', this.srcLazy);
      }
    }
  }

}

import it into your Module:

import { LazyLoadImageDirective } from './lazy-load-image.directive';
...
@NgModule({
  imports: [
    CommonModule
  ],
  declarations: [
    LazyLoadImageDirective
  ],
  exports: [
    CommonModule,
    LazyLoadImageDirective
  ]
})
...etc

and use on an image with: <img src="../assets/placeholder.jpg" srcLazy="../assets/myimage.jpg" alt="Example" appLazyLoadImage />