If you want to build a simple, lightweight eCommerce website without relying on React, Angular, Vue.js, or other overhyped frameworks, follow along.
We’ll keep things minimal and efficient by using just two libraries: Juris and BSS.
Let’s start by looking at the project’s folder structure::
Let's extent it:
It’s worth noting that, for now, we don’t need to include Node.js in our workflow.
We’ll begin by examining the index.html file :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Galaxy Tech Shop</title>
<script type="importmap">
{
"imports": {
"juris": "https://esm.sh/juris@0.9",
"bss": "https://esm.sh/bss@1.6"
}
}
</script>
</head>
<body>
<div id="app"></div>
<script type="module" src="./src/main.js"></script>
</body>
</html>
Let’s ask an AI to explain what’s happening here.
Development Perspective
This HTML file reflects a modern, minimalist, and framework-free approach to web development. Let’s break down what makes it interesting from a development standpoint.
🚀 Modern JavaScript Without a Build Step
By using type="module" along with an import map, we can rely on native ES modules directly in the browser.
This means:
- No bundler
- No transpiler
- No immediate need for Node.js
This setup keeps the development workflow lightweight and fast.
📦 CDN-Based Dependency Management
The dependencies (juris and bss) are loaded directly from a CDN via esm.sh.
Benefits:
- Instant setup
- No local installation
- Ideal for prototypes and small projects
You can run the project using a simple static server.
🧩 Clear Separation of Concerns
The HTML stays minimal and declarative:
- A single mounting point:
#app - All logic lives in
main.js
This keeps the structure clean and easy to maintain.
🔮 Future-Friendly Architecture
Even without a framework, this setup follows modern SPA principles.
If the project grows, adding a build step or a Node.js workflow later will be straightforward.
🌍 Standards-First Approach
Everything here is based on web standards:
- ES modules
- Import maps
- Semantic HTML
This reduces vendor lock-in and improves long-term maintainability.
⚖️ Trade-offs to Consider
- CDN imports may need optimization for production (caching, version pinning).
- Import maps are supported by modern browsers, but not legacy ones.
✅ Summary
This approach prioritizes simplicity, performance, and control.
It’s a solid foundation for lightweight applications, educational projects, or anyone looking to avoid heavy frameworks while still writing modern web code.
Let us examine now the entry point app.js :
import { Juris } from 'juris';
import { initGlobalStyles } from './styles/global.js';
import { products } from './data/products.js';
import { loadCartFromStorage } from './utils/storage.js';
// Styles
initGlobalStyles();
// 1. IMPORT the missing UI components
import { NavLink } from './components/ui/NavLink.js';
import { CartBadge } from './components/ui/CartBadge.js';
import { Hero } from './components/ui/Hero.js';
import { Breadcrumb } from './components/ui/Breadcrumb.js';
// 2. IMPORT the rest of your components
import { ProductCard } from './components/product/ProductCard.js';
import { CartItem } from './components/product/CartItem.js';
import { ProductsPage } from './components/pages/ProductsPage.js';
import { CartPage } from './components/pages/CartPage.js';
import { ProductDetailPage } from './components/pages/ProductDetailPage.js';
import { RouteRenderer } from './components/routing/RouteRenderer.js';
import { App } from './app.js';
const juris = new Juris({
states: {
products,
cart: loadCartFromStorage(),
router: {
currentRoute: location.hash.slice(1) || '/'
}
},
components: {
NavLink,
Hero,
CartItem,
Breadcrumb,
ProductCard,
CartBadge,
ProductsPage,
CartPage,
ProductDetailPage,
RouteRenderer
}
});
document.getElementById('app').append(juris.objectToHtml(App));
window.addEventListener('hashchange', () =>
juris.setState('router.currentRoute', location.hash.slice(1) || '/')
);


Top comments (0)