Search code examples
node.jsangularwebpackangular2-aotaot

Angular AOT - UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: #): TypeError: Cannot read property 'request' of undefined


I am using @ngtools/webpack as my Angular CLI for adding AOT Compilation to my Angular 5 app. As is no surprise to anyone, it has been a long journey for me already.

I have gotten AOT working in 3 environments, localhost, development and staging. Or course, deploying to production environment yesterday, I found my Webpack build crashing.

I cannot achieve a meaningful error message though I do know for sure the source of issue is the @ngtools/webpack.AngularCompilerPlugin.

My error message is hundreds of:

UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: #): TypeError: Cannot read property 'request' of undefined

After the AOT Plugin step of Webpack emits hundreds of these UnhandledPromiseRejectionWarnings, it continues building node_module code and then fails to create a dist output:

> [email protected] build-production /app
> webpack --mode production -p --progress --colors --env.env production

env configuration production
***AOT Compilation***
WebpackDelPlugin::Successfully deleted /app/dist/*.* assets.

[91m  0% compiling[0m[91m[0m[91m 10% building modules 0/1 modules 1 active multi babel-polyfill ./src/main.ts[0m[91m                                    10% building modules 1/1 modules 0 active[0m[91m(node:15) DeprecationWarning: Tapable.plugin is deprecated. Use new API on `.hooks` instead
[0m[91m(node:15) DeprecationWarning: Tapable.apply is deprecated. Call apply on the plugin directly instead
[0m[91m(node:15) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): TypeError: Cannot read property 'request' of undefined
(node:15) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): TypeError: Cannot read property 'request' of undefined
[0m[91m(node:15) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 3): TypeError: Cannot read property 'request' of undefined
(node:15) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 4): TypeError: Cannot read property 'request' of undefined
(node:15) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 5): TypeError: Cannot read property 'request' of undefined
///----removed for brevity
(node:15) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 202): TypeError: Cannot read property 'request' of undefined
[0m[91m 10% building modules 1/2 modules 1 active ?ode_modules/babel-polyfill/lib/index.js
//removed for brevity
 70% building modules 2087/2087 modules 0 active[0mRemoving intermediate container b082f2548cbe
 ---> 098c4df274ad
Step 14/17 : RUN cd /app && cp -a dist/* /usr/share/nginx/html
 ---> Running in e179a7482da7
[91mcp: cannot stat 'dist/*': No such file or directory
[0mRemoving intermediate container e179a7482da7
Service 'frontendproduction' failed to build: The command '/bin/sh -c cd /app && cp -a dist/* /usr/share/nginx/html' returned a non-zero code: 1

I have been researching for a while, I found a couple web links that I thought might be relevant, tried many fixes, in particularly this article with no luck. Here is a couple other articles I thought could be relevant but have not helped:

Here is my Webpack.config.js:

var merge = require('webpack-merge'),
htmlPlugin = require('html-webpack-plugin'),
revPlugin = require('webpack-rev-replace-plugin'),
config = require('./build.config.json'),
path = require('path'),
extendedDefinePlugin = require('extended-define-webpack-plugin'),
webpackDelPlugin = require('webpack-del-plugin'),
openBrowserPlugin = require('open-browser-webpack-plugin'),
uglifyJSPlugin = require('uglifyjs-webpack-plugin');
const AotPlugin = require('@ngtools/webpack').AngularCompilerPlugin;
//import {AngularCompilerPlugin} from '@ngtools/webpack';

//Note : in package.json the last variable (dev) is the param delivered to this function { env: 'dev' }. 
module.exports = function (env) {
    console.log('env configuration', env.env);
    /**
     * configPerTarget is merged with build.config.json based on the env passed
     * currently no configuration properties, this configPerTarget not in use per se, keeping just in case - Ogden 4-12-2018
     */
    var configPerTarget = {
        localhost: {
        },
        development: {
        },
        test: {
        },
        staging: {
        },
        production: {
        },
        maintenance: {
        }
    };

    // Note : '__dirname' is the root file path.
    const ROOT_DIR = path.resolve(__dirname);
    const DIST_DIR = path.join(ROOT_DIR, config.dist);

    // If no env make it dev
    if (!env) {
        env = {};
        env.env = config.envDevelopment;
    }

    //merge config with env specific configPerTarget
    config = merge(config, configPerTarget[env.env]);

    // this takes path variables from build.config.json and builds it with given env
    var appConfigPath = config.envs + config.appConfig.replace('{env}', env.env);


    var webPackConfig = {
        entry: ['babel-polyfill', config.src + config.entry],//main.ts
        output: {
            path: path.resolve(__dirname, config.dist),
            filename: config.buildjs,
            sourceMapFilename: config.buildjsmap,
            chunkFilename: config.buildchunk
        },
        module: {
            rules: [
                { test: /\.html$/, use: 'raw-loader' },
                { test: /\.css$/, use: 'raw-loader' },
                {
                    test: /\.scss$/,
                    exclude: /node_modules/,
                    loaders: ['style-loader', 'css-loader', 'sass-loader'],
                },
                //For images. 
                { test: /\.(jpe?g|png|gif|svg)$/i, loader: 'file-loader?name=app/assets/images/[name].[ext]' },
                {
                    test: /\.(ttf|eot|woff|woff2)$/,
                    loader: 'file-loader'
                },
            ]
        },
        //https://webpack.js.org/configuration/devtool/
        //Webpack 4.4 has its own mode development and production, which are environment modes
        //do Webpack 4.4 is handling the devtool sourcemap config where in the past it was not
        //looks like we no longer have to worry about setting devtool
        //https://github.com/damianobarbati/yarsk/blob/50b6f352a13ec2e778fa8b252f915550b6132964/config/webpack.config.js#L110
        //devtool: config.devtool,
        resolve: {
            modules: [__dirname + path.sep + 'src', __dirname, 'node_modules'],
            extensions: ['.js', '.ts', '.scss', '.css', '.html']
        },
        plugins: [
            new htmlPlugin({
                template: config.src + config.index
            }),
            new revPlugin({
                cwd: config.src,
                files: '**/*.html',
                outputPageName: function (filename) {
                    return filename;
                },
                modifyReved: function (filename) {
                    return filename.replace(/(\/style\/|\/script\/)/, '')
                }
            }),
            //Makes AppConfig variable available in the application code. 
            new extendedDefinePlugin({
                AppConfig: require(appConfigPath)
            }),
            //Usefull if you need remove some files or folders before compilation processes. 
            //currently not used (no dist file).
            new webpackDelPlugin({ match: path.join(DIST_DIR, '*.*') }),
            //opens browser after compilation.
            new openBrowserPlugin({ url: 'http://localhost:8080' })
        ],
        optimization: {
            minimizer: [
                new uglifyJSPlugin({
                    uglifyOptions: {
                        output: {
                            comments: false,
                            ascii_only: true //must be on to fix this issue https://github.com/angular/angular/issues/19475
                        }
                    }
                })
            ]
        }
    }

    if (env.env === config.envLocalhost) {
        webPackConfig.module.rules.push(
            {
                test: /\.ts$/,
                loaders: [
                    'ts-loader',
                    'angular2-template-loader',
                    'angular-router-loader']
            }
        );

        return webPackConfig;
    } 

    //********************************AOT Compilation*************************************** */
    //-- AOT Compilation from this point on, currently AOT runs in all environments
    //this seems helpful because you get to see AOT build errors before pushing to build server
    //the downside might be more mangled code and harder to debug source code...
    console.log('***AOT Compilation***');

    webPackConfig.module.rules.push(
        {
            test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/,
            loaders: ['@ngtools/webpack']
        }
    );

    webPackConfig.plugins.push(new AotPlugin({
        tsConfigPath: './tsconfig-aot.json',
        entryModule: path.join(config.src, 'app/app.module#AppModule'),
        sourceMap: true
    }));

    return webPackConfig;
}

