Search code examples
javascriptangularjswebpackwebpack-dev-serverwebpack-2

Optimal webpack.config with webpack 2 for AngularJS 1.x app?


I want to set up an Angular 1.x app from scratch using webpack 2.

I am having trouble finding the best configuration for webpack.config, with optimal entry and output for production (meaning, all code, style and templating minified and gziped with no code repetition).

My main problem is how to set up webpack.config so that it recognizes all partials within the folder structure of my project, like these:

enter image description here

My current config file, for reference (which can't see subfolders):

var HtmlWebpackPlugin = require( 'html-webpack-plugin' );
var ExtractTextPlugin = require( 'extract-text-webpack-plugin' );
var path = require( 'path' );

module.exports = {
    devServer: {
        compress: true,
        contentBase: path.join( __dirname, '/dist' ),
        open: true,
        port: 9000,
        stats: 'errors-only'
    },
    entry: './src/app.js',
    output: {
        path: path.join( __dirname, '/dist' ),
        filename: 'app.bundle.js'
    },
    module: {
        rules: [ {
            test: /\.scss$/,
            use: ExtractTextPlugin.extract( {
                fallback: 'style-loader',
                use: [
                    'css-loader',
                    'sass-loader'
                ],
                publicPath: '/dist'
            } )
        } ]
    },
    plugins: [
        new HtmlWebpackPlugin( {
            hash: true,
            minify: { collapseWhitespace: true },
            template: './src/index.html',
            title: 'Prov'
        } ),
        new ExtractTextPlugin( {
            filename: 'main.css',
            allChunks: true
        } )
    ]
};

Solution

  • Note that this isn't an exhaustive solution, as there are many optimizations one can make in the frontend, and I've kept the code snippets fairly short.

    With webpack, there are a few routes that you can take to include partials into your app.js.

    Solution 1
    You can import/require your partials within app.js as such:

    app.js

    var angular = require('angular');
    var proverbList = require('./proverb/list/proverb.list');
    // require other components
    
    // set up your app as normal
    

    This allows the app.bundle.js to include your component js files in the main bundle. You can also use html-loader to include templates in the final bundle.

    This isn't ideal, as all it does is create a large bundle.js (which doesn't leverage multiple downloads with http2 nor does it allow loading of components/files when the user explicitly requires it).

    Solution 2
    Importing partials as separate entry files into your webpack bundle:

    webpack.config.js

    const globby = require('globby');
    const sourceDir = 'src';
    var webpackentry = {
        app: `${__dirname}/src/app.js`
    };
    
    const glob = globby.sync(`${__dirname}/${sourceDir}/**/*.js`)
        .map((file)=>{
        let name = file.split('/').pop().replace('.js', '');
        webpackentry[name] = file;
    });
    
    
    const config = {
      entry: webpackentry,
      ...
    }
    

    The second solution is unorthodox but it can be useful if you wanted to split all your partials as <script> tags in your html (for example if your company/team uses that as a means to include your directive/components/controllers), or if you have an app-2.bundle.js.

    Solution 3
    Use CommonsChunkPlugin:

    webpack.config.js

    let webpackentry = {
      vendor: [
       'module1',
       'module2',
       'module3',
      ]
    }
    ...
    plugins: [
      new webpack.optimize.CommonsChunkPlugin({
        name: ['vendor'] //... add other modules
      })
    ]
    

    CommonsChunkPlugin allows webpack to scrawl through your entry files and discern common modules that are shared among them. This means that even if you are importing module1 in different files, they will be compiled only once in your final bundle.