'How to Prevent Webpack Error after npm Install?

I was working on a project, and everything was going good, until I did npm install.

Then, Webpack throws the following error:

new ForkCheckerPlugin(),
        ^
TypeError: ForkCheckerPlugin is not a constructor
    at makeWebpackConfig (/home/nsanz/Documentos/git/tachology/webpack.make.js:252:9)
    at Object.exports.default (/home/nsanz/Documentos/git/tachology/server/config/express.js:86:27)
    at Object.<anonymous> (/home/nsanz/Documentos/git/tachology/server/app.js:28:1)
    at Module._compile (module.js:570:32)
    at loader (/home/nsanz/Documentos/git/tachology/node_modules/babel-register/lib/node.js:144:5)
    at Object.require.extensions.(anonymous function) [as .js] (/home/nsanz/Documentos/git/tachology/node_modules/babel-register/lib/node.js:154:7)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at Module.require (module.js:497:17)
    at require (internal/module.js:20:19)
    at Object.<anonymous> (/home/nsanz/Documentos/git/tachology/server/index.js:12:28)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at Module.runMain (module.js:604:10)
    at run (bootstrap_node.js:389:7)
    at startup (bootstrap_node.js:149:9)
    at bootstrap_node.js:504:3  

My package.json looks like:

 {
  "name": "tachology",
  "version": "0.0.0",
  "main": "server/index.js",
  "dependencies": {
    ...
  },
  "devDependencies": {
    "angular-mocks": "~1.6.0",
    "autoprefixer": "^7.1.2",
    "babel-core": "^6.6.5",
    "babel-eslint": "^7.2.3",
    "babel-register": "^6.6.5",
    "browser-sync": "^2.8.0",
    "bs-fullscreen-message": "^1.0.0",
    "babel-plugin-transform-class-properties": "^6.6.0",
    "babel-plugin-transform-runtime": "^6.6.0",
    "babel-preset-es2015": "^6.6.0",
    "eslint": "^4.3.0",
    "del": "^3.0.0",
    "gulp": "^3.9.1",
    "gulp-babel": "^6.1.2",
    "gulp-env": "^0.4.0",
    "gulp-eslint": "^4.0.0",
    "gulp-imagemin": "^3.0.1",
    "gulp-inject": "^4.0.0",
    "gulp-istanbul": "^1.1.1",
    "gulp-istanbul-enforcer": "^1.0.3",
    "gulp-load-plugins": "^1.0.0-rc.1",
    "gulp-mocha": "^4.3.1",
    "gulp-node-inspector": "^0.2.0",
    "gulp-plumber": "^1.0.1",
    "gulp-protractor": "^4.1.0",
    "gulp-rev": "^8.0.0",
    "gulp-rev-replace": "^0.4.2",
    "gulp-sort": "^2.0.0",
    "gulp-sourcemaps": "^2.6.0",
    "gulp-util": "^3.0.5",
    "gulp-watch": "^4.3.5",
    "gulp-stylint": "^4.0.0",
    "grunt": "^1.0.1",
    "grunt-build-control": "^0.7.0",
    "isparta": "^4.0.0",
    "nodemon": "^1.3.7",
    "run-sequence": "^2.1.0",
    "lazypipe": "^1.0.1",
    "webpack": "^3.4.1",
    "webpack-dev-middleware": "^1.5.1",
    "webpack-stream": "^3.2.0",
    "extract-text-webpack-plugin": "^3.0.0",
    "html-webpack-plugin": "^2.16.0",
    "html-webpack-harddisk-plugin": "~0.1.0",
    "pug-html-loader": "^1.0.8",
    "awesome-typescript-loader": "3.2.1",
    "ng-annotate-loader": "~0.6.1",
    "babel-loader": "^7.1.1",
    "css-loader": "^0.28.4",
    "file-loader": "^0.11.2",
    "imports-loader": "^0.7.1",
    "isparta-instrumenter-loader": "^1.0.0",
    "isparta-loader": "^2.0.0",
    "istanbul-instrumenter-loader": "^2.0.0",
    "null-loader": "^0.1.1",
    "postcss-loader": "^2.0.6",
    "raw-loader": "^0.5.1",
    "style-loader": "^0.18.2",
    "node-sass": "^4.5.3",
    "sass-loader": "^6.0.6",
    "karma-webpack": "^2.0.4",
    "through2": "^2.0.1",
    "open": "~0.0.4",
    "istanbul": "1.1.0-alpha.1",
    "chai": "^4.1.0",
    "sinon": "^2.4.1",
    "chai-as-promised": "^7.1.1",
    "chai-things": "^0.2.0",
    "karma": "~1.7.0",
    "karma-firefox-launcher": "^1.0.0",
    "karma-script-launcher": "^1.0.0",
    "karma-coverage": "^1.0.0",
    "karma-chrome-launcher": "^2.0.0",
    "karma-phantomjs-launcher": "~1.0.0",
    "karma-spec-reporter": "~0.0.20",
    "karma-sourcemap-loader": "~0.3.7",
    "sinon-chai": "^2.8.0",
    "mocha": "^3.0.2",
    "jasmine-core": "^2.3.4",
    "karma-jasmine": "^1.0.2",
    "jasmine-spec-reporter": "^4.1.1",
    "phantomjs-prebuilt": "^2.1.4",
    "proxyquire": "^1.0.1",
    "strip-ansi": "^4.0.0",
    "supertest": "^3.0.0"
  },
  "engines": {
    "node": "^6.2.2",
    "npm": "^3.9.5"
  },
  "scripts": {
    "test": "gulp test",
    "update-webdriver": "node node_modules/protractor/bin/webdriver-manager update",
    "start": "node server"
  },
  "private": true
}

