COLEwebdev.org: A React App That Skips the Build Step Entirely

COLEwebdev.org architecture: React 18 and Babel Standalone loaded from CDN, five JSX files transpiled in-browser, no build step required
TL;DR: COLEwebdev.org is a React 18 single-page app for a Cape Cod web design studio. It loads React and Babel Standalone from CDN, splits the UI across five sequentially-loaded JSX files, and requires zero build tooling to develop or deploy. No package.json. No node_modules. No webpack config. Development is python -m http.server 8080. The tradeoff — Babel Standalone's ~900KB first-load — is the right call for a marketing site that values zero maintenance overhead over shaved milliseconds.

Why Skip the Build Step?

Most modern React setups start with a command like npm create vite@latest or Create React App. What follows is a node_modules directory, a lockfile, a build config, and a pipeline that turns source files into a deployable bundle. For a complex app with dozens of contributors and daily deployments, that infrastructure earns its weight.

For a marketing site touched twice a year by different people, the calculus is different. Every npm audit warning needs a response. Dependency version drift silently breaks things. A developer cloning the repo three months later runs npm install and hits a peer dependency conflict before writing a single line of code. The toolchain becomes the project's second maintenance surface.

COLEwebdev.org sidesteps all of that. React 18, ReactDOM, and Babel Standalone load from CDN. The component files are plain JSX, served as-is over HTTP. There is no build step because there is nothing to build.

How In-Browser JSX Transpilation Works

JSX is not valid JavaScript. A browser given a raw .jsx file will throw a syntax error at the first angle bracket it doesn't recognize. The usual solution is to run a compiler — Babel or esbuild — before the browser ever sees the code. COLEwebdev.org flips this: the compiler runs inside the browser, just before execution.

Babel Standalone is a self-contained build of Babel that runs in any JavaScript environment, including browsers. When you load it via <script> and mark your component files with type="text/babel", it intercepts those scripts before the JavaScript engine parses them, converts JSX into React.createElement() calls, and hands the result to the engine.

<!-- React 18 + Babel loaded from CDN -->
<script src="https://unpkg.com/react@18.3.1/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js"></script>

<!-- Component files — transpiled by Babel in the browser -->
<script src="tweaks-panel.jsx" type="text/babel"></script>
<script src="parts-hero.jsx" type="text/babel"></script>
<script src="parts-services.jsx" type="text/babel"></script>
<script src="parts-rest.jsx" type="text/babel"></script>
<script src="app.jsx" type="text/babel"></script>

The type="text/babel" attribute is the only magic. Without it, the browser would parse the file as regular JavaScript and immediately fail on any JSX syntax. With it, Babel intercepts, transforms, and executes the converted code — all before the React render cycle even starts.

The Five-File Loading Architecture

Without a bundler to resolve imports, COLEwebdev.org uses a different module boundary strategy: five files loaded in a fixed sequence, each contributing components to a shared global scope that later files can reference.

The order is not arbitrary:

  1. tweaks-panel.jsx — defines the useTweaks hook first; every subsequent file that calls it depends on this loading first
  2. parts-hero.jsx — Header and Hero components; Hero uses useTweaks to select its display variant
  3. parts-services.jsx — Services grid, cost estimator, and AI showcase section
  4. parts-rest.jsx — Portfolio, Testimonials, CTA, News section, and Footer
  5. app.jsx — Root App component that assembles everything and calls ReactDOM.createRoot()

This mirrors the pattern classic JavaScript libraries used before ES modules: jQuery had to load before any plugin that referenced $. It's not the most elegant dependency model, but it's completely transparent — no module graph to trace, no bundler to debug when something loads in the wrong order.

The Component Tree

The root App component, defined in app.jsx, assembles the full page layout:

