I'm getting the error message:
(global) - index.js:1:0
ReferenceError: require is not defined
The solution I keep seeing online is to use ES6 modules and export/import rather than using require. However, I'm not using require, at least not in any way that's obvious to me.
Is it just not possible to do a fully client-side React application this way? If it is possible, what do I need to change to make this work?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>
<title>Title</title>
</head>
<body>
<div id="root"></div>
<script src="index.js" type="text/babel"></script>
</body>
</html>
// index.js
import { SettingsFloater } from "./components/settingsFloater";
const App = () => {
return (
<div>
<SettingsFloater />
</div>
);
};
ReactDOM.render(<App />, document.getElementById('root'));
// SettingsFloater.js
export const SettingsFloater = () => {
return (
<div></div>
);
}
What’s happening is Babel Standalone is rewriting your import/export into CommonJS (require(...)), because the code is being compiled as a “script” (not a browser ES module). Browsers do not provide require, so you get:
ReferenceError: require is not defined
So you are “using require” just indirectly, via Babel’s module transform.
your setup triggers this because You load index.js with type="text/babel", Babel Standalone transpiles it in the browser, By default (or depending on presets/plugins), Babel converts ES modules to CommonJS and you know commonJS uses require, which doesn’t exist in the browser.
So I'd say Use a real ESM setup (no Babel-in-browser), This is the cleanest “fully client-side” approach, but you must avoid JSX unless you have a build step.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Title</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="./index.js"></script>
</body>
</html>
index.js (ESM + no JSX)
import React from "https://esm.sh/react@17";
import ReactDOM from "https://esm.sh/react-dom@17";
import { SettingsFloater } from "./components/SettingsFloater.js";
const App = () =>
React.createElement("div", null, React.createElement(SettingsFloater));
ReactDOM.render(React.createElement(App), document.getElementById("root"));
components/SettingsFloater.js
import React from "https://esm.sh/react@17";
export const SettingsFloater = () => {
return React.createElement("div", null);
};
Also note that You must run this from a server (not file://). Use any static server and also Include file extensions in imports (./components/SettingsFloater.js), because browsers require it for ESM.
If you have the experience, Use a bundler (Vite)
If you want JSX, multiple files, imports that “just work”, fast reload. then just use Vite ( will still be a fully client-side React app when deployed. the bundler is just for development/build).
And Yes, a fully client-side React app is possible