Replacing JS Imports with Rollup
Tags: javascript, todayilearned
Published: 2020-01-07 16:01:52

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](https://github.com/microsoft) to help solve really tricky problems, and [share our stories](https://www.microsoft.com/developerblog) 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](https://overlayed.app) - it helps broadcasters interact with their viewers in new ways, using overlays. Under the hood, Overlayed is powered by user-defined modules (using [ESM](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules)), that export React components. You can learn more about that, [here](https://dev.to/bengreenier/introducing-overlayed-streamer-overlays-powered-by-react-17ja) - but it's not what this post is about.

Previously, I wrote about [accessing globals from within modules](https://dev.to/bengreenier/accessing-globals-inside-js-modules-esm-1eo5) which is a precursor to what I'd like to share today - Replacing imports with [rollup](https://rollupjs.org). 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
```

Which will just provide a [default export](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export) that's value is set to that of the [globalThis](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/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](https://babeljs.io/) 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](https://github.com/tleunen/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](https://github.com/pikapkg/builders/tree/master/packages/plugin-bundle-web) 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](https://github.com/tleunen/babel-plugin-module-resolver#getting-started), depending on your setup.


```
{
  "plugins": [
    ["module-resolver", {
      "alias": {
        "react": "./react-shim.js",
      }
    }]
  ]
}
```

## 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](https://overlayed.app) going forward. Hopefully that will come with more tangible examples.

Thanks for reading,

💙🌈
-Ben

P.S: Header Photo by [Paul Esch-Laurent](https://unsplash.com/@pinjasaur?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/javascript?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)