DEV Community

Cover image for Replacing JS Imports with Rollup
Ben Greenier
Ben Greenier

Posted on

Replacing JS Imports with Rollup

Hi! I’m Ben Greenier — I’m an engineer at Microsoft working to create awesome open source projects with our partners. We get to create software to help solve really tricky problems, and share our stories as we go. This means that as part of my job I get to play with lots of new technologies, learn how to use them, and help other folks do the same.

Lately I've been working on a browser app called Overlayed - it helps broadcasters interact with their viewers in new ways, using overlays. Under the hood, Overlayed is powered by user-defined modules (using ESM), that export React components. You can learn more about that, here - but it's not what this post is about.

Previously, I wrote about accessing globals from within modules which is a precursor to what I'd like to share today - Replacing imports with rollup. Rollup is a JS bundler, meaning it's job is to combine some code, along with all of it's dependencies, into one file. Let's take a look at a pattern I discovered (not invented) for replacing dependencies with alternate versions when Rollup runs.

First, we need to define a valid replacement. Let's use React as an example, and build on our example from the last post. We can define a React replacement like this:

export default globalThis.React
Enter fullscreen mode Exit fullscreen mode

Which will just provide a default export that's value is set to that of the globalThis React variable. It only makes sense to do this if you know React will be provided in the global scope - Like in a browser where React is included as a script dependency, that loads before your script.

We can then use Rollup and Babel to rewrite any React imports that look like import React from 'react' to import React from "our-replacement.js", effectively. This makes use of babel-plugin-module-resolver. You might be wondering why Babel is introduced here. It's a great question, that I don't have an answer to. The build logic I modified to get this working uses it, presumably for a great reason. Given that I'm still learning, I've stuck with it to minimize variables.

Here's the babel configuration addition that makes this possible:

Note: You may need to modify some other configuration, depending on your setup.

{
  "plugins": [
    ["module-resolver", {
      "alias": {
        "react": "./react-shim.js",
      }
    }]
  ]
}
Enter fullscreen mode Exit fullscreen mode

In conclusion

Using Rollup, Babel, and babel-plugin-module-resolver, I was able to redirect React imports to a custom module, that loads React from the global environment, which reduces the size of the produced browser bundle, and prevents duplicated versions of React appearing in sibling modules. However, this only works if React exists in the global environment.

I plan on learning more about this approach, and using it for overlayed going forward. Hopefully that will come with more tangible examples.

Thanks for reading,

💙🌈
-Ben

P.S: Header Photo by Paul Esch-Laurent on Unsplash

Top comments (0)