rbasniak
rbasniak

Reputation: 4954

Dynamic import on Angular 7+

I'm trying to build project that contains some components with dynamic imports, like:

import {Directive, Input, ElementRef} from '@angular/core';

@Directive({
  selector: '[saKnob]'
})
export class KnobDirective {

  @Input() saKnob: any;
  constructor(private el: ElementRef) {
    import('jquery-knob').then(()=>{
      this.render()
    })
  }

  render(){
    $(this.el.nativeElement).knob(this.saKnob || {})
  }
}

The dynamic import on the constructor seems to be the problem. I'm getting the following error:

ERROR in ./src/app/shared/forms/input/knob.directive.ts 15:8
Module parse failed: 'import' and 'export' may only appear at the top level 
(15:8)
You may need an appropriate loader to handle this file type.
|         var _this = this;
|         this.el = el;
>         import('jquery-knob').then(function () {
|             _this.render();
|         });

As far as I researched, this kind of import is supported since Angular 4, and I'm using Angular 7.

Does anyone have an idea on what could be the problem?

* UPDATE *

As pointed by some answers, I was already using esnext on my tsconfig.app.file file:

{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "outDir": "../out-tsc/app",
    "baseUrl": "./",
    "module": "esnext",
    "types": [],
    "paths": {
      "@app/*": ["app/*"],
      "@env/*": ["environments/*"]
    }
  },
  "exclude": [
    "src/test.ts",
    "**/*.spec.ts"
  ]
}

And here's the contents of the tsconfig.json

{
"compileOnSave": false,
"compilerOptions": {
    "baseUrl": "./",
    "outDir": "./dist/out-tsc",
    "sourceMap": true,
    "declaration": false,
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "module": "es2015",
    "target": "es5",
    "typeRoots": ["node_modules/@types"],
    "lib": ["es2018", "dom"],
    "paths": {
    "@app/*": ["src/app/*"],
    "@env/*": ["src/environments/*"]
    }
}
}

My typescript version is ~3.1.6.

Upvotes: 9

Views: 10397

Answers (4)

zmag
zmag

Reputation: 8241

You can't just call import like that. You need to import SystemJS first. then call its import method.

import('jquery-knob').then(()=>{
  this.render()
})

stackblitz: https://stackblitz.com/edit/angular-bkbqkj

Upvotes: 1

Ashish Jain
Ashish Jain

Reputation: 2977

This worked for me on Angular 8. First install acorn (acorn will be added in package.json file) then delete node_modules & package-lock.json then npm install.

npm install acorn
rm -rf node_modules
rm -f package-lock.json
npm install

Upvotes: 0

Viachaslau T
Viachaslau T

Reputation: 181

In short:

It's caused by npm issue appeared with @angular-devkit/build-angular update from 0.12.x to 0.13.x and related webpack update under the hood from 4.28.x to 4.29.x.

Possible solutions (workarounds):

  • use @angular-devkit/build-angular 0.12.x
  • try workarounds mentioned here. One working for me is to add explicit latest acorn dependency (e. g. npm i --save acorn will add 6.1.1 at the time of writing). Another popular workaround is to run npm update acorn --depth 20 && npm dedupe.
  • use yarn if applicable

Details:

Have recently stumbled upon similar issue after project update from Angular 7.2 to Angular 7.3. Before update build was fine, and esnext as target was already specified in tsconfig.json.

After some tests I've revealed that it relates to @angular-devkit/build-angular and found issues (13767, 13793) in angular-cli that surprisingly were closed. But alan-agius4 comment in issue 13793 shed some light to real origin: invalid hoisting for peer dependencies; explained in details by sokra in this comment.

There were already accepted pull request #147 for issue #4794, but then it was reverted in pull request #152 and issue #4794 remains opened at the time of writing.

Upvotes: 6

Loheek
Loheek

Reputation: 1985

It works when creating a new project using ng new with the latest angular-cli.

I think the problem is your Typescript config. Try to set these values in you tsconfig.json:

{
    ...
    "module": "es2015",
    "target": "es5",
    "lib": [
        "es2018",
        ...
    ]
}

Upvotes: 0

Related Questions