Skip to content

Latest commit

 

History

History
234 lines (171 loc) · 7.35 KB

File metadata and controls

234 lines (171 loc) · 7.35 KB

Developing a Web App with Vanilla HTML/Javascript/Bootstrap

  1. Simplicity = Maintainability

    • No build steps, no dependency hell, no weird bundler configs.
    • You understand every line of your code — no magic, no indirection.
    • Easier onboarding for others (as long as the code is cleanly organized).
  2. Performance

    • No virtual DOM diffing, hydration, or bloated JS bundles.
    • Initial load times are faster because you're not shipping half of npm to the browser.
  3. Direct Browser Support

    • Modern browsers are incredibly capable now. Features like fetch, async/await, modules, and CSS Grid/Flexbox make life easier.
  4. Better for Certain Kinds of Apps

    • Internal tools, dashboards, data-heavy UIs, or admin panels don’t always need client-side routing or SSR.
    • Tabulator is a great example of a powerful library that thrives in a no-framework setup.
  5. You Control the Stack

    • You pick the graphing library. You pick your CSS utility. No lock-in, no ecosystem churn.
  6. Bootstrap Gets the Job Done

    • It's not trendy, but it’s stable and familiar, and if you're not chasing bleeding-edge UI trends, it’s more than enough.

⚠️ What You Might Miss (But Can Often Live Without)

  1. Componentization & Reusability

    • Frameworks like React/ Vue shine when you need lots of composable, nested UI components with shared state and dynamic updates.
    • You’ll need to roll your own patterns for components and state management — or just keep things flat and simple.
  2. Tooling Ecosystem

    • Frameworks come with built-in solutions (routing, form handling, SSR, etc.).
    • With vanilla JS, you’ll selectively add libraries (like Chart.js or ApexCharts for graphs).
  3. Community & Hiring Perception

    • Yes, some devs may turn their nose up and say “where’s your SPA router or Vite config?”
    • But real users (and smart devs) care more about usability and maintainability than whether you’re using the flavor-of-the-week stack.
  4. Scalability Concerns

    • For very large apps with lots of interactive components, it can become messy to manage state or keep UI updates consistent.
    • That said, many apps never get that big, and thoughtful structure can go a long way.
  5. Developer Experience

    • You’ll miss out on some DX perks like hot module replacement, JSX syntax, or TypeScript integration unless you manually add them.

🎯 What You Can Do to Level It Up Without Frameworks

  1. Structure Your Code Like Components (Manually)

    • Use ES modules (import/export) to break up logic and rendering functions.
    • Wrap UI chunks into small, reusable functions or classes.
  2. Use Modern CSS

    • Learn CSS Grid/Flexbox and use utility classes (Tailwind is usable without a framework, or even just your own class helpers).
    • Look into component-focused CSS like Web Components or just scoped styles via Shadow DOM.
  3. Enhance With Good Libraries

    • Graphing: Chart.js, ApexCharts, or Plotly work great with vanilla JS.
    • State management: You might not even need one! But something like Observable patterns can be helpful for complex views.
  4. Use a Lightweight Router if Needed

    • If you ever want client-side routing, consider something tiny like Navigo.
  5. Progressively Enhance

    • Start simple, and add complexity only where the use case demands it.

👨‍💻 Some Devs are Going “Frameworkless” by Choice

  • There’s a growing number of developers who write “frameworkless” or “vanilla-first” apps for performance, maintainability, and control.
  • Sites like htmx, unpoly, and Alpine.js give modern interaction with minimal JS.
  • Even GitHub and Basecamp (hey, DHH!) have talked about moving away from heavy JS frontends where not needed.

Awesome — let’s get you set up with a clean, modern vanilla JS module structure that scales well without needing React/Vue. This structure will give you:

✅ Code separation
✅ Component-style organization
✅ Easy readability and maintainability
✅ The ability to grow your app without losing control


🗂️ Suggested File Structure

Here’s a simple example:

/my-app
│
├── index.html
├── main.js               # Your entry point
├── /components           # Reusable UI chunks
│   ├── navbar.js
│   ├── chart.js
│   └── table.js
├── /services             # API or data utilities
│   └── supabase.js
├── /utils                # General helper functions
│   └── dom.js
├── /styles
│   └── style.css

📦 1. Using ES Modules (native, no bundler needed)

In index.html:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Vanilla App</title>
  <link rel="stylesheet" href="./styles/style.css">
</head>
<body>
  <div id="app"></div>

  <!-- Load JS entry point -->
  <script type="module" src="./main.js"></script>
</body>
</html>

🚀 2. Your Entry Point (main.js)

import { renderNavbar } from './components/navbar.js';
import { renderChart } from './components/chart.js';
import { renderTable } from './components/table.js';

function init() {
  renderNavbar();
  renderChart();
  renderTable();
}

init();

🧩 3. A Sample Component (e.g. table.js)

import { createElement } from '../utils/dom.js';

export function renderTable() {
  const app = document.getElementById('app');
  const table = createElement('div', 'my-table-container');

  table.innerHTML = `<p>This is where the table will go</p>`;
  
  app.appendChild(table);
}

🧰 4. A Utility Function (utils/dom.js)

export function createElement(tag, className = '', id = '') {
  const el = document.createElement(tag);
  if (className) el.className = className;
  if (id) el.id = id;
  return el;
}

🌐 5. A Service File (e.g. supabase.js)

import { createClient } from '@supabase/supabase-js';

const supabaseUrl = 'https://your-project.supabase.co';
const supabaseKey = 'public-anon-key';
export const supabase = createClient(supabaseUrl, supabaseKey);

export async function fetchData(tableName) {
  const { data, error } = await supabase.from(tableName).select('*');
  if (error) throw error;
  return data;
}

🎨 6. Optional CSS Setup (styles/style.css)

body {
  font-family: sans-serif;
  margin: 2rem;
}

.my-table-container {
  border: 1px solid #ccc;
  padding: 1rem;
}

💡 Bonus Tips

  • Use browser-native modules (type="module") — modern browsers support them out of the box.
  • Split code based on responsibility (rendering vs logic vs API vs helpers).
  • No bundlers required unless you want one — but you can easily add tools like Vite or Parcel later without changing your architecture.
  • Use import maps (optional) to simplify path management.
  • Store global app state in a single file if needed — just like Redux but simpler.

✅ Result: You Get

  • No framework lock-in
  • Native modules
  • Real separation of concerns
  • A “component-like” feel
  • Readable code with no magical abstraction layers