Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multi-tenant JavaScript application with tenant specific bundles

I'm investigating ways to build a multi-tenant JS web application. I was hoping to be able to import files as follows.

import Thing from './thing'

I want to configure webpack/babel/a tool to look for a file specific to the tenant first, i.e. thing.tenant.js, then falling back to thing.js.

A similar approach to platform-specific code in react-native, except the tenant, would be supplied as part of the build and end up with its own bundle bundle.tenant.js.

Does anyone know of a way to do this?

like image 227
benembery Avatar asked Nov 28 '17 13:11

benembery


1 Answers

So we've finally got a solution in place for this. We return an array of webpack configurations in our config file.

Using webpack merge we combined our shared configuration with a tenant-specific configuration. We made a method that generates these to keep the configuration more succinct.

For each tenant we custom extensions array in resolve to get it to first look for a file with the tenant extension as follows.

  {
    resolve: {
      extensions: [`.${tenant}.js`, ".js"]
    }
  }

This means when our code imported a module like so

import Header from './header'

Webpack would first look for header.{tenant}.js and then ask for tenant.js.

We applied the same principle to our sass imports however, we are currently a forked version of sass-loader to achieve the same thing with sass.

module: {
    rules: [
        {
            test: /\.scss$/,

            use: [
                // Loaders omitted for brevity...
                {
                    loader: "sass-loader",
                    options: {
                        sourceMap: true,
                        extensions: [`.${tenant}.scss`, ".scss", ".sass", ".css"],
                    }
                }
            ]
        }
   ]
}

This gave us 90% of what we needed. But build times were slow as multiple configurations means multiple webpack runs. To mitigate this we started using the webpack hard source plugin which made the build time much more acceptable. The following configuration is added to the plugins configuration.

new HardSourceWebpackPlugin({
    configHash: (webpackConfig) => {
            const config = {
                webpackConfig,
                // our custom config merged in here...
            }
            return require('node-object-hash')({
                sort: false
            }).hash(config);
    },
})
like image 88
benembery Avatar answered Sep 29 '22 19:09

benembery