function App() {
  return (
    <>
      <Header />
      <main>
        <Hero />
        <Trust />
        <Services />
        <Estimator />
        <AIShowcase />
        <Process />
        <Portfolio />
        <CTA />
        <Testimonial />
        <News />
      </main>
      <NewsletterBanner />
      <Footer />
    </>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);

Using React 18's createRoot() is correct even in a CDN-loaded setup — it enables concurrent rendering features and avoids the deprecation warning that ReactDOM.render() now logs. The CDN build includes the same runtime as any npm-installed version.

The Tweaks System: Design-Time UI Customization

The tweaks-panel.jsx file introduces a development-time design tool built directly into the app. The useTweaks hook manages a set of configurable settings — things like color palette, font size, layout density, and dark mode — and a floating TweaksPanel component exposes live controls for changing them.

Changes made through the panel are reflected immediately via CSS variable updates on the <html> element. Persistence works through a message protocol: when a setting changes, the hook posts a message to the parent window, which rewrites the defaults in a comment-delimited EDITMODE block in the source file. The next time the page loads, the new defaults are read directly from source.

In production — when no editor host is listening for those messages — the panel isn't shown, and the app simply uses whatever defaults were last baked into the source. There's no localStorage dependency, no feature flags, no build-time constant switching. The design-time state is just part of the file.

The practical effect is a live design feedback loop that requires no hot module replacement, no Storybook, and no separate design toolchain. Change a setting, see it update immediately, and the source file records the decision.

The CSS Design System: Variables and Density Modes

styles.css (~42KB) is the entire styling layer. It uses CSS custom properties for the brand palette:

:root {
  --brand-blue:  #2563EB;
  --brand-green: #059669;
  --navy:        #0f172a;
  --paper:       #EEFAF8;   /* green-blue tint, recently updated to v=10 */
  --ink:         #1e293b;
}

Density modes — compact, regular, comfy — are driven by a data-density attribute on the <html> element. An useEffect in the App component writes the current density setting:

useEffect(() => {
  document.documentElement.setAttribute('data-density', tweaks.density);
}, [tweaks.density]);

The CSS responds to that attribute directly:

[data-density="compact"] .section { padding: 2rem 0; }
[data-density="regular"] .section { padding: 3.5rem 0; }
[data-density="comfy"]   .section { padding: 5rem 0; }

Switching density modes triggers a CSS attribute change, not a JavaScript re-render of the component tree. The layout shift is immediate and smooth — no React reconciliation, no layout thrash, no flash of unstyled content.

Schema.org LocalBusiness: SEO Built into the HTML

The index.html <head> contains a detailed Schema.org structured data block that gives Google everything it needs to generate a local business knowledge panel:

{
  "@context": "https://schema.org",
  "@type": ["LocalBusiness", "ProfessionalService"],
  "name": "Cole Web Development",
  "serviceArea": {
    "@type": "GeoCircle",
    "description": "Barnstable, Bourne, Brewster, Chatham, Dennis,
                     Eastham, Falmouth, Harwich, Mashpee, Orleans,
                     Provincetown, Sandwich, Truro, Wellfleet, Yarmouth"
  },
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "4.8",
    "reviewCount": "72"
  }
}

All 15 Cape Cod towns are enumerated in the service area. A full service catalog is included. This markup lives in a <script type="application/ld+json"> block — no CMS plugin, no SEO middleware, no build-time injection. It's just data in the document.

For a local services business, this is the difference between appearing in Google's local 3-pack and not appearing at all. The fact that the app has no build step doesn't prevent it from having first-class structured data — the two concerns are completely independent.

The Development Workflow

The README's development setup section is one sentence:

python -m http.server 8080

Open http://localhost:8080 and start editing. There is no npm install, no npm run dev, no Vite server to configure. Any text editor works. Any developer — regardless of Node.js version, npm configuration, or familiarity with modern JavaScript tooling — can be productive in under two minutes.

The project has 201 commits. That sustained development pace, reached without a build system, is the real proof of concept. Babel Standalone adds a few hundred milliseconds to first paint during development; the developer experience gains more than compensate.

The Tradeoffs

This architecture isn't free. Understanding what you're trading is the point:

What you gain:

  • Zero toolchain maintenance — no lockfile conflicts, no npm audit surface, no breaking changes from bundler upgrades
  • Universal contributor access — any HTTP server, any text editor, any OS
  • Deployable as static files — copy to any web host, S3 bucket, or GitHub Pages. No build step in CI/CD
  • Transparent dependency graph — every CDN version is pinned in index.html and human-readable at a glance

What you give up:

  • Babel Standalone is ~900KB — it's the dominant payload on first load (cached on return visits)
  • No tree shaking — the full React development build loads, not an optimized production bundle
  • No TypeScript type checking at build time — Babel can strip type annotations but won't verify them
  • No hot module replacement — changes require a manual browser refresh
  • Shared global scope between files — naming collisions are possible if components aren't prefixed carefully

For a marketing site with a modest traffic volume, the performance costs are invisible to users. The browser caches the CDN resources after the first visit; subsequent page loads skip the Babel download entirely. For a high-traffic application where first-load performance is a conversion metric, you'd want pre-compiled assets.

When This Approach Makes Sense

The no-build pattern is a good fit for a specific category of projects:

  • Marketing and brochure sites that change infrequently and are maintained by a small, varied team
  • Internal tools where deployment complexity is a real friction and users are on company networks with fast connections
  • Prototypes and demos where the value is in the idea, not the infrastructure
  • Projects with non-technical contributors who need to make content edits without running a build pipeline

It's a poor fit for SPAs with complex client-side routing, apps with sensitive credentials that must stay out of the CDN request chain, or anything where first-load performance is a business metric. The honest version of software engineering is choosing the right tool for the actual requirements — and for COLEwebdev.org, this is demonstrably the right tool.

What's Next

If performance ever became a priority, the natural upgrade path is incremental. Switch from React's development UMD build to the production build (react.production.min.js) — that alone roughly halves the React bundle size and removes development-mode runtime checks. Then, if Babel Standalone's 900KB becomes a real problem, a single-command tool like esbuild can pre-compile the JSX files into a single optimized bundle without touching the component architecture.

The components don't care whether they were transpiled by Babel in the browser or esbuild on a CI server. The migration path from no-build to build is a deployment concern, not an application concern. That's a useful property to have.

For now, the site has 201 commits, is actively maintained, and requires no more than a Python one-liner to develop. The repo is at github.com/josefresco/COLEwebdev.org. The approach is worth knowing — you'll recognize the situations where it's exactly the right call.

Need a Marketing Site or React App Built to Last?

Whether you want a zero-maintenance static site, a full React application, or something in between, the right architecture depends on your actual requirements — not the current default. Let's figure out the right fit for your project.