Build a micro-javascript frontend framework based on Web Components and no-build
Develop a micro-frontend using Web Components without build steps
Creating a basic JavaScript framework on Web Components with Shadow DOM and ES Modules, including client-side routing, requires a few steps. I shall outline how one can set up a framework.
Step 1: Setting Up Your Project
Create a brand new directory for your project and initialize it.
mkdir my-framework
cd my-framework
npm init -y
Step 2: Creating the Base Class for Components
Create a base class for your components. This one should extend HTMLElement
and set up some basic functionality.
// src/MyComponent.js
export class MyComponent extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
this.render();
}
disconnectedCallback() {
// Clean up if needed
}
render() {
// This method should be overridden by subclasses
this.shadowRoot.innerHTML = `<p>Override the render method in your component</p>`;
}
}
Step 3: Creating a Simple Component
Create a simple component that extends our MyComponent
base class.
// src/HelloWorld.js
import { MyComponent } from './MyComponent.js';
class HelloWorld extends MyComponent {
render() {
this.shadowRoot.innerHTML = `<p>Hello, World!</p>`;
}
}
customElements.define('hello-world', HelloWorld);
Step 4: Creating the Router
Build a simple client-side router. This router will be bound to changes in the URL and load an appropriate component accordingly.
// src/Router.js
class Router {
constructor(routes) {
this.routes = routes;
window.addEventListener('popstate', this.handleRoute.bind(this));
this.handleRoute();
}
handleRoute() {
const path = window.location.pathname;
const route = this.routes[path] || this.routes['/404'];
document.querySelector('router-view').innerHTML = `<${route}></${route}>`;
}
navigate(path) {
window.history.pushState({}, path, path);
this.handleRoute();
}
}
export const createRouter = (routes) => new Router(routes);
Step 5: Create the Entry Point
Now it is time to create an entry point for your application. This file should import the components that will be used and configure the router.
// src/index.js
import './HelloWorld.js';
import { createRouter } from './Router.js';
const routes = {
'/': 'hello-world',
'/404': 'not-found' // Create this component or use a default one
};
const router = createRouter(routes);
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll('[route-link]').forEach(link => {
link.addEventListener('click', (e) => {
e.preventDefault();
router.navigate(e.target.getAttribute('href'));
});
});
});
Step 6: Setting Up Your HTML
Create an HTML file to serve your application. This file will import the entry point module and set up the routing links.
<!-- public/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Framework</title>
</head>
<body>
<nav>
<a href="/" route-link>Home</a>
<a href="/404" route-link>Not Found</a>
</nav>
<router-view></router-view>
<script type="module" src="./src/index.js"></script>
</body>
</html>
Step 7: Running the Application
Since we are using ES Modules, we can take advantage of modern browsers' native module support. Use a simple HTTP server to serve your application.
You can use a tool like http-server
to serve the public
directory.
npx http-server public
Outcome
Now you have a basic frontend javascript framework using Web Components with Shadow DOM, ES Modules, and client-side routing with no build step. Here is the summary of files that you should have:
my-framework/
src/
MyComponent.js
HelloWorld.js
Router.js
index.js
public/
index.html
package.json
Expanding the Framework
To expand this framework, consider adding:
State Management: Implement a simple state management solution.
Styling: Add scoped styles to components using the Shadow DOM.
HTTP Requests: Include utilities for making HTTP requests.
Advanced Routing: Implement more advanced routing features like nested routes and route guards.
This setup gives you a strong base for a modern, lightweight framework using Web Components, Shadow DOM, ES Modules, and client-side routing—with no build step.