The webpacke.make.json file:

'use strict';
/*eslint-env node*/
var webpack = require('webpack');
var autoprefixer = require('autoprefixer');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var HtmlWebpackHarddiskPlugin = require('html-webpack-harddisk-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin;
var fs = require('fs');
var path = require('path');
var ForkCheckerPlugin = require('awesome-typescript-loader').ForkCheckerPlugin;

module.exports = function makeWebpackConfig(options) {
    /**
     * Environment type
     * BUILD is for generating minified builds
     * TEST is for generating test builds
     */
    var BUILD = !!options.BUILD;
    var TEST = !!options.TEST;
    var E2E = !!options.E2E;
    var DEV = !!options.DEV;

    /**
     * Config
     * Reference: http://webpack.github.io/docs/configuration.html
     * This is the object where all configuration gets set
     */
    var config = {};

    /**
     * Entry
     * Reference: http://webpack.github.io/docs/configuration.html#entry
     * Should be an empty object if it's generating a test build
     * Karma will set this when it's a test build
     */
    if(TEST) {
        config.entry = {};
    } else {
        config.entry = {
            app: './client/app/app.js',
            polyfills: './client/polyfills.js',
            vendor: [
                'angular',
                'angular-animate',
                'angular-aria',
                'angular-cookies',
                'angular-resource',

                'angular-sanitize',


                'angular-ui-router',
                'lodash'
            ]
        };
    }

    /**
     * Output
     * Reference: http://webpack.github.io/docs/configuration.html#output
     * Should be an empty object if it's generating a test build
     * Karma will handle setting it up for you when it's a test build
     */
    if(TEST) {
        config.output = {};
    } else {
        config.output = {
            // Absolute output directory
            path: BUILD ? path.join(__dirname, '/dist/client/') : path.join(__dirname, '/.tmp/'),

            // Output path from the view of the page
            // Uses webpack-dev-server in development
            publicPath: BUILD || DEV || E2E ? '/' : `http://localhost:${8080}/`,
            //publicPath: BUILD ? '/' : 'http://localhost:' + env.port + '/',

            // Filename for entry points
            // Only adds hash in build mode
            filename: BUILD ? '[name].[hash].js' : '[name].bundle.js',

            // Filename for non-entry points
            // Only adds hash in build mode
            chunkFilename: BUILD ? '[name].[hash].js' : '[name].bundle.js'
        };
    }



    if(TEST) {
        config.resolve = {
            modulesDirectories: [
                'node_modules'
            ],
            extensions: ['', '.js', '.ts']
        };
    }

    /**
     * Devtool
     * Reference: http://webpack.github.io/docs/configuration.html#devtool
     * Type of sourcemap to use per build type
     */
    if(TEST) {
        config.devtool = 'inline-source-map';
    } else if(BUILD || DEV) {
        config.devtool = 'source-map';
    } else {
        config.devtool = 'eval';
    }

    /**
     * Loaders
     * Reference: http://webpack.github.io/docs/configuration.html#module-loaders
     * List: http://webpack.github.io/docs/list-of-loaders.html
     * This handles most of the magic responsible for converting modules
     */

    config.sassLoader = {
        outputStyle: 'compressed',
        precision: 10,
        sourceComments: false
    };

    config.babel = {
        shouldPrintComment(commentContents) {
            // keep `/*@ngInject*/`
            return /@ngInject/.test(commentContents);
        }
    }

    // Initialize module
    config.module = {
        preLoaders: [],
        loaders: [{
            // JS LOADER
            // Reference: https://github.com/babel/babel-loader
            // Transpile .js files using babel-loader
            // Compiles ES6 and ES7 into ES5 code
            test: /\.js$/,
            loader: 'babel',
            include: [
                path.resolve(__dirname, 'client/'),
                path.resolve(__dirname, 'node_modules/lodash-es/')
            ]
        }, {
            // TS LOADER
            // Reference: https://github.com/s-panferov/awesome-typescript-loader
            // Transpile .ts files using awesome-typescript-loader
            test: /\.ts$/,
            loader: 'awesome-typescript-loader',
            query: {
                tsconfig: path.resolve(__dirname, 'tsconfig.client.json')
            },
            include: [
                path.resolve(__dirname, 'client/')
            ]
        }, {
            // ASSET LOADER
            // Reference: https://github.com/webpack/file-loader
            // Copy png, jpg, jpeg, gif, svg, woff, woff2, ttf, eot files to output
            // Rename the file using the asset hash
            // Pass along the updated reference to your code
            // You can add here any file extension you want to get copied to your output
            test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)([\?]?.*)$/,
            loader: 'file'
        }, {
            // Pug HTML LOADER
            // Reference: https://github.com/willyelm/pug-html-loader
            // Allow loading Pug throw js
            test: /\.(jade|pug)$/,
            loaders: ['pug-html']
        }, {

            // CSS LOADER
            // Reference: https://github.com/webpack/css-loader
            // Allow loading css through js
            //
            // Reference: https://github.com/postcss/postcss-loader
            // Postprocess your css with PostCSS plugins
            test: /\.css$/,
            loader: !TEST
                // Reference: https://github.com/webpack/extract-text-webpack-plugin
                // Extract css files in production builds
                //
                // Reference: https://github.com/webpack/style-loader
                // Use style-loader in development for hot-loading
                ? ExtractTextPlugin.extract('style', 'css!postcss')
                // Reference: https://github.com/webpack/null-loader
                // Skip loading css in test mode
                : 'null'
        }, {
            // SASS LOADER
            // Reference: https://github.com/jtangelder/sass-loader
            test: /\.(scss|sass)$/,
            loaders: ['style', 'css', 'sass'],
            include: [
                path.resolve(__dirname, 'node_modules/bootstrap-sass/assets/stylesheets/*.scss'),
                path.resolve(__dirname, 'client/app/app.scss')
            ]


        }]
    };

    config.module.postLoaders = [{
        test: /\.js$/,
        loader: 'ng-annotate?single_quotes'
    }];

    // ISPARTA INSTRUMENTER LOADER
    // Reference: https://github.com/ColCh/isparta-instrumenter-loader
    // Instrument JS files with Isparta for subsequent code coverage reporting
    // Skips node_modules and spec files
    if(TEST) {
        config.module.preLoaders.push({
            //delays coverage til after tests are run, fixing transpiled source coverage error
            test: /\.js$/,
            exclude: /(node_modules|spec\.js|mock\.js)/,
            loader: 'isparta-instrumenter',
            query: {
                babel: {
                    // optional: ['runtime', 'es7.classProperties', 'es7.decorators']
                }
            }
        });
    }


    /**
     * PostCSS
     * Reference: https://github.com/postcss/autoprefixer-core
     * Add vendor prefixes to your css
     */
    config.postcss = [
        autoprefixer({
            browsers: ['last 2 version']
        })
    ];

    /**
     * Plugins
     * Reference: http://webpack.github.io/docs/configuration.html#plugins
     * List: http://webpack.github.io/docs/list-of-plugins.html
     */
    config.plugins = [
        /*
         * Plugin: ForkCheckerPlugin
         * Description: Do type checking in a separate process, so webpack don't need to wait.
         *
         * See: https://github.com/s-panferov/awesome-typescript-loader#forkchecker-boolean-defaultfalse
         */
        new ForkCheckerPlugin(),

        // Reference: https://github.com/webpack/extract-text-webpack-plugin
        // Extract css files
        // Disabled when in test mode or not in build mode
        new ExtractTextPlugin('[name].[hash].css', {
            disable: !BUILD || TEST
        })
    ];

    if(!TEST) {
        config.plugins.push(new CommonsChunkPlugin({
            name: 'vendor',

            // filename: "vendor.js"
            // (Give the chunk a different name)

            minChunks: Infinity
            // (with more entries, this ensures that no other module
            //  goes into the vendor chunk)
        }));
    }

    // Skip rendering index.html in test mode
    // Reference: https://github.com/ampedandwired/html-webpack-plugin
    // Render index.html
    let htmlConfig = {
        template: 'client/_index.html',
        filename: '../client/index.html',
        alwaysWriteToDisk: true
    }
    config.plugins.push(
      new HtmlWebpackPlugin(htmlConfig),
      new HtmlWebpackHarddiskPlugin()
    );

    // Add build specific plugins
    if(BUILD) {
        config.plugins.push(
            // Reference: http://webpack.github.io/docs/list-of-plugins.html#noerrorsplugin
            // Only emit files when there are no errors
            new webpack.NoErrorsPlugin(),

            // Reference: http://webpack.github.io/docs/list-of-plugins.html#dedupeplugin
            // Dedupe modules in the output
            new webpack.optimize.DedupePlugin(),

            // Reference: http://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin
            // Minify all javascript, switch loaders to minimizing mode
            new webpack.optimize.UglifyJsPlugin({
                mangle: false,
                output: {
                    comments: false
                },
                compress: {
                    warnings: false
                }
            }),

            // Reference: https://webpack.github.io/docs/list-of-plugins.html#defineplugin
            // Define free global variables
            new webpack.DefinePlugin({
                'process.env': {
                    NODE_ENV: '"production"'
                }
            })
        );
    }

    if(DEV) {
        config.plugins.push(
            // Reference: https://webpack.github.io/docs/list-of-plugins.html#defineplugin
            // Define free global variables
            new webpack.DefinePlugin({
                'process.env': {
                    NODE_ENV: '"development"'
                }
            })
        );
    }

    config.cache = DEV;

    if(TEST) {
        config.stats = {
            colors: true,
            reasons: true
        };
        config.debug = false;
    }

    /**
     * Dev server configuration
     * Reference: http://webpack.github.io/docs/configuration.html#devserver
     * Reference: http://webpack.github.io/docs/webpack-dev-server.html
     */
    config.devServer = {
        contentBase: './client/',
        stats: {
            modules: false,
            cached: false,
            colors: true,
            chunk: false
        }
    };

    config.node = {
        global: 'window',
        process: true,
        crypto: 'empty',
        clearImmediate: false,
        setImmediate: false
    };

    return config;
};

I've tried downgrading Webpack to version 1.15.0, removing the node_modules folder and installing it again, but I still get the same error.

What is it going wrong?

Update:

Just in case it helps, when I do npm install, the Webpack module is shown like this UNMET PEER DEPENDENCY [email protected].

I get the following error when downgrading awesome-typescript-loader to 2.2.4:

WebpackOptionsValidationError(webpackOptionsValidationErrors);
        ^
WebpackOptionsValidationError: Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.
 - configuration has an unknown property 'postcss'. These properties are valid:
   object { amd?, bail?, cache?, context?, dependencies?, devServer?, devtool?, entry, externals?, loader?, module?, name?, node?, output?, performance?, plugins?, profile?, recordsInputPath?, recordsOutputPath?, recordsPath?, resolve?, resolveLoader?, stats?, target?, watch?, watchOptions? }
   For typos: please correct them.
   For loader options: webpack 2 no longer allows custom properties in configuration.
     Loaders should be updated to allow passing options via loader options in module.rules.
     Until loaders are updated one can use the LoaderOptionsPlugin to pass these options to the loader:
     plugins: [
       new webpack.LoaderOptionsPlugin({
         // test: /\.xxx$/, // may apply this only for some modules
         options: {
           postcss: ...
         }
       })
     ]
 - configuration.module has an unknown property 'postLoaders'. These properties are valid:
   object { exprContextCritical?, exprContextRecursive?, exprContextRegExp?, exprContextRequest?, loaders?, noParse?, rules?, unknownContextCritical?, unknownContextRecursive?, unknownContextRegExp?, unknownContextRequest?, unsafeCache?, wrappedContextCritical?, wrappedContextRecursive?, wrappedContextRegExp?, strictExportPresence?, strictThisContextOnImports? }
   Options affecting the normal modules (`NormalModuleFactory`).
 - configuration.node should be one of these:
   false | object { Buffer?, __dirname?, __filename?, console?, global?, process?, ... }
   Include polyfills or mocks for various node stuff.
   Details:
    * configuration.node should be false
    * configuration.node.global should be a boolean.

Update 2:

It seems downgrading [email protected] solved my problem. But now, I am getting another error:

/home/nsanz/Documentos/git/tachology/node_modules/extract-text-webpack-plugin/node_modules/async/dist/async.js:1003
        iteratee(coll[index], index, onlyOnce(iteratorCallback));
        ^
TypeError: chunk.sortModules is not a function

Update 3:

After installing [email protected], I get this new error:

/home/nsanz/Documentos/git/tachology/node_modules/extract-text-webpack-plugin/index.js:187
        throw new Error("Breaking change: extract now only takes a single argument. Either an options " +
        ^
Error: Breaking change: extract now only takes a single argument. Either an options object *or* the loader(s).
Example: if your old code looked like this:
    ExtractTextPlugin.extract('style-loader', 'css-loader')

You would change it to:
    ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader' })

The available options are:
    use: string | object | loader[]
    fallback: string | object | loader[]
    publicPath: string

Update 4:

After fixing another ExtractTextPlugin error, I receive a new error (I find this one through different pug files):

ERROR in ./client/app/main/main.pug
Module parse failed: /home/nsanz/Documentos/git/tachology/node_modules/pug-html-loader/lib/index.js!/home/nsanz/Documentos/git/tachology/client/app/main/main.pug Unexpected token (1:0)
You may need an appropriate loader to handle this file type.
| <div class="uk-section uk-section-default main"><div class="uk-container" ng-show="$ctrl.Auth.hasRoleSync('driver')"><div class="uk-flex"><div class="uk-width-1-3"><div class="test-upload uk-placeholder uk-text-center"><span uk-icon="icon: cloud-upload; ratio: 3"></span><br/><span class="uk-text-middle uk-margin-small-left uk-margin-small-right">Arrastra los ficheros o</span><div class="uk-form-custom"><input type="file" multiple="multiple" enctype="multipart/form-data" ng-model="$ctrl.upload"/><span class="uk-link">pulsa aquí</span></div></div><progress class="uk-progress" id="progressbar" value="0" max="100" hidden="hidden"></progress></div><div class="uk-width-2-3 uk-margin-left"><table class="uk-table uk-table-hover uk-table-striped uk-table-small uk-table-justify" id="files"><thead><tr><th class="uk-table-shrink">#</th><th class="uk-table-expand">Nombre del Fichero</th><th class="uk-table-expand"><form class="uk-search uk-search-default uk-width-1-1"><span class="uk-search-icon"></span><input class="uk-search-input" type="search" placeholder="Buscar..." ng-model="search.filename"/></form></th></tr></thead><tbody><tr class="uk-text-center empty-msg" ng-hide="$ctrl.fileList.length !== 0"><td colspan="3">No se encuentra ningún fichero,&nbsp;<a href="signup">subir uno nuevo.</a></td></tr><tr ng-repeat="file in $ctrl.fileList | filter:search"><td>{{$index + 1}}</td><td class="uk-table-link"><a class="uk-link-reset" ng-click="$ctrl.parseFile(file)">{{file.filename}}</a></td><td class="uk-text-right"><i class="uk-icon-link download" uk-icon="icon: cloud-download" ng-click="$ctrl.downloadFile(file)"></i><i class="uk-icon-link uk-margin-left trash" uk-icon="icon: trash" ng-click="$ctrl.deleteFile(file)"></i></td></tr></tbody></table></div></div></div><div class="uk-container" ng-hide="$ctrl.Auth.hasRoleSync('driver')"><div class="uk-flex uk-flex-around uk-flex-stretch"><div class="uk-width-1-3 uk-card uk-card-default uk-card-hover uk-card-body main-button" ng-click="$ctrl.go('/conductores')"><div class="uk-text-center"><span uk-icon="icon: users; ratio: 4"></span><h3 class="uk-card-title">CONDUCTORES</h3></div></div><div class="uk-width-1-3 uk-card uk-card-default uk-card-hover uk-card-body uk-margin-left main-button" ng-click="$ctrl.go('/vehiculos')"><div class="uk-text-center"><span class="fa fa-car"></span><h3 class="uk-card-title">VEHÍCULOS</h3></div></div><div class="uk-width-1-3 uk-card uk-card-default uk-card-hover uk-card-body uk-margin-left main-button" ng-click="$ctrl.go('/informes')"><div class="uk-text-center"><span uk-icon="icon: list; ratio: 4"></span><h3 class="uk-card-title">INFORMES</h3></div></div></div></div></div>
 @ ./client/app/main/main.component.js 140:12-33
 @ ./client/app/app.js


Solution 1:[1]

In your devDependencies, try downgrading this:

awesome-typescript-loader": "3.2.1"

to this:

awesome-typescript-loader": "2.2.4"

If it still doesn't work, we'll find another solution.


EDIT

After the last question update, this is my advice. Delete the next line in webpack.make.json:

 config.plugins = [
        /*...*/
        new ForkCheckerPlugin(), // <-- Delete this line

The reason for this is that it seems that forking is built-in for Webpack >= 3.0.0


EDIT 2

Seems like Webpack 3.4.1 is causing you troubles, because you are relying on some old dependencies. Do the following:

npm uninstall webpack --save-dev

then:

npm install [email protected] --save-dev

Hopefully this will work now! If it still doesn't work, try re-incorporating the new ForkCheckerPlugin() statement (this time using webpack 2.1.0)


EDIT 3

It seems to work now with webpack 2.1.0-beta.22, but you got another error.

This error happened because extract-text-webpack-plugin is not of the same major version as webpack is (3.x.x vs 2.x.x). Do this:

npm uninstall --save-dev extract-text-webpack-plugin

then this:

npm install --save-dev [email protected]

EDIT 4

This new error is a bit easier to solve. It comes explained in your error logs. In your webpack.make.js change the line:

ExtractTextPlugin.extract('style', 'css!postcss')

To:

ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader' })

EDIT 5

Things are getting interesting. I'd recommend changing this (inside of webpack.make.js):

}, {
    // Pug HTML LOADER
    // Reference: https://github.com/willyelm/pug-html-loader
    // Allow loading Pug throw js
    test: /\.(jade|pug)$/,
    loaders: ['pug-html']
}, {

to this:

}, {
    // Pug HTML LOADER
    // Reference: https://github.com/willyelm/pug-html-loader
    // Allow loading Pug throw js
    test: /\.(jade|pug)$/,
    loaders: ['pug-html-loader']
}, {

Solution 2:[2]

I also encountered the same error. My steps to resolve the issue:

  1. I deleted the whole repo
  2. downloaded the code again
  3. npm install

Issue resolved for me

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Sanket Sirotiya