I am getting this console error in the Chrome browser
index.tsx:13 Uncaught ReferenceError: React is not defined
at index.tsx:13:2
I am really struggling to figure out how to get Rollup.js to work with React. I've been able to write a good-sized app in pure js using Rollup.js, but I want to start using React with it now. I'm not sure how to resolve this issue ; the code simply won't run in the browser yet I have no compilation issues. I've done much searching on this topic and none of the suggestions work. Any help would be appreciated!
I am compiling to bundle.js using
rollup -c -w
The output from rollup is
rollup v3.6.0
bundles src/ts/index.tsx → resources/public/js/bundle.js...
LiveReload enabled
created resources/public/js/bundle.js in 1.1s
[2023-01-24 01:11:33] waiting for changes...
My rollup.config.js looks like
import typescript from '@rollup/plugin-typescript';
import { nodeResolve } from '@rollup/plugin-node-resolve';
import livereload from 'rollup-plugin-livereload';
import babel from '@rollup/plugin-babel';
export default {
input: 'src/ts/index.tsx',
output: {
file: 'resources/public/js/bundle.js',
format: 'iife',
sourcemap: 'inline',
inlineDynamicImports: true,
globals: {
"react/jsx-runtime":"jsxRuntime",
"react-dom/client":"ReactDOM",
"react":"React"},
},
external: [ 'react', 'react/jsx-runtime','react-is', 'react-dom/client','react-dom'],
watch: true,
plugins: [typescript(),
nodeResolve(),
livereload(),
babel({
babelHelpers: "bundled",
exclude: 'node_modules/**',
presets: [ ["@babel/preset-react", {"runtime": "automatic"}] ]
})]
};
My tsconfig.js
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react",
"noImplicitAny": true,
"removeComments": true,
"checkJs": false,
"preserveConstEnums": true,
"sourceMap": true,
},
"include": ["src"],
"exclude": ["node_modules", "**/*.spec.ts"]
}
My index.tsx file:
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
App.tsx
import React from 'react';
function App() {
return (
<div className="App">
<header className="App-header">
<p>
Edit <code>src/App.tsx</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
I figured this out myself and I wanted to post the solution as I was doing a lot of head scratching. I hope this helps future readers. ChatGPT was my co-pilot and helped me arrive at the solution.
Because React is compiled as a commonjs aka cjs module, you need the @rollup/plugin-commonjs installed. My understanding is that there is a particular order you need to call the plugin in the plugins array. commonjs must come before babel.
In addition, you will need the @rollup/plugin-replace to replace the process.env.NODE_ENV var in the root index.js of the React library with a value so that you can choose the minified or non-minified version.
'use strict';
if (process.env.NODE_ENV === 'production') {
module.exports = require('./cjs/react.production.min.js');
} else {
module.exports = require('./cjs/react.development.js');
}
In my case, my rollup.config.js is for a dev environment so I set the value to dev, otherwise I would replace it with production. To be on the safe side, I call the replace plugin before commonjs or babel.
I also removed the external declarations I had above
Working rollup.config.js
import typescript from '@rollup/plugin-typescript';
import { nodeResolve } from '@rollup/plugin-node-resolve';
import livereload from 'rollup-plugin-livereload';
import commonjs from '@rollup/plugin-commonjs';
import babel from '@rollup/plugin-babel';
import replace from '@rollup/plugin-replace';
export default {
input: 'src/ts/index.tsx',
output: {
file: 'resources/public/js/bundle.js',
format: 'iife',
sourcemap: 'inline',
inlineDynamicImports: true,
globals: {
"react/jsx-runtime":"jsxRuntime",
"react-dom/client":"ReactDOM",
"react":"React"},
},
watch: true,
plugins: [typescript(),
nodeResolve(),
livereload(),
// this should be 'production' for minified code
replace({preventAssignment: true,
'process.env.NODE_ENV': JSON.stringify('dev')}),
commonjs(),
babel({
babelHelpers: "bundled",
exclude: 'node_modules/**',
presets: [["@babel/preset-react", {"runtime": "automatic"}]]})]};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With