Search code examples
webpack-2ng-bootstrapangular2-aot

ng-bootstrap AoT build failure with Unexpected Token and missing loader


I am trying to use ng-bootstrap library in my project. Runs fine with webpackdevserver and jit build but aot build throw errors similar to following

Module parse failed: E:\SVNCode\Learning\spa\aot\node_modules\@ng-
bootstrap\ng-bootstrap\alert\alert.ngfactory.ts Unexpected token (13:21)
You may need an appropriate loader to handle this file type.

I have searched for the issue but the only reference related to ng-bootstrap was ticket no. #1381 on github, which was closed without any further details. So, I believe that I may be missing something very small. Here are relevant details

  1. Node : 8.1.3
  2. Angular & Compiler-cli: 4.2.4
  3. Webpack : 2.6.1
  4. typescript : 2.3.4
  5. ng-bootstrap : 1.0.0-alpha.26
  6. bootstrap : 4.0.0-alpha.6 (using CDN but tried after install also with same result)

webpack.prod.js

let ExtractTextPlugin = require('extract-text-webpack-plugin');
let webpack = require('webpack');
let HtmlWebpackPlugin = require('html-webpack-plugin');
let CompressionPlugin = require("compression-webpack-plugin");
let CopyWebpackPlugin = require('copy-webpack-plugin');

let path = require('path');
let rootDir = path.resolve(__dirname, '..');

module.exports = {
    entry: {
        'polyfills': './spa/polyfills.ts',
        'vendor': './spa/vendor-aot.ts',
        'app': './spa/main-aot.ts' // AoT compilation
    },

    output: {
        path: path.join(rootDir,'wwwroot'),
        filename: 'js/[name]-[hash:6].bundle.js',
        chunkFilename: 'js/[id]-[hash:6].chunk.js',
        publicPath: '/'
    },

    resolve: {
        extensions: ['.ts', '.js', '.json', '.css', '.html']
    },

    module: {
        rules: [
            {
                test: /\.ts$/,
                use: [
                    'babel-loader?presets[]=es2015',
                    'awesome-typescript-loader?configFileName=tsconfig-aot.json',
                    'angular-router-loader?aot=true&genDir=spa/aot/'
                ],
                exclude: /node_modules/
            },
            {
                test: /\.css$/,
                loaders: ['to-string-loader', 'css-loader']
            },
            {
                test: /\.html$/,
                use: 'html-loader'
            }
        ],
        exprContextCritical: false
    },
    plugins: [
        new webpack.optimize.CommonsChunkPlugin({
            name: ['app', 'vendor', 'polyfills']
        }),
        new webpack.LoaderOptionsPlugin({
            minimize: true,
            debug: false
        }),
        new webpack.optimize.UglifyJsPlugin({
            beautify: false,
            compress: {
                warnings: false
            },
            output: {
                comments: false
            },
            sourceMap: false,
            mangle: {keep_fnames: true}
        }),
        new CompressionPlugin({
            asset: "[path].gz[query]",
            algorithm: "gzip",
            test: /\.js$|\.html$/,
            threshold: 10240,
            minRatio: 0.8
        }),
        new ExtractTextPlugin("[name].css"),
        new HtmlWebpackPlugin({
            template: './spa/index.html'
        }),
        new CopyWebpackPlugin([
            { from: path.join(rootDir,'spa','assets'), to: 'assets'}
        ]),
        new webpack.NoEmitOnErrorsPlugin()
    ]
};

tsconfig-aot.js

{
    "compilerOptions": {
        "target": "es2015",
        "module": "commonjs",
        "moduleResolution": "node",
        "sourceMap": false,
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "removeComments": true,
        "noImplicitAny": true,
        "suppressImplicitAnyIndexErrors": true,
        "lib": ["es2015","dom"],
        "typeRoots": ["node_modules/@types"],
        "types":["node", "core-js"]
    },
    "files": [
        "spa/app/app.module.ts",
        "spa/main-aot.ts"
    ],
    "exclude": ["node_modules"],
    "angularCompilerOptions": {
        "genDir": "spa/aot",
        "skipMetadataEmit": true
    },
    "awesomeTypescriptLoaderOptions":{
        "useWebpackText": true,
        "useCache": true
    }
}

vendor-aot.ts

import '@angular/platform-browser';
import '@angular/core';
import '@angular/common';
import '@angular/http';
import '@angular/forms';
import '@angular/router';
import '@angular/platform-browser/animations';

import 'rxjs';
//can import others e.g. bootstrap, jquery etc
//can import js, ts, css, sass etc..
import '@ng-bootstrap/ng-bootstrap';

Thanks & Regards


Solution

  • After searching the internet high and low, going through several stackoverflow posts and github project configurations/samples, I finally managed to fix it (duct tape way).

    All I had to do to fix the issue was remove the exclusion of node_modules folder in webpack config file.

    Now, WHY exclusion of node_modules works for angular and rxjs packages but not for ng-bootstrap, is still beyond me.

    Exclusion works when building for jit but for aot to succeed node_modules HAS TO BE INCLUDED in ts loader chain. Now the build time for aot has increased multifold, but at least it works.