First of all thank you for rollup, I think it's awesome tool and love using it.
I have 2 scenarios (which are a bit connected) and wanted your opinion on how I should solve them. I am not sure it's something that rollup should be solving, but I think it's quite a realistic scenario that more people will run into, and it's nice to know a way to solve it (even by creating a very custom plugin)
Dynamic modules
Lets assume that there is a form, where the user registers animals. He selects the animal type, and then he adds several info, some of which are common for all animals, while some are for specific types.
It's obvious this is modeled by something like:
class Dog extends Animal
class Cat extends Animal
// etc.
When receiving the form data, I would like to do something like this (which is doable in node, since modules are not statically analyzed)
function processForm(data) {
var animal = new require('../../models/' + data.animalType.toLowerCase()).Animal;
animal.color = data.color;
animal.save();
// whatever
}
The example only scratches the surface, but I hope you understand the use case.
Now I understand that rollup cant handle this, since it can't know what data.animalType will evaluate to.
What I am thinking is to actually always bundle all the animal models. And my question is this:
Isomorphic JS
Again I will simplify a bit things, but in my codebase, we have folders structured like this:
Before rollup, utils/index.js looked something like this:
var utils = {};
if (isClientSide()) utils = require('./client');
else if (isServerSide()) utils = require('./server');
exports = utils;
And this allowed for usage like this: var utils = require('./utils'), anywhere in the code, no matter if you where server or client side.
In a very simple scenario, with rollup i could require both client and server and let tree shaking take care of the rest. However, there are much more complex scenarios that don't allow that. For example:
var utils = require('./utils')
If (isServerSide()) utils.doSomethingServerSide()
which of course will bundle server side stuff for the client and can have heavy consequences.
My current idea is to create a plugin that ignores modules with specific naming patters. So maybe I can ignore all modules that end with *-server.js. Any other ideas are more than welcome.
For the first case, in ES modules you would have to do something like this:
import Dog from '../../models/Dog.js';
import Cat from '../../models/Cat.js';
...
const types = { Dog, Cat, ... };
function processForm(data) {
var animal = new types[data.animalType.toLowerCase()].Animal;
animal.color = data.color;
animal.save();
// whatever
}
Eventually there'll be some consensus on how dynamic asynchronous module loading will work, and at that point Rollup will presumably introduce some way of handling it like so...
async function processForm(data) {
const Type = await System.import(`../../models/${data.animalType.toLowerCase()}.js`);
var animal = Type.Animal;
animal.color = data.color;
animal.save();
// whatever
}
...(note processForm is now async) – but in the meantime, that's how you'd include them in the bundle.
For the second case, generating separate client/server bundles is probably the way to go. I haven't tried this approach, but something like this might work, using the --environment flag (see CLI documentation) and rollup-plugin-replace:
// src/utils/index.js
import utils from './TARGET.js';
export default utils;
import replace from 'rollup-plugin-replace';
const TARGET = process.env.TARGET;
// rollup.config.js
export default {
entry: 'src/index.js',
dest: `bundle-${TARGET}.js`,
format: TARGET === 'server' ? 'cjs' : 'iife',
plugins: [
replace({ TARGET })
]
};
rollup -c --environment TARGET=server
rollup -c --environment TARGET=client
Most helpful comment
For the first case, in ES modules you would have to do something like this:
Eventually there'll be some consensus on how dynamic asynchronous module loading will work, and at that point Rollup will presumably introduce some way of handling it like so...
...(note
processFormis now async) – but in the meantime, that's how you'd include them in the bundle.For the second case, generating separate client/server bundles is probably the way to go. I haven't tried this approach, but something like this might work, using the
--environmentflag (see CLI documentation) and rollup-plugin-replace: