Error: You must use the `@babel/plugin-transform-runtime` plugin when `babelHelpers` is "runtime" on npm link

Viewed 2378

I have 2 react libraries, and one consumes the other.

project-ui propert-utils

project-utils is installed in project-ui

"devDependencies": {
  "@company/project-utils": "git+ssh://git@github.com/company/project-utils.git#main",
},
"dependencies": {
  "@company/project-utils": "git+ssh://git@github.com/company/project-utils.git#main",
}

both have the same .babelrc files

{
  "env": {
    "test": {
      "presets": [["@babel/preset-env"], "@babel/preset-react"]
    }
  },
  "presets": [
    [
      "@babel/preset-env",
      {
        "modules": false
      }
    ],
    "@babel/preset-react"
  ],
  "ignore": ["node_modules/**"],
  "plugins": ["@babel/plugin-transform-runtime"]
}

The rollup.config.js in the project-ui is as follows

import babel from '@rollup/plugin-babel';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import json from '@rollup/plugin-json';
import postcss from 'rollup-plugin-postcss';
import filesize from 'rollup-plugin-filesize';
import precss from 'precss';
import autoprefixer from 'autoprefixer';
import peerDepsExternal from 'rollup-plugin-peer-deps-external';
import localResolve from 'rollup-plugin-local-resolve';
import externals from 'rollup-plugin-node-externals';
import builtins from 'rollup-plugin-node-builtins';
import globals from 'rollup-plugin-node-globals';
import image from 'rollup-plugin-inline-image';
import { terser } from 'rollup-plugin-terser';

import pkg from './package.json';

const OUTPUT_NAME = 'Example';

const ENVIRONMENT = process.env;
const PRODUCTION = ENVIRONMENT.production || ENVIRONMENT.production === 'true';

const formGlobals = {
  formik: 'formik',
  'lodash/throttle': 'throttle',
  'react-number-format': 'NumberFormat',
  'react-ga': 'ReactGA',
};

const GLOBALS = {
  react: 'React',
  'react-dom': 'ReactDOM',
  'react-router-dom': 'reactRouterDom',
  'prop-types': 'PropTypes',
  formik: 'formik',
  'lodash/throttle': 'throttle',
  'react-number-format': 'NumberFormat',
  'react-ga': 'ReactGA',
  'react-dates': 'ReactDates',
  'styled-components': 'styled',
  'react-tag-autocomplete': 'ReactTags',
  'react-spinkit': 'Spinner',
  'react-select': 'Select',
  '@fortawesome/fontawesome-svg-core': 'fontawesomeSvgCore',
  '@fortawesome/react-fontawesome': 'reactFontawesome',
  '@fortawesome/pro-regular-svg-icons': 'proRegularSvgIcons',
  '@fortawesome/free-brands-svg-icons': 'freeBrandsSvgIcons',
  '@fortawesome/pro-solid-svg-icons': 'proSolidSvgIcons',
};

const PLUGINS = ({ cssPlugin }) => {
  return [
    PRODUCTION && globals(),
    PRODUCTION && builtins(),
    PRODUCTION && externals(),
    babel({
      babelHelpers: 'runtime',
      exclude: 'node_modules/**',
      presets: ['@babel/env', '@babel/preset-react'],
    }),
    commonjs({
      include: 'node_modules/**',
    }),
    PRODUCTION && peerDepsExternal(),
    postcss({ extract: cssPlugin, plugins: [autoprefixer, precss] }),
    PRODUCTION && json({ include: 'node_modules/**' }),
    PRODUCTION && localResolve(),
    resolve({
      browser: true,
      resolveOnly: [/^(?!react$)/, /^(?!react-dom$)/, /^(?!prop-types)/],
    }),
    PRODUCTION && filesize(),
    image(),
    PRODUCTION && terser(),
  ];
};

