Search code examples
reactjstypescriptrollupjs

Rollup ESM generates broken imports


I want to bundle a typescript react App as a component into a ES module or UMD. But the generated ES bundle produces an invalid module js.

On bundle it gives me this hints. But I cant find any solution for this.

(!) Missing global variable names
Use output.globals to specify browser global variable names corresponding to external modules
http (guessing 'http')
...

inside the esm js bundle there are imports like these:

import http from 'http';
import https from 'https';
import url from 'url';
import require$$0 from 'stream';
...

function createCommonjsModule(fn) {
  var module = { exports: {} };
    return fn(module, module.exports), module.exports;
}

And after adding it to the browser:

<script type="module" src="./index.esm.js"></script>

I got the error about the missing relative imports:

Uncaught TypeError: Failed to resolve module specifier "http". Relative references must start with either "/", "./", or "../".

Iam surely have mistakes on my rollup configuration, but I cant find the spot and happy and thankful about any hints. ...

Of course I have nodemodule imports in my app like:

import {observer} from 'mobx-react';

But rollup should handle this. Dont he?

Here is my rollup.config:

import pkg from './package.json';
import nodeResolve from "@rollup/plugin-node-resolve";
import typescript from "rollup-plugin-typescript2";
import image from "@rollup/plugin-image";
import styles from "rollup-plugin-styles";
import commonjs from "@rollup/plugin-commonjs";
import replace from "@rollup/plugin-replace";
import json from '@rollup/plugin-json';
import babel from '@rollup/plugin-babel';
import copy from "rollup-plugin-copy";
import del from "rollup-plugin-delete";

export default {
    input: pkg.source,
    output: [
        {
            file: pkg.module,
            format: 'es',
            sourcemap: false
        },
        {
            file: "dist/index.umd.js",
            format: 'umd',
            sourcemap: true
        },
    ],
    plugins: [
        del({targets: 'dist/*'}),
        nodeResolve({
            mainFields: ['jsnext:main', 'module', 'main'],
            dedupe: [ 'react', 'react-dom' ]
        }),
        replace({
            preventAssignment: false,
            'process.env.NODE_ENV': JSON.stringify('development'),
            __buildDate__: () => JSON.stringify(new Date())
        }),
        json(),
        typescript(),
        styles(),
        copy({
            targets: [
                {src: 'public/**/*', dest: 'dist'}
            ]
        }),
        babel({ //disabled cause WebComponent integration
            presets: ["@babel/preset-react"],
            exclude: 'node_modules/**',
            babelHelpers: 'bundled'
        }),
        commonjs(),
        image()
    ]
};

Solution

  • I had a similar issue (though with stream module, not http), and for me the solution was to set browser: true in nodeResolve within rollup.config:

    export default [
      {
        input: '...',
        plugins: [
          nodeResolve({
            'browser': true,
          }),
          commonjs(),
        ],
        output: {
           ...
        }
      }
    ];
    

    From description of a flag:

    browser

    Type: Boolean
    Default: false

    If true, instructs the plugin to use the browser module resolutions in package.json and adds 'browser' to exportConditions if it is not present so browser conditionals in exports are applied. If false, any browser properties in package files will be ignored. Alternatively, a value of 'browser' can be added to both the mainFields and exportConditions options, however this option takes precedence over mainFields.