How to include external dependencies in UMD bundle with rollup

2.7k Views Asked by At

I'm using rollup to bundle a library and I want to include external dependencies together with my code in the UMD bundle. I can't find any useful information about this in the docs. It could be that I'm missing something obvious but it seems like the docs only demonstrates how to mark relative modules as external. I've been trying to achieve this without any success. Is it doable and if yes, how?

My code making use of an external component: src/index.ts

import { ExternalComponent } from 'external-component'

function MyComponent() {
  const externalComponent = ExternalComponent()
  // ...
}

export default MyComponent

Desired output: bundle.umd.js

function ExternalComponent() {
 // ...
}

function MyComponent() {
  const externalComponent = ExternalComponent()
  // ...
}

rollup.config.js

import babel from '@rollup/plugin-babel'
import typescript from 'rollup-plugin-typescript2'
import resolve from '@rollup/plugin-node-resolve'
import { terser } from 'rollup-plugin-terser'
import localTypescript from 'typescript'

const CONFIG_BABEL = {
  extensions: ['.js', '.jsx', '.ts', '.tsx'],
  exclude: 'node_modules/**',
  babelHelpers: 'bundled',
}

const CONFIG_TYPESCRIPT = {
  tsconfig: 'tsconfig.json',
  typescript: localTypescript,
}

const kebabCaseToPascalCase = (string = '') => {
  return string.replace(/(^\w|-\w)/g, (replaceString) =>
    replaceString.replace(/-/, '').toUpperCase(),
  )
}

export default [
  {
    input: 'src/index.ts',
    output: [
      {
        file: `${packageJson.name}.umd.js`,
        format: 'umd',
        strict: true,
        sourcemap: false,
        name: kebabCaseToPascalCase(packageJson.name),
        plugins: [terser()],
      }
    ],
    plugins: [resolve(), typescript(CONFIG_TYPESCRIPT), babel(CONFIG_BABEL)],
  },
]

package.json

{
  "types": "index.d.ts",
  "scripts": {
    "build": "rollup -c",
    "start": "rollup -c --watch",
  },
  "devDependencies": {
    "@babel/core": "7.17.0",
    "@rollup/plugin-babel": "^5.3.0",
    "@rollup/plugin-node-resolve": "13.1.3",
    "husky": "^4.3.8",
    "npm-run-all": "^4.1.5",
    "prettier": "2.5.1",
    "rollup": "^2.67.0",
    "rollup-plugin-terser": "^7.0.2",
    "rollup-plugin-typescript2": "^0.31.2",
    "typescript": "^4.5.5"
  },
}

Thanks in advance,
David

2

There are 2 best solutions below

1
Yumin Gui On

I find something from the rollup documentation:

If you do want to include the module in your bundle, you need to tell Rollup how to find it. In most cases, this is a question of using @rollup/plugin-node-resolve.

But the @rollup/plugin-node-resolve doc does not help.

0
Nathaniel Tucker On

You'll want to use external with output.globals

For example:

import packageJson from './package.json';

const peers = Object.keys(packageJson.peerDependencies);

export default [
  {
    input: 'src/index.ts',
    external: id => peers.some(dep => dep === id || id.startsWith(dep)),
    output: [
      {
        file: `${packageJson.name}.umd.js`,
        format: 'umd',
        strict: true,
        sourcemap: false,
        name: kebabCaseToPascalCase(packageJson.name),
        plugins: [terser()],
        globals: {
          react: 'React',
        },
      },
    ],
  }
]

globals maps the package name to the variable name in the global scope. In this case, the 'react' package uses upper-first, so we map react to 'React' to make that dependency work