Search code examples
angularrollupangular2-aotrollupjstree-shaking

Angular2 - Rollup Tree shaking (*.ngfactory - could not be resolved)


I try to use Tree-shaking for Angular 2 app after AOT compilation, and I catch the next message:

'Containers/module.ngfactory' is imported by Containers\module.aot.js, but could not be resolved – treating it as an external dependency

No name was provided for external module 'Containers/module.ngfactory' in options.globals – guessing 'Containers_module_ngfactory'

And I don't know how to fix this.

this is module.aot.js code after AOT compilation:

import { enableProdMode } from '@angular/core';
enableProdMode();
import { platformBrowser } from '@angular/platform-browser';
import { ModuleNgFactory } from 'Containers/module.ngfactory';
platformBrowser().bootstrapModuleFactory(ModuleNgFactory);
//# sourceMappingURL=module.aot.js.map

rollup-config.js

'use strict';

import nodeResolve from 'rollup-plugin-node-resolve'
import commonjs    from 'rollup-plugin-commonjs';
import uglify      from 'rollup-plugin-uglify'

export default {
    entry: './Containers/module.aot.js',
    dest:  './module.vendor.js',
    sourceMap: false,
    format: 'iife',
    onwarn: function(warning) {
        // Skip certain warnings
        if ( warning.code === 'THIS_IS_UNDEFINED' ) { return; }
        if ( warning.code === 'EVAL' ) { return; }
        console.warn( warning.message );
    },
    plugins: [
        nodeResolve({jsnext: true, module: true}),
        commonjs({
            include: 'node_modules/rxjs/**',
        }),
        uglify()
    ]
}

and tsconfig-aot.json

{
    "compilerOptions": {
        "target": "es5",
        "module": "es2015",
        "moduleResolution": "node",
        "sourceMap": true,
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "lib": [ "es2015", "dom" ],
        "noImplicitAny": true,
        "suppressImplicitAnyIndexErrors": true,
        "baseUrl": ".",
        "paths": {
            "app/*": [ "../src/*" ]
        },
        "typeRoots": [
            "../node_modules/@types"
        ]
    },
    "files": [
        "../src/globals.ts",
        "../src/Containers/module.aot.ts"
    ],
    "exclude": [
        "node_modules",
        "typings"
    ],
    "angularCompilerOptions": {
        "genDir": "../",
        "skipMetadataEmit": false,
        "skipTemplateCodegen": false
    }
}

In general, AOT works fine, but I can't run to tree-shaking for a bundle my code to the one file.

Help me please resolve this problem.

UPD

It's problem just with the main module.aot.js file.

Any suggestion how to resolve this problem?


Solution

  • I have found solutions for this case. It's very simple, but I had spent for this many time :(

    In the each an Angular components we need to put a correct patch to the other service, module, etc.

    For example:

    If we have a project structure like this:

    |-main.ts
    |-src
            | - service
                    | - authorize.service.ts
            | - login
                    | - login.component.ts
    

    then in the login.component.ts you would like to import authorize.service.ts from service folder, you need to put a patch to this service like this:

    import { donothing } from '../service/authorize.service'
    

    It's very strange but the Angular app with JIT or AOT works well if we put next path to this service:

    import { donothing } from 'service/authorize.service'
    

    And the second case it's path to some service, module, etc, which is situated in the current directory.

    For example:

    We have a project like previous but in the root folder we have helper.service.ts file.

    |-main.ts
    |-helper.service.ts
    ...
    

    If you try to include helper.service.ts in the main.ts like this:

    import { donothing2 } from 'helper.service'
    

    or

    import { donothing2 } from '/helper.service'
    

    It will be work with JIT and AOT but doesn't work when we a try to run Rollup for tree-shaking.

    Solution very simple but for me it's strange.

    We need to put . before a file name, because without the . it's treated as an external import.

    import { donothing2 } from './helper.service'
    

    I hope my answer will be helpful for someone.

    Thanks.