Przemek Dabrowski
Przemek Dabrowski

Reputation: 71

How to split dynamically by directories with Webpack/SplitChunks plugin?

I'm trying to split my React code (created with create-react-app) with the splitChunks plugin in the following way :

I have following components (JSX) structure :

and I want to have following output (build) :

(other runtimes / mains are at the root of /static/js)

Another restriction is that components are loaded dynamically with

const Component = lazy(() => import(componentPath));
...
<Suspense fallback={..}>Component</suspense>

"componentPath" is determined on the fly (when a user clicks on an icon then it opens a given service).

The reason for this is that I want to include each bundle into a separate Docker image running the backend. Then each Docker image is reachable thanks to Application routing :

static/js/serviceA/  ==> js served by Docker container running service A
static/js/serviceB/  ==> js served by Docker container running service B
static/js/serviceC/  ==> js served by Docker container running service C

So far, I'v tried to:

Then I tried to use the splitChunks plugin with following :

  splitChunks: {
    chunks: 'all',
    name: function(module) {
      let serviceName = module.rawRequest ? module.rawRequest : 'default';
      serviceName = serviceName.replace('../', '').replace('./', '');
      serviceName = serviceName.split('/')[0];
      return serviceName;
    },
    cacheGroups: {
      vendors: {
        test: /[\\/]node_modules[\\/]/,
        priority: -10
      },
      default: {
        minChunks: 2,
        priority: -20,
        reuseExistingChunk: true
      },
      serviceA: {
        test: /[\\/]serviceA[\\/]/,
        priority: -10
      },
      serviceB: {
        test: /[\\/]serviceB[\\/]/,
        priority: -10
      },
      serviceC: {
        test: /[\\/]serviceC[\\/]/,
        priority: -10
      },              
    }
  },

This approach looks like working as all my services are in their own directories. But I still have some additional directories as numbers (bundle ID probably) that I would have expect to be rather included into the default.

So the question is : is my approach correct ?

Upvotes: 7

Views: 2325

Answers (1)

Anya
Anya

Reputation: 1398

I'm not sure if the following option would work for you. I had a similar problem, where I needed different folders to be outputed on different bundles.

In my case, I started with the glob solution, suggested here. Then, knowing that I needed an array of inputs for each desired output, I came up with this:

const path = require('path');
const glob = require('glob');

const plugins = [...];

module.exports = {
    entry: glob.sync('./src/**/*.js').reduce((acc, item) => {
        const path = item.split('/');
        path.pop();
        const rootFolder = path[2] ? `${path[0]}/${path[2]}` : path[0];
        if (acc[rootFolder]) {
            acc[rootFolder].push(item);
        } else {
            acc[rootFolder] = [item];
        }
        return acc;
    }, {}),
    output: {
        filename: '[name]/main.js',
        path: path.resolve(__dirname, 'dist'),
    },
  module: { ... },
    plugins,
};

This is a simplified version of my config and it could probably be improved, but it works fine for my needs. :)

More info on glob library: https://github.com/isaacs/node-glob

Upvotes: 1

Related Questions