const EXTERNAL = [
  ...Object.keys(pkg.peerDependencies || {}),
  ...Object.keys(pkg.dependencies || {}),
  'lodash/throttle',
  'formik',
  'react-dates/initialize',
  'react-dates/lib/css/_datepicker.css',
];

const CJS_AND_ES_EXTERNALS = EXTERNAL.concat(/@babel\/runtime/);

const OUTPUT_DATA = (dir) => {
  const umd = {
    file: dir ? `/index.js` : pkg.browser,
    format: 'umd',
  };
  const cjs = {
    file: dir ? `/index.cjs.js` : pkg.main,
    format: 'cjs',
  };
  const es = {
    file: dir ? `/index.esm.js` : pkg.module,
    format: 'es',
  };

  return [{ ...umd }, { ...cjs }, { ...es }];
};

const WATCH = {
  chokidar: {
    usePolling: true,
    paths: 'src/**',
  },
};

const OUTPUT_FILES = [
  {
    input: 'src/form/index.js',
    output: 'form',
    cssPlugin: false,
    globals: formGlobals,
  },
  {
    input: 'src/buttons/index.js',
    output: 'buttons',
    cssPlugin: false,
  },
  {
    input: 'src/theme/index.js',
    output: 'theme',
    cssPlugin: false,
  },
  {
    input: 'src/icons/index.js',
    output: 'icons',
    cssPlugin: false,
  },
  {
    input: 'src/icons/index.js',
    output: 'icons',
    cssPlugin: false,
  },
  {
    input: 'src/interactive/index.js',
    output: 'interactive',
    cssPlugin: false,
  },
];

const arr = [];
const config = arr.concat.apply(
  [],
  OUTPUT_FILES.map(({ input, output, cssPlugin }) =>
    OUTPUT_DATA(output).map(({ file, format }) => ({
      input,
      output: {
        file: `${output}${file}`,
        format,
        name: OUTPUT_NAME,
        globals: GLOBALS,
      },
      watch: WATCH,
      external: ['cjs', 'es'].includes(format) ? CJS_AND_ES_EXTERNALS : EXTERNAL,
      plugins: PLUGINS(cssPlugin),
    }))
  )
);

export default config;

The rollup.config.js in the project-utils is as follows

import babel from '@rollup/plugin-babel';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import json from '@rollup/plugin-json';
import postcss from 'rollup-plugin-postcss';
import filesize from 'rollup-plugin-filesize';
import precss from 'precss';
import autoprefixer from 'autoprefixer';
import peerDepsExternal from 'rollup-plugin-peer-deps-external';
import localResolve from 'rollup-plugin-local-resolve';
import externals from 'rollup-plugin-node-externals';
import builtins from 'rollup-plugin-node-builtins';
import globals from 'rollup-plugin-node-globals';
import image from 'rollup-plugin-inline-image';
import { terser } from 'rollup-plugin-terser';

import pkg from './package.json';

const OUTPUT_NAME = 'Example';

const ENVIRONMENT = process.env;
const PRODUCTION = ENVIRONMENT.production || ENVIRONMENT.production === 'true';

const GLOBALS = {
  react: 'React',
  'react-dom': 'ReactDOM',
  'prop-types': 'PropTypes',
  'whatwg-fetch': 'whatwgFetch',
  'file-saver': 'fileSaver',
  'resize-observer-polyfill': 'ResizeObserver',
  'dinero.js': 'Dinero',
  '@auth0/auth0-react': 'auth0React',
};

const PLUGINS = ({ cssPlugin }) => {
  return [
    PRODUCTION && globals(),
    PRODUCTION && builtins(),
    PRODUCTION && externals(),
    babel({
      babelHelpers: 'runtime',
      exclude: 'node_modules/**',
      presets: ['@babel/env', '@babel/preset-react'],
    }),
    commonjs({
      include: 'node_modules/**',
    }),
    PRODUCTION && peerDepsExternal(),
    postcss({ extract: cssPlugin, plugins: [autoprefixer, precss] }),
    PRODUCTION && json({ include: 'node_modules/**' }),
    PRODUCTION && localResolve(),
    resolve({
      browser: true,
      resolveOnly: [/^(?!react$)/, /^(?!react-dom$)/, /^(?!prop-types)/],
    }),
    PRODUCTION && filesize(),
    image(),
    PRODUCTION && terser(),
  ];
};

