13
votes

I have an Angular application that is currently built via Webpack into one large bundle, containing all dependencies and app code in a single file. I am trying to split the code into two bundles, one bundle with all of my dependencies, and another with all of my application code.

I have the following webpack.config.js:

var webpack = require('webpack');
var path = require('path');

var definePlugin = new webpack.DefinePlugin({
    'process.env': {
        NODE_ENV: `"${process.env.NODE_ENV}"`
    }
});

var SRC = path.resolve(__dirname, 'src/main/client');
var APP = path.resolve(SRC, 'app/index.js');
var DEST = path.resolve(__dirname, 'target/webapp/dist');

module.exports = {
    entry: {
        vendor: [
            'angular',
            'angular-animate',
            'moment',
            'angular-moment',
            'angular-translate',
            'angular-ui-bootstrap',
            'angular-ui-router',
            'lodash'
        ],
        app: APP
    },
    plugins: [
        new webpack.ProvidePlugin({
            _: 'lodash',
            angular: 'angular',
            angularMoment: 'angular-moment',
            angularTranslate: 'angular-translate',
            moment: 'moment',
            ngAnimate: 'angular-animate',
            uibootstrap: 'angular-ui-bootstrap',
            uirouter: 'angular-ui-router'
        }),
        new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.bundle.js'),
        definePlugin
    ],
    output: {
        path: DEST,
        filename: 'bundle.js',
        publicPath: '/',
        hash: true
    },
    module: {
        preLoaders: [],
        loaders: [
            { test: /\.html$/, loaders: ['html'] },
            { test: /\.css$/, loaders: ['style', 'css'] },
            { test: /\.scss$/, loaders: ['style', 'css', 'sass'] },
            {
                test: /\.js$/,
                exclude: /(node_modules|bower_components)/,
                loaders: ['ng-annotate', 'babel?presets[]=es2015', 'eslint']
            },
            {
                test: /\.(ttf|eot|svg|woff2?)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
                loader: 'file'
            }
        ]
    },
    sassLoader: {
        includePaths: [path.resolve(__dirname, './node_modules')]
    }
};

This produces two bundles, one with only the dependencies and one with only the application code. However, when I attempt to load the application, I get: Uncaught TypeError: angular.module is not a function which is traced back to angular-moment.js within the vendor.bundle.js. In other words, angular isn't accessible to other modules that need to be loaded in the vendor.bundle.js file. However, I'm not sure how to make these dependencies visible to each other.

2

2 Answers

1
votes

To answer the question in the headline of the original post, Angular 1 is not working nicely with webpack without a shim (see https://github.com/webpack/webpack/issues/2049). Try this webpack loader config:

module: {
    loaders: [
        /*
         * Necessary to be able to use angular 1 with webpack as explained in https://github.com/webpack/webpack/issues/2049
         */
        {
            test: require.resolve('angular'),
            loader: 'exports?window.angular'
        },
    ]
},
plugins: [
    new webpack.ProvidePlugin({
        'angular': 'angular',
    }),
],

This should initialize the angular object properly instead of the default action of setting it to an empty object (which does not have a property named module).

0
votes

Following should move all the scripts not in src folder to vendor chunk.

const path = require('path');
const projectRoot = path.resolve('./');

      new webpack.optimize.CommonsChunkPlugin({
        name: 'vendor',
        minChunks: (module) => module.resource && module.resource.indexOf(path.join(projectRoot, 'src')) === -1,
      }),