Ask HN: Building Large Frontend Apps Without Frameworks Like React

Building Large Frontend Apps Without JavaScript Frameworks

You can build complex web applications without React or similar frameworks. The browser provides powerful native APIs. Modern JavaScript handles state, routing, and DOM manipulation effectively. Obsidian demonstrates this approach at scale.

Why Skip the Framework

Frameworks change frequently. React introduced hooks five years ago—a fundamental shift in how developers write components. Next.js deprecated Create React App in 2024 after years as the recommended setup tool. These changes force migration work instead of feature development.

Browser APIs evolve slowly and deliberately. Functions like document.querySelector and fetch remain stable for years. Your code works without constant updates.

Framework-free projects give you complete control. You optimize performance at the DOM level. You avoid supply chain vulnerabilities from hundreds of dependencies. Your success doesn’t depend on Meta’s React roadmap or Vercel’s business decisions.

Core Building Blocks

Start with native browser features:

DOM Manipulation: Use querySelector, addEventListener, and direct element creation. These APIs are fast and well-documented.

State Management: Implement the observer pattern with JavaScript Proxies or create custom event systems. A basic pub/sub system requires under 100 lines.

Routing: The History API handles navigation with pushState and popstate events. You control URL structure and page transitions.

Components: Write functions that return DOM elements. Organize related HTML, CSS, and JavaScript together—the approach React popularized but doesn’t require React.

Modularity: ES6 modules provide clean code organization. Import and export functions like any modern language.

Practical Architecture

Structure your application in layers:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// Create reusable elements
const createButton = (text, onClick) => {
  const button = document.createElement('button');
  button.textContent = text;
  button.addEventListener('click', onClick);
  return button;
};

// Handle events and state
const updateView = (container, data) => {
  container.innerHTML = '';
  container.appendChild(createButton('Action', () => handleAction(data)));
};

Use MutationObserver to watch for DOM changes and trigger component initialization. This provides React-like lifecycle hooks without the overhead.

Store business logic separately from UI code. Event handlers connect them. This separation makes testing straightforward and reduces coupling.

Tools Worth Using

You don’t need zero dependencies. Choose focused libraries:

  • Vite or ESBuild: Fast bundling and hot reload during development
  • TypeScript: Catch errors before runtime
  • Lit: Lightweight web components if you want more structure
  • Alpine.js: Reactive behavior for simpler applications

Avoid reinventing solved problems. Use established date libraries or validation tools. But keep your dependency tree shallow.

Real-World Examples

Obsidian built a complex desktop application this way. They use webpack for bundling, moment.js for dates, and vanilla JavaScript for UI. The result performs better than framework-heavy alternatives.

Draw.io creates sophisticated diagrams without React or Vue. The codebase demonstrates how far vanilla JavaScript extends for interactive applications.

These projects succeed because they match tools to requirements. They don’t default to frameworks.

Common Challenges

Component Reusability: Extract common patterns into functions. Pass configuration as parameters. Return DOM elements that work anywhere.

State Synchronization: Design clear data flow. Use events to communicate between components. Avoid circular dependencies.

Team Onboarding: Document your architecture. Establish patterns for common tasks. Consider framework experience less valuable than JavaScript fundamentals.

Scaling: Organize code by feature, not file type. Keep components focused. Test business logic independently from DOM manipulation.

When Frameworks Make Sense

Large teams benefit from shared conventions. Framework knowledge transfers between projects and companies. Popular frameworks offer extensive documentation and community support.

Complex state requirements—like real-time collaboration or offline sync—might justify framework overhead. Evaluate whether you need those features.

If you’re building standard CRUD applications, server-side rendering with minimal JavaScript often works better than any frontend framework.

Getting Started

Pick a small project. Build one feature without frameworks. See where you need abstraction. Create focused utilities as requirements emerge.

Study browser APIs deeply. Read MDN documentation. Understand the platform before adding layers on top.

Write tests for your business logic. Separate concerns. Make functions pure when possible.

The web platform gives you everything needed to build sophisticated applications. Frameworks add convenience but aren’t prerequisites for quality software.