rollup / rollup-plugin-commonjs

This module has moved and is now available at @rollup/plugin-commonjs / https://github.com/rollup/plugins/blob/master/packages/commonjs
MIT License
501 stars 126 forks source link

Can't use React hooks #407

Closed screendriver closed 5 years ago

screendriver commented 5 years ago

I want to use React hooks within my application that is bundled with rollup via

import React, { useState } from 'react';

Unfortunately I get the error

Error: 'useState' is not exported by node_modules/react/index.js

My rollup.config.js looks like this:

import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import replace from 'rollup-plugin-replace';

export default {
  input: 'target/index.js',
  output: {
    file: 'public/bundle.js',
    format: 'iife',
    sourcemap: true,
  },
  plugins: [
    resolve(),
    commonjs({
      include: 'node_modules/**',
      react: ['Component', 'createElement', 'createContext', 'useState'],
      'react-dom': ['render'],
    }),
    replace({
      'process.env.NODE_ENV': JSON.stringify('development'),
    }),
  ],
};
TrySound commented 5 years ago

Hi @screendriver Try this

import react from 'react';
import reactDom from 'react-dom';

commonjs({
  include: 'node_modules/**',
  namedExports: {
    react: Object.keys(react),
    'react-dom': Object.keys(reactDom)
  }
})
screendriver commented 5 years ago

Awesome. Thanks! 🎉

funkybob commented 5 years ago

After struggling with this same issue over the past couple of weeks trying to port a project from webpack to rollup, I'd really love to understand why this fails.

Given module.exports = React in the CJS bundle, doesn't that mean import { foo } from 'react'; should be importing, effectively, React.foo ?

eight04 commented 5 years ago

Nope. module.exports = React will be converted to export default React. This statement doesn't export a foo variable. You will get an import error when trying to import {foo} from 'react'.

To make it work, you have to configure the transformer i.e. the commonjs plugin to add an extra statement:

export default React;
export const foo = React.foo;

See https://github.com/rollup/rollup-plugin-commonjs#custom-named-exports

funkybob commented 5 years ago

Thanks! I've spent a couple of days flailing about trying to find any authoritative declaration of how that works -- exports vs. module.exports ; Life would be so much nicer if people would publish ESM, too :/

bkulyk commented 4 years ago

@TrySound works brilliantly, but I hate it. I've wasted far too much time on this problem, thanks a ton.

funkybob commented 4 years ago

My current rollup has a series of rollup-plugin-re entries to convert broken imports into something more sane. e.g.:

{
  // ironically, this is the format FB seem to be planning to use in the next major release
  test: "import * as React from 'react';",
  replace: (_, imp) => `import React from 'react';`
},
{
  test: /import React, (\{.+\}) from 'react';/,
  replace: (_, imp) => `import React from 'react'; const ${imp} = React;`
},
{
  test: /import (\{.+\}) from 'react';/,
  replace: (_, imp) => `import React from 'react'; const ${imp} = React;`
},

I have 9 such entries, and have managed to get our sizeable codebase working. Note that it's not React that does this "wrong"; it's all 3rd party libs.

Coming from a language with more strict rules about importing, it sometimes amazes me the JS world works as well as it does...