const EXTERNAL = [
  ...Object.keys(pkg.peerDependencies || {}),
  ...Object.keys(pkg.dependencies || {}),
];

const CJS_AND_ES_EXTERNALS = EXTERNAL.concat(/@babel\/runtime/);

const OUTPUT_DATA = (dir) => {
  const umd = {
    file: dir ? `/index.js` : pkg.browser,
    format: 'umd',
  };
  const cjs = {
    file: dir ? `/index.cjs.js` : pkg.main,
    format: 'cjs',
  };
  const es = {
    file: dir ? `/index.esm.js` : pkg.module,
    format: 'es',
  };

  return [{ ...umd }, { ...cjs }, { ...es }];
};

const WATCH = {
  chokidar: {
    usePolling: true,
    paths: 'src/**',
  },
};

const OUTPUT_FILES = [
  {
    input: 'src/api/index.js',
    output: 'api',
    cssPlugin: false,
  },
  {
    input: 'src/utils/index.js',
    output: 'utils',
    cssPlugin: false,
  },
  {
    input: 'src/hooks/index.js',
    output: 'hooks',
    cssPlugin: false,
  },
  {
    input: 'src/hooks/hooks-api/index.js',
    output: 'hooks/hooks-api',
    cssPlugin: false,
  },
];

const arr = [];
const config = arr.concat.apply(
  [],
  OUTPUT_FILES.map(({ input, output, cssPlugin }) =>
    OUTPUT_DATA(output).map(({ file, format }) => ({
      input,
      output: {
        file: `${output}${file}`,
        format,
        name: OUTPUT_NAME,
        globals: GLOBALS,
      },
      watch: WATCH,
      external: ['cjs', 'es'].includes(format) ? CJS_AND_ES_EXTERNALS : EXTERNAL,
      plugins: PLUGINS(cssPlugin),
    }))
  )
);

export default config;

I have a single import to the project-utils in the project-ui

import { useResize } from '@company/project-utils/hooks';

Now, when I run npx rollup -c --watch on the project-ui everything works as expected. That import works fine, there are no console errors.

However, when I run npm link @company/project-utils it does link it up correctly but I get the following error in the console.

rollup v2.39.0
bundles src/form/index.js → form/index.js...
[!] (plugin babel) Error: You must use the `@babel/plugin-transform-runtime` plugin when `babelHelpers` is "runtime".

../project-utils/hooks/index.js
Error: You must use the `@babel/plugin-transform-runtime` plugin when `babelHelpers` is "runtime".

    at error (/Users/aaron/git/project-ui/node_modules/rollup/dist/shared/rollup.js:5275:30)
    at throwPluginError (/Users/aaron/git/project-ui/node_modules/rollup/dist/shared/rollup.js:18232:12)
    at Object.error (/Users/aaron/git/project-ui/node_modules/rollup/dist/shared/rollup.js:18839:24)
    at Object.error (/Users/aaron/git/project-ui/node_modules/rollup/dist/shared/rollup.js:18401:38)
    at preflightCheck (/Users/aaron/git/project-ui/node_modules/@rollup/plugin-babel/dist/index.js:222:11)

I have ensured that I am on the same branch as the package.json defines for the project-utils .I have run a build npx rollup -c --environment=production and also tried to run a watch npx rollup -c --watch on the project-utils but still coming back with the same error.

This works fine for a colleague of mine but we are left scratching our heads why it's failing on my end.

Any help would be greatly appreciated.

0 Answers
Related