Angular-cli: Default import is undefined in dev, but exists in `--prod`

Created on 2 Jan 2018  路  5Comments  路  Source: angular/angular-cli

Versions

<!--
Output from: `ng --version`.
If nothing, output from: `node --version` and `npm --version`.
  Windows (7/8/10). Linux (incl. distribution). macOS (El Capitan? Sierra?)
-->
Angular CLI: 1.6.3
Node: 9.3.0
OS: darwin x64
Angular: 5.1.2
... animations, common, compiler, compiler-cli, core, forms
... http, language-service, platform-browser
... platform-browser-dynamic, router

@angular/cli: 1.6.3
@angular-devkit/build-optimizer: 0.0.36
@angular-devkit/core: 0.0.22
@angular-devkit/schematics: 0.0.42
@ngtools/json-schema: 1.1.0
@ngtools/webpack: 1.9.3
@schematics/angular: 0.1.11
@schematics/schematics: 0.0.11
typescript: 2.5.3
webpack: 3.10.0

Repro steps

Observed behavior

<!-- Normally this includes a stack trace and some more information. -->
TypeError: chartModule is not a function
    at eval (webpack-internal:///../../../../angular-highcharts/angular-highcharts.es5.js:257)
    at Array.forEach (<anonymous>)
    at ChartService.initModules (webpack-internal:///../../../../angular-highcharts/angular-highcharts.es5.js:256)
    at new ChartModule (webpack-internal:///../../../../angular-highcharts/angular-highcharts.es5.js:286)
    at _createClass (webpack-internal:///../../../core/esm5/core.js:11112)
    at _createProviderInstance$1 (webpack-internal:///../../../core/esm5/core.js:11086)
    at initNgModule (webpack-internal:///../../../core/esm5/core.js:11039)
    at new NgModuleRef_ (webpack-internal:///../../../core/esm5/core.js:12293)
    at createNgModuleRef (webpack-internal:///../../../core/esm5/core.js:12283)
    at Object.debugCreateNgModuleRef [as createNgModuleRef] (webpack-internal:///../../../core/esm5/core.js:14627)

Desired behavior


Following default import should not be undefined: https://github.com/cebor/angular-highcharts-demo/blob/master/src/app/app.module.ts#L4

Mention any other details that might be useful (optional)

  • ng serve --prod is working
  • with ng 1.6.1 all works fine

Most helpful comment

https://github.com/angular/angular-cli/issues/9059 reported a similar problem. Using the reproduction provided by @cebor I boiled it down to a simpler repro:

import more from 'highcharts/highcharts-more.src';
import dragula from 'dragula';

console.log(more);
console.log(dragula);

Both of these console logs will show undefined in ng serve but functions in ng serve --prod. It's not related to --aot however.

I tracked it down to https://github.com/angular/angular-cli/pull/8128, where we force TS to use commonjs on dev serve. The difference is significant... at the time it could go as high as 60% of rebuild time.

This causes different semantics to be used for default imports. This optimization will go away with Webpack 4 (https://github.com/angular/angular-cli/pull/8611) but for now it's a huge rebuild speed improvement.

For now I think the only good alternative is to force the default import:

import * as more from 'highcharts/highcharts-more.src';
import * as dragula from 'dragula';

console.log(more);
console.log(dragula);

This will work on dev/prod.

All 5 comments

I have similar issues with lodash (which I partially resolved by installing lodash-es instead) and with is_js (this is blocking issue for me since I can't find good solution for using this with cli > 1.6.1)

So at the moment I can't use imports like:
import is from 'is_js' or import isString from 'lodash/isString' since I'm getting errors that is or isString are undefined

I was just about to post a bug with steps to reproduce the loadash issue. I have encountered similar issues.
I specifically am running ng build --watch, however, the same errors occur with ng serve

@zoamel @cebor , I have fixed my lodash issue by changing:
import isFunction from 'lodash/isFunction'
to
import * as isFunction from 'lodash/isFunction'

My other issue has to do with my Angular Components that extends a BaseComponent.
When Angular component does not have an ngOnInit function, ONLY in watch mode, attempting to access the Angular Component's ngOnInit I get an undefined method.

For that, I had to wrap checks around the method calls.

For example:

@Injectable()
export class EaiComponent implements OnInit, OnDestroy, OnChanges {
    private _util: Util;

    constructor(private injector: Injector) {
        this._util = this.injector.get(Util);

        const ngOnInit = this.ngOnInit !== EaiComponent.prototype.ngOnInit ? this.ngOnInit : this.util.noop;
        const ngOnChanges = this.ngOnChanges !== EaiComponent.prototype.ngOnChanges ? this.ngOnChanges : this.util.noop;
        const ngOnDestroy = this.ngOnDestroy !== EaiComponent.prototype.ngOnDestroy ? this.ngOnDestroy : this.util.noop;
        const destroy = this.destroy !== EaiComponent.prototype.destroy ? this.destroy : this.util.noop;
        this._me = this.constructor ? this.constructor.name : EaiComponent.name;

        this.ngOnInit = (...args) => {
            EaiComponent.prototype.ngOnInit.apply(this, args);
            if (ngOnInit) {
                ngOnInit.apply(this, args)
            }
        }
}

Note: Rolling back to 1.6.1 works fine in both scenarios. The issue presented starting with 1.6.2

https://github.com/angular/angular-cli/issues/9059 reported a similar problem. Using the reproduction provided by @cebor I boiled it down to a simpler repro:

import more from 'highcharts/highcharts-more.src';
import dragula from 'dragula';

console.log(more);
console.log(dragula);

Both of these console logs will show undefined in ng serve but functions in ng serve --prod. It's not related to --aot however.

I tracked it down to https://github.com/angular/angular-cli/pull/8128, where we force TS to use commonjs on dev serve. The difference is significant... at the time it could go as high as 60% of rebuild time.

This causes different semantics to be used for default imports. This optimization will go away with Webpack 4 (https://github.com/angular/angular-cli/pull/8611) but for now it's a huge rebuild speed improvement.

For now I think the only good alternative is to force the default import:

import * as more from 'highcharts/highcharts-more.src';
import * as dragula from 'dragula';

console.log(more);
console.log(dragula);

This will work on dev/prod.

@filipesilva Thanks for above workaround. It fixed one issue for us on one default import but in another case a library where we use momentjs and build the library using ngc & rollup, using the "import *" approach gives the following error during the rollup step

[!] Error: Cannot call a namespace ('moment')

There are some workarounds to that, ( https://github.com/rollup/rollup/issues/670#issuecomment-281139978 ) but a consuming angular app throws

TypeError: moment_1.default is not a function

Is the fix that will come with webpack 4 a big task that is not going to happen anytime soon?

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

_This action has been performed automatically by a bot._

Was this page helpful?
0 / 5 - 0 ratings