Search code examples
angularangular-ui-routerrollupaot

ui-router/angular-hybrid not working with AOT / rollup


I am trying to make the ui-router work for an angular hybrid application. It works when using JIT compilation, but when I try to make it work with AOT and rollup, the rollup step fails with an error mesaage:

'@uirouter/angular-hybrid' is imported by src\app.module.js, but could not be resolved - treating it as an external dependency

I have opened an issue on the github here. The error can be reproduced by downloading the angular-hybrid minimal example and setting up AOT and rollup on this example the way it is described in angular guidelines, as can be seen in the files from this plunker. The import from '@uirouter/angular-hybrid' is impossible for rollup to resolve.

import { UIRouterUpgradeModule } from '@uirouter/angular-hybrid';

Does anybody have some experience trying to make angular-hybrid work in combination with AOT/rollup? Has somebody succeeded in doing so?

UPDATE

I have managed to make the rollup step work by adding a custom plugin to the rollup-config that resolves the angular-hybrid package. But even so, the application fails in runtime while bootstraping angular and asking for UrlService there. The provider for UrlService is not found with the following call (interestingly, the UrlService exists among the registered providers of the injector, but it is impossible to be found using the UrlService token):

var router = injector.get(UrlService);

Here is the adjusted rollup-config, which I am not sure is proper, since the DI does not work. Still the former question, how to make angular-hybrid compatible with rollup remains.

import nodeResolve from "rollup-plugin-node-resolve"
import commonjs from "rollup-plugin-commonjs";
import uglify from "rollup-plugin-uglify";
import progress from "rollup-plugin-progress";

class UIRouterHybridResolver 
{
    constructor(options) 
    {
        this.options = options;
    }

    resolveId(id, from)
    {
        if (id.startsWith("@uirouter/angular-hybrid"))
        {
            return `${__dirname}/node_modules/@uirouter/angular-hybrid/lib/angular-hybrid.js`;          
        }

        return null;
    }
}
const uIRouterHybridResolver = (config) => new UIRouterHybridResolver(config);

export default {
    entry: "src/main.js",
    dest: "src/build.js", // output a single application bundle
    sourceMap: false,
    format: "iife",
    onwarn: function (warning) {
        // Skip certain warnings

        // should intercept ... but doesn't in some rollup versions
        if (warning.code === "THIS_IS_UNDEFINED") { return; }

        // console.warn everything else
        console.warn(warning.message);
    },
    plugins: [       
        commonjs({
            include: [
                "node_modules/rxjs/**",
                "node_modules/@uirouter/core/**"
            ]
        }),
        nodeResolve({ jsnext: true, module: true }),
        uIRouterHybridResolver(),
        uglify(),        
        progress({ clearLine: true })
    ],
    globals: { angular: "angular" },
    external: ["angular"]
};

Solution

  • You are almost there. The final essence for our rollup.js bundle is:

    a UIRouter CORE esm version (see What is the purpose of the esm directories in the Angular 2 modules?).

    That piece of code is available at node_modules\@uirouter\core\lib-esm\ (the \lib-esm at the end). To use it, we would need to adjust the UIRouterHybridResolver plugin:

    class UIRouterHybridResolver 
    {
        resolveId(id, from)
        {
            if (id.startsWith("@uirouter/core"))
            {
                return `${__dirname}/node_modules/@uirouter/core/lib-esm/index.js`;
            }
            if (id.startsWith("@uirouter/angular-hybrid"))
            {
                return `${__dirname}/node_modules/@uirouter/angular-hybrid/lib/angular-hybrid.js`;
            }
        }
    }
    const uIRouterHybridResolver = () => new UIRouterHybridResolver();
    

    We also must be sure, that this would be the very first plugin of our exported config:

    export default {
        entry: "src/main.js",
        dest: "src/build.js", 
        ...
        plugins: [       
            uIRouterHybridResolver(),
            commonjs({
                include: [
                    "node_modules/rxjs/**"
                ]
            }),
            ...
    

    NOTE: also, the commonjs plugin does not need (should not have) the "node_modules/@uirouter/core/**", just include "node_modules/rxjs/**"

    ...and that is it... hybrid UIRouter with AOT is working...

    EXTEND

    Also, be sure, that we follow instructions described here: https://www.npmjs.com/package/@uirouter/angular-hybrid. Mostly that the package.json contains just the key @uirouter/angular-hybrid:

    dependencies: {
      ...
      "@angular/common": "^4.0.0",
      "@angular/compiler": "^4.0.0",
      "@angular/core": "^4.0.0",
      "@angular/platform-browser": "^4.0.0",
      "@angular/platform-browser-dynamic": "^4.0.0",
      "@angular/upgrade": "^4.0.0",
      ...
      "@uirouter/angular-hybrid": "3.1.2",
      ...
    

    I.e. do not append stuff like "@uirouter/angular": "1.0.0-beta.7" etc. And finally assure that dependencies are up to date by calling npm i