And here is my package.json:

{
  "name": "tsl-frontend",
  "version": "0.1.0",
  "scripts": {
    "test": "karma start",
    "build-localhost": "webpack --mode development --progress --colors --env.env localhost",
    "build-development": "webpack --mode development --progress --colors --env.env development",
    "build-staging": "webpack --mode production --progress --colors --env.env staging",
    "build-production": "webpack --mode production -p --progress --colors --env.env production",
    "build-maintenance": "webpack --mode production -p --progress --colors --env.env maintenance",
    "serve": "webpack-dev-server --mode development --inline --progress --colors --env.env development",
    "serve-production": "webpack-dev-server --mode production --inline --progress --colors --env.env development",
    "serve-localhost": "webpack-dev-server --mode development --inline --progress --colors --env.env localhost",
    "serve-host": "webpack-dev-server --host 0.0.0.0 --port 80 --disable-host-check --mode development --inline --progress --colors --env.env localhost",
    "serve-maintenance": "webpack-dev-server --mode development --inline --progress --colors --env.env maintenance"
  },
  "dependencies": {
    "@angular/animations": "^5.2.11",
    "@angular/cdk": "^2.0.0-beta.12",
    "@angular/common": "^5.2.11",
    "@angular/compiler": "^5.2.11",
    "@angular/compiler-cli": "^5.2.11",
    "@angular/core": "^5.2.11",
    "@angular/forms": "^5.2.11",
    "@angular/http": "^5.2.11",
    "@angular/material": "^2.0.0-beta.12",
    "@angular/platform-browser": "^5.2.11",
    "@angular/platform-browser-dynamic": "^5.2.11",
    "@angular/platform-server": "^5.2.11",
    "@angular/router": "^5.2.11",
    "@ng-bootstrap/ng-bootstrap": "^1.1.2",
    "@types/file-saver": "^1.3.0",
    "angular2-jwt": "^0.2.3",
    "angular2-text-mask": "^8.0.5",
    "bootstrap": "^4.1.2",
    "chart.js": "^2.7.2",
    "devextreme": "^18.1.4",
    "devextreme-angular": "^18.1.4",
    "file-saver": "^1.3.8",
    "font-awesome": "^4.7.0",
    "moment": "2.18.1",
    "moment-timezone": "0.5.13",
    "ng2-bootstrap-modal": "1.0.1",
    "ng2-charts": "^1.6.0",
    "ng2-drag-drop": "^2.9.2",
    "ng2-page-scroll": "^4.0.0-beta.12",
    "ng2-toastr": "^4.1.2",
    "popper.js": "^1.14.3",
    "reflect-metadata": "0.1.8",
    "rxjs": "5.5.5",
    "systemjs": "0.19.40",
    "typescript": "^2.9.2",
    "xlsx": "^0.11.19",
    "zone.js": "^0.8.26"
  },
  "devDependencies": {
    "@ngtools/webpack": "^6.0.8",
    "@servicestack/client": "^1.0.14",
    "@types/file-saver": "^1.3.0",
    "@types/jasmine": "^2.8.8",
    "@types/node": "7.0.7",
    "angular-router-loader": "^0.6.0",
    "angular2-router-loader": "^0.3.5",
    "angular2-template-loader": "^0.6.2",
    "babel-polyfill": "^6.26.0",
    "css-loader": "^0.28.11",
    "extended-define-webpack-plugin": "^0.1.3",
    "extract-text-webpack-plugin": "^3.0.2",
    "file-loader": "^1.1.11",
    "file-saver": "^1.3.8",
    "html-webpack-plugin": "^4.0.0-alpha",
    "jasmine": "^2.99.0",
    "karma": "^1.7.0",
    "karma-sourcemap-loader": "^0.3.7",
    "karma-webpack": "^2.0.13",
    "ng-intercom": "^1.0.0-beta.5-2",
    "ng2-tree": "^2.0.0-rc.11",
    "node-sass": "^4.9.2",
    "open-browser-webpack-plugin": "0.0.5",
    "path": "^0.12.7",
    "raw-loader": "^0.5.1",
    "sass-loader": "^6.0.7",
    "style-loader": "^0.13.2",
    "text-mask-addons": "^3.7.2",
    "toposort": "^1.0.7",
    "ts-loader": "^4.4.2",
    "webpack": "^4.16.1",
    "webpack-cli": "^2.1.5",
    "webpack-del-plugin": "0.0.1",
    "webpack-dev-server": "^3.1.4",
    "webpack-merge": "^4.1.3",
    "webpack-rev-replace-plugin": "^0.1.1"
  }
}

Solution

  • I do believe that this error was caused because I had two versions of Webpack installed for my project. This would make sense from perspective that the error occurred in one environment and not others. Perhaps the npm dependency tree was different and an older version of Webpack was being used for some reason.

    There was an npm package: webpack-rev-replace-plugin that had a Webpack v1.5 dependency. I was using Webpack v4.16. Once I removed the webpack-rev-replace-plugin and thus the older version of Webpack, I started getting a different error related to the uglifyjs-webpack-plugin, once I removed the uglifyjs-webpack-plugin and just used Webpacks defaults for minification etc, all was fine.