Tired of waiting for build steps? Discover how to harness React 19’s full power using nothing but vanilla JavaScript and modern ESM CDNs. No webpack, no Vite, no hassle!
🚀 Ditch Your Build Tools: With Pure React + ESM CDNs
⚡ Why Use Pure React with JavaScript?
Before diving into the code, let’s consider the fundamental reasons to use React in its purest form:
Understanding the core model: Working with React’s raw APIs helps you understand how React works under the hood
Learning fundamentals: Building a mental model of React’s architecture without build-system abstractions
Debugging skills: Improving your ability to troubleshoot React issues by understanding the underlying mechanisms
Simplified mental model: Removing layers of abstraction to see that React is “just JavaScript”
Control: Having complete control over every aspect of your application without blackbox tooling
Lightweight applications: Building small apps without the overhead of a full toolchain
Performance transparency: Seeing exactly what code you’re shipping to the browser
🔥Why Build-Free React with ESM?
Beyond the benefits of pure React, using ESM CDNs provides additional advantages:
Zero configuration: No bundlers, transpilers, or build scripts to manage
Instant feedback: Changes are visible immediately without waiting for builds
Modern JavaScript: Leverage native ES modules supported in all modern browsers
Simplified workflow: Focus on writing React code without tooling complexities
Easy prototyping: Perfect for quick demos or proof-of-concept
Legacy environment constraints: Working in environments where build tools aren’t available
🛠️ Getting Started: Your First React 19 Zero-Build App
esm.sh is a CDN that serves npm packages as ES Modules, making them directly importable in the browser.
Let’s create a complete React 19 application in under 60 seconds:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Lightning React 19</title>
</head>
<body>
<div id="root"></div>
<script type="module">
// Import React 19 instantly from ESM CDN
import React from 'https://esm.sh/react@19';
import ReactDOM from 'https://esm.sh/react-dom@19/client';
// Your React app is just a few lines away
const app = React.createElement('h1', null, 'React 19 in seconds, not minutes!');
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(app);
</script>
</body>
</html>
That’s it! No npm install, no create-react-app, no waiting. Just pure, instant React.
🔄 React.createElement: The Building Block You’re Overlooking
While JSX gets all the attention, React’s true power lies in its createElement API:
// This familiar JSX:
// <button className="btn-primary" onClick={handleClick}>Click Me</button>
// Is just syntactic sugar for this:
React.createElement(
'button',
{
className: 'btn-primary',
onClick: () => console.log('Clicked!')
},
'Click Me'
);
🌐 Multi-File Applications Made Easy
For real-world apps, organize your code across multiple files and import them as ES modules.
Working with Third-Party Libraries
One of the great advantages of esm.sh is that you can import any npm package as an ES module:
💪 Let’s build a basic React App with confetti animation on the mouse movement.
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>React App</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<div id="root"></div>
<script type="module" src="./main.tsx"></script>
</body>
</html>
/* style.css */
* {
padding: 0;
margin: 0;
line-height: 1.5;
}
div {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
}
h1 {
font-size: 32px;
font-family: Inter, sans-serif;
}
p {
font-size: 16px;
font-style: italic;
// app.tsx
import React, { type MouseEvent } from "https://esm.sh/react@19"
import confetti from "https://esm.sh/canvas-confetti@1.6.0"
const App = () => {
function onMouseMove(e: MouseEvent) {
confetti({
particleCount: 5,
origin: {
x: e.pageX / window.innerWidth,
y: (e.pageY + 20) / window.innerHeight,
}
})
}
return (
<div onMouseMove={onMouseMove}>
<h1>Hello React! ⚛️</h1>
<p>Building user interfaces.</p>
</div>
)
}
export default App
// main.tsx
import React from "https://esm.sh/react@19"
import { createRoot } from "https://esm.sh/react-dom@19/client"
import App from "./app.tsx"
const root = createRoot(document.getElementById("root"))
root.render(<App />)
🛡️Optimizations and Best Practices
When using ESM CDNs for React 19 development:
- Version pinning: Always specify exact versions to avoid unexpected changes
import React from 'https://esm.sh/react@19.0.0';
2. Import Maps: Clean up your imports for better readability
<script type="importmap">
{
"imports": {
"react": "https://esm.sh/stable/react@19.0.0",
"react-dom/client": "https://esm.sh/stable/react-dom@19.0.0/client"
}
}
</script>
<script type="module">
// Clean imports without long URLs
import React from 'react';
import { createRoot } from 'react-dom/client';
</script>
3. Production Builds: Automatically optimized by esm.sh
// Development mode for debugging
import React from 'https://esm.sh/react@19.0.0/dev';
// Production mode (default) for performance
import React from 'https://esm.sh/react@19.0.0';
4. CDN caching: Take advantage of HTTP caching with esm.sh
// Using the /stable/ path for better caching
import React from 'https://esm.sh/stable/react@19.0.0';
🚀 The Zero-Build Ecosystem: Beyond React
The zero-build approach extends to your favorite libraries, too:
// State management
import { create } from 'https://esm.sh/zustand@4';
// UI components
import { Button, Card } from 'https://esm.sh/@mantine/core@6';
// Animation
import { motion } from 'https://esm.sh/framer-motion@10';
Note: UMD was a popular method for loading React without a build step, but it will no longer be supported starting with React 19. To load React 19 using a script tag, use an ESM-based CDN like esm.sh.
https://react.dev/blog/2024/04/25/react-19-upgrade-guide#umd-builds-removed
🔮Pros and Cons of Pure React with ESM
🏆Pros:
No build step required
Better understanding of React internals
Can run directly in the browser
Fewer dependencies
Easier debugging of the actual React code
Instant feedback during development
Perfect for small applications and demos
😐 Cons:
Verbose syntax compared to JSX (unless using Babel runtime)
Deeply nested elements become hard to read
Missing out on modern tooling benefits like code-splitting
Less common in production environments
No built-in TypeScript support
🧩 When to Use This Approach
Pure React with ESM CDNs is ideal for:
Learning projects to understand React fundamentals
Small widgets embedded in larger non-React applications
Environments with restricted build capabilities
Creating demos or proofs of concept
Adding isolated React components to existing websites
Teaching React concepts without tooling complexity
🧠 Conclusion
Building React 19 applications without a build step is not only possible but also powerful, thanks to modern ES Modules and CDNs like esm.sh. This approach simplifies the development process, allowing you to focus on core React concepts using just JavaScript.
While many developers use JSX and build tools, understanding React in its pure JavaScript form provides valuable insights into its internal workings, enhancing your skills as a developer. As browser support for modern JavaScript features improves and React evolves, build-free development will become increasingly viable for a variety of applications.
Remember, React is fundamentally JavaScript, enabling you to use as much or as little of the ecosystem as needed.
Top comments (0)