Danie Clawson
Danie Clawson

Reputation: 183

How to rollup multiple directories separately with one output

So, I have a directory:

mods/
-core/
--index.js
--scripts/
---lots of stuff imported by core/index

This works with typical rollup fashion if you want to rollup to for example mods/core/index.min.js

But I have many of these mods/**/ directories and I want to take advantage of the fact that they are rollup'd into iifes. Each mods/**/index.js will, rather than export, assign to a global variable that we presume is provided:

mods/core/index.js

import ui from './scripts/ui/'
global.ui = ui

mods/someMod/scripts/moddedClass.js

export default class moddedClass extends global.ui.something { /* some functionality extension */}

mods/someMod/index.js

import moddedClass from './scripts/moddedClass'
global.ui.something = moddedClass

So hopefully you can see how each mod directory can be rollup'd in typical fashion but, I need to then put the actual iifes inside another one so that:

mods/compiled.js

(function compiled() {
  const global = {};

  (function core() {
    //typical rollup iife
  })();

  (function someMod() {
    //typical rollup iife
  })();

  //a footer like return global or global.init()
})();

Any help towards this end would be greatly appreciated. The simplest possible answer, I think, is how I can simply get a string value for each mod's iife instead of rollup writing it to a file.

At that point I could just iterate the /mods/ directory, in an order specified by some modlist.json or something, and call rollup on each /mod/index.js, then build the outer iife myself from strings.

However, I suppose this would not be a full solution for sourcemapping? Or can multiple inline sourcemaps be included? With source mapping in mind, I wonder if another build step might be necessary, where each mod is transpiled before this system even gets to it.

Upvotes: 2

Views: 5403

Answers (2)

Danie Clawson
Danie Clawson

Reputation: 183

Okay so the way I ended up solving this was using source-map-concat

It basically does what I described, right out of the box. The only thing I had to do was to asynchronously iterate the mod directory and rollup each mod, before passing the results to source-map-concat, since rollup.rollup returns a Promise.

I also ended up wanting in-line sourcemaps so that the code can be directly injected rather than written to a file, so I used convert-source-map for that.

The only issue left to solve is sub-source mapping. Sorcery would work great for that, if I was generating files, but I would like to keep it as string sources. For now it will at least show me what mod an error came from, but not the sub-file it came from. If anyone has info on how to do a sorcery-style operation on strings let me know.

Here's the relevant final code from my file:

const rollup  = require("rollup")
const concat  = require("source-map-concat")
const convert = require("convert-source-map")

const fs   = require("fs")
const path = require("path")

const modsPath = path.join(__dirname, "mods")

const getNames = _ => JSON.parse(fs.readFileSync(path.join(modsPath, "loadList.json"), "utf8"))

const wrap = (node, mod) => {
  node.prepend("\n// File: " + mod.source + "\n")
}

const rolls = {}
const bundles = {}

const rollupMod = (modName, after) => {
  let dir = path.join(modsPath, modName),
      file = path.join(dir, "index.js")

  rollup.rollup({
    entry: file,
    external: "G",
    plugins: []
  }).then(bundle => {
    rolls[modName] = bundle.generate({
      format: "iife",
      moduleName: modName,
      exports: "none",
      useStrict: false,
      sourceMap: true
    })

    after()
  })
}

const rollupMods = after => {
  let names = getNames(), i = 0,
      rollNext = _ => rollupMod(names[i++], _ => i < names.length - 1? rollNext() : after())

  rollNext()
}

const bundleCode = after => {
  rollupMods(_ => {
    let mods = concat(getNames().map(modName => {
      let mod = rolls[modName]

      return {
        source: path.join(modsPath, modName),
        code: mod.code,
        map: mod.map
      }
    }), {
      delimiter: "\n",
      process: wrap
    })

    mods.prepend("(function(){\n")
    mods.add("\n})();")

    let result = mods.toStringWithSourceMap({
      file: path.basename('.')
    })

    bundles.code = result.code + "\n" + convert.fromObject(result.map).toComment()

    after(bundles.code)
  })
}

exports.bundleCode = bundleCode

Upvotes: 1

Yi Kai
Yi Kai

Reputation: 640

Use rollup's bundle.generate api to generate multiple iifes and write them into one file using fs.appendFile.

For the sourcemaps you can use this module(it's from the same author of rollup) https://github.com/rich-harris/sorcery

Upvotes: 1

Related Questions