5

I have a bunch of stuff in node_modules that, from what I can tell, all ends up in vendor.js when I build my Ionic3 project. For simplicity's sake, lets say I have the following folders in node_modules: abc, xyz, uvw, and qrs. Lets say further that abc and xyz are public libraries but uvw and qrs are private libraries. As such, I would like to end up not with a single vendor.js that includes all four libraries. Rather, I would like to end up with a vendor.js that includes abc and xyz, and a private.js that includes uvw and qrs.

How do I alter the configuration files in my Ionic3 project to achieve that outcome? Ideally I would only have to name uvw and qrs in the configuration and have the default behavior of vendor.js being generated for 'everything else' in node_modules.

UPDATE For reference, Ionic 3.9.2 uses Webpack 3.10.0, and the default Ionic webpack config looks like the following. I really only care about the production build doing the behavior I describe above.

/*
 * The webpack config exports an object that has a valid webpack configuration
 * For each environment name. By default, there are two Ionic environments:
 * "dev" and "prod". As such, the webpack.config.js exports a dictionary object
 * with "keys" for "dev" and "prod", where the value is a valid webpack configuration
 * For details on configuring webpack, see their documentation here
 * https://webpack.js.org/configuration/
 */

var path = require('path');
var webpack = require('webpack');
var ionicWebpackFactory = require(process.env.IONIC_WEBPACK_FACTORY);

var ModuleConcatPlugin = require('webpack/lib/optimize/ModuleConcatenationPlugin');
var PurifyPlugin = require('@angular-devkit/build-optimizer').PurifyPlugin;

var optimizedProdLoaders = [
  {
    test: /\.json$/,
    loader: 'json-loader'
  },
  {
    test: /\.js$/,
    loader: [
      {
        loader: process.env.IONIC_CACHE_LOADER
      },

      {
        loader: '@angular-devkit/build-optimizer/webpack-loader',
        options: {
          sourceMap: true
        }
      },
    ]
  },
  {
    test: /\.ts$/,
    loader: [
      {
        loader: process.env.IONIC_CACHE_LOADER
      },

      {
        loader: '@angular-devkit/build-optimizer/webpack-loader',
        options: {
          sourceMap: true
        }
      },

      {
        loader: process.env.IONIC_WEBPACK_LOADER
      }
    ]
  }
];

function getProdLoaders() {
  if (process.env.IONIC_OPTIMIZE_JS === 'true') {
    return optimizedProdLoaders;
  }
  return devConfig.module.loaders;
}

var devConfig = {
  entry: process.env.IONIC_APP_ENTRY_POINT,
  output: {
    path: '{{BUILD}}',
    publicPath: 'build/',
    filename: '[name].js',
    devtoolModuleFilenameTemplate: ionicWebpackFactory.getSourceMapperFunction(),
  },
  devtool: process.env.IONIC_SOURCE_MAP_TYPE,

  resolve: {
    extensions: ['.ts', '.js', '.json'],
    modules: [path.resolve('node_modules')]
  },

  module: {
    loaders: [
      {
        test: /\.json$/,
        loader: 'json-loader'
      },
      {
        test: /\.ts$/,
        loader: process.env.IONIC_WEBPACK_LOADER
      }
    ]
  },

  plugins: [
    ionicWebpackFactory.getIonicEnvironmentPlugin(),
    ionicWebpackFactory.getCommonChunksPlugin()
  ],

  // Some libraries import Node modules but don't use them in the browser.
  // Tell Webpack to provide empty mocks for them so importing them works.
  node: {
    fs: 'empty',
    net: 'empty',
    tls: 'empty'
  }
};

var prodConfig = {
  entry: process.env.IONIC_APP_ENTRY_POINT,
  output: {
    path: '{{BUILD}}',
    publicPath: 'build/',
    filename: '[name].js',
    devtoolModuleFilenameTemplate: ionicWebpackFactory.getSourceMapperFunction(),
  },
  devtool: process.env.IONIC_SOURCE_MAP_TYPE,

  resolve: {
    extensions: ['.ts', '.js', '.json'],
    modules: [path.resolve('node_modules')]
  },

  module: {
    loaders: getProdLoaders()
  },

  plugins: [
    ionicWebpackFactory.getIonicEnvironmentPlugin(),
    ionicWebpackFactory.getCommonChunksPlugin(),
    new ModuleConcatPlugin(),
    new PurifyPlugin()
  ],

  // Some libraries import Node modules but don't use them in the browser.
  // Tell Webpack to provide empty mocks for them so importing them works.
  node: {
    fs: 'empty',
    net: 'empty',
    tls: 'empty'
  }
};


module.exports = {
  dev: devConfig,
  prod: prodConfig
}
vicatcu
  • 5,407
  • 7
  • 41
  • 65
  • What is your ionic-app-scripts version? – Khurshid Ansari Apr 11 '19 at 07:45
  • @KhurshidAnsari as per the ./node_modules/@ionic/app-scripts/package.json file for my project, version is 3.1.9; and it is possible, certainly to extend the Ionic webpack config ala https://stackoverflow.com/questions/41512923/how-to-extend-default-webpack-config-in-ionic-v2 – vicatcu Apr 11 '19 at 12:53

1 Answers1

3

If you're using webpack v4, then optimization.splitChunks.cacheGroups is what you're looking for. Full doc here.

Now looks like OP want to manually pick what module goes to what bundle. This is how you can do it:

  1. Add two new cacheGroups, say optimization.splitChunks.cacheGroups.vendor and .private
  2. Set filename, enforce and test fields
cacheGroups.vendor = {
  filename: 'vendor.js',
  enforce: true,
  test: (module) => {
    const vendorList = ['abc', 'xyz']
    return vendorList.includes(module.name)
  }
}

// Similar config for `cacheGroups.private`
hackape
  • 18,643
  • 2
  • 29
  • 57
  • As it turns out, webpack version 3.10.0 goes with Ionic 3.9.2... does that change things? – vicatcu Apr 10 '19 at 00:53
  • I've updated the question with Ionic 3.9.2's default webpack config for reference. – vicatcu Apr 10 '19 at 01:33
  • is there a similar capability for webpack 3? – vicatcu Apr 12 '19 at 12:04
  • @vicatcu webpack 3 I'm not sure, I know `commonChunkPlugin` exist but not entirely sure I understand how it works. You can't even find doc for v3 on the official site now. [This](https://webpack-3.cdn.bcebos.com/plugins/commons-chunk-plugin/) is a mirror to v3 doc. – hackape Apr 12 '19 at 12:56