Skip to content

AdamBien/bce.design

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

156 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

bce.design

Quickstarter and sample application for building non-trivial web applications with minimal tooling, essential dependencies, high productivity, and no migrations.

Web standards first, external libraries last. Built directly on browser APIs - no framework lock-in, just native Web Components, ES modules, and modern JavaScript. Visit bce.design/web-components for more information.

Every external dependency is treated as a liability and continuously replaced with web standards: the Bulma CSS framework was removed in favor of plain CSS design tokens, and Redux Toolkit is superseded by reduction.js, a minimal standards-based store built on structuredClone. The single remaining runtime library is lit-html for declarative templating. The complete replacement log: from dependencies to web standards.

Tip

LLMs love stable web standards: airails.dev ...and developers predictability: sbce.dev. This project's architecture rules are captured in the web-components skill.

Core Architecture

This project implements unidirectional data flow with a Redux-style store for predictable state management. All state changes flow in one direction: Actions → Reducers → Store → View Components. The application follows the Boundary Control Entity (BCE) pattern for clear separation of concerns.

Two interchangeable store implementations are provided, selected via the import map in app/src/index.html: reduction.js (active default) — a minimal, standards-based implementation of the used Redux Toolkit API (configureStore, createAction, createReducer) that relies on structuredClone instead of Immer — or the original Redux Toolkit vendored in app/src/libs/. Application code imports @reduxjs/toolkit either way; switching is a one-line import map change.

Boundary Control Entity quickstarter -> with web components

run

There is nothing to build. Serve app/src with any static web server that falls back to index.html for unknown paths (required for client-side routing), e.g. with zws (zero dependencies web server, requires Java):

cd app/src
zws.sh --single

For deployment, copy app/src to any static host — an S3 bucket, a CDN, or the META-INF/resources/ folder of a Quarkus backend.

BCE overview

e2e tests

The e2e tests are available from:

tests

code coverage

The e2e tests with configured global code coverage is available from: codecoverage

IDE

  1. Visual Studio Code
  2. Setup: JS imports
  3. lit-html plugin for syntax highlighting inside html templates
  4. redux devtools browser extension — works with both store implementations, see observability

update dependencies

There is no build system. Runtime dependencies are vendored as self-contained ES modules in app/src/libs/ and mapped via the import map in index.html. lit-html ships as a single dependency-free module, so an update is a plain file copy:

./update-lit-html.sh 3.3.3

external ingredients

  1. lit-html
  2. redux toolkit (optional — reduction.js, a minimal built-in implementation of the used API, is the active default; switch via the import map in index.html)

Client-side routing is implemented with web standards: the Navigation API and URLPattern — no router dependency required.

standards-based routing

app/src/app.js declares the route table, app/src/router.js implements the mechanics in ~30 lines:

initRouter(document.querySelector('.view'), [
    { path: '/',                 component: 'b-list' },
    { path: '/add',              component: 'b-bookmarks' },
    { path: '/edit/:bookmarkId', component: 'b-bookmarks' }
]);

Navigation is plain HTML: any <a href="/add"> whose URL matches a route is intercepted by the Navigation API and rendered client-side — no Router.go(), no link components. URLPattern uses the same :param syntax as router libraries (both inherit it from path-to-regexp); named path parameters are passed to the routed component as attributes. The edit view demonstrates the pattern: the list renders <a href="/edit/${bookmark.id}">, the router creates <b-bookmarks bookmarkid="...">, and the component loads the bookmark into the form through the control layer.

Deliberate non-features: URLs matching no route fall through to regular browser navigation (external links keep working), and reloads are never intercepted (reload means reload). Both imply the serving requirement above — unknown paths must fall back to index.html.

observability

Store and components report diagnostics directly to browser DevTools — no additional tooling required:

  • Redux DevTools: with the Redux DevTools extension installed, reduction.js reports every dispatched action and the resulting state — action log, payloads, state tree, and diffs appear in the Redux panel. Without the extension this is a no-op.
  • User Timing: every dispatch records standards-based performance.measure entries: reduce <action> (reducer run) and notify <action> (subscriber notification) in reduction.js, plus render <Component> per web component in BElement.js. The component renders nest inside the notify window, breaking each dispatch down by component — visible in the Performance panel's Timings track and queryable via performance.getEntriesByType('measure').

what is BCE?

Boundary Control Entity (BCE) pattern organizes code by responsibility:

  • Boundary: UI components (Web Components) - user interaction layer
  • Control: Business logic and orchestration - application behavior
  • Entity: State management and data models - domain objects

In this project:

  • bookmarks/boundary/ - UI components like List.js, Add.js
  • bookmarks/control/ - Logic like CRUDControl.js
  • bookmarks/entity/ - State like BookmarksReducer.js

The bookmarks BC is the sample business component that keeps this template runnable and testable. After cloning, remove or replace it with your own BCs. Removing it touches four coupling points: the imports and the route registrations in app/src/app.js, the bookmarks reducer registration in app/src/store.js, the <h1> title in app/src/index.html, and the e2e specs in tests/ and codecoverage/.

BCE eliminates naming debates and provides instant code organization, helping avoid Parkinson's law of triviality. Learn more about BCE

unidirectional data flow

State always travels the same cycle — the view never mutates state directly. A boundary web component (Add.js) forwards user input to the control layer (CRUDControl.js), which dispatches an action to the store; the entity layer reducer (BookmarksReducer.js) computes the next state, and the store notifies all subscribed components (BElement.js), which re-render via lit-html:

graph LR
    Boundary([Boundary<br/>web components]) -->|user event| Control([Control<br/>action creators])
    Control -->|dispatches action| Store([Store<br/>reduction.js or Redux Toolkit])
    Store -->|state, action| Entity([Entity<br/>reducers])
    Entity -->|next state| Store
    Store -->|notifies subscribers| Boundary
    Store -.->|persists state| Storage([localStorage])

    classDef boundary fill:#d5e8d4,stroke:#82b366,color:#000
    classDef control fill:#e1d5e7,stroke:#9673a6,color:#000
    classDef entity fill:#fff2cc,stroke:#d6b656,color:#000
    classDef bc fill:#dae8fc,stroke:#6c8ebf,color:#000
    classDef ext fill:#fff2cc,stroke:#d6b656,color:#000,stroke-dasharray:5 5
    class Boundary boundary
    class Control control
    class Entity entity
    class Store bc
    class Storage ext
Loading

unidirectional data flow

static hosting on Amazon S3

static web hosting on Amazon S3 intro

from dependencies to web standards

Each external dependency was removed once a web standard could take over. The dependency name links to the commit that eliminated it:

removed dependency web standard replacement in the code
Vaadin Router Navigation API + URLPattern router.js
Bulma CSS framework CSS custom properties as design tokens, container queries tokens.css, style.css
Redux Toolkit + Immer structuredClone-based store reduction.js
build system (Rollup / npm) import maps + vendored ES modules index.html, libs/
lit-html (pending) DOM Parts — proposal, not yet implemented in browsers libs/lit-html.js

lit-html is the last remaining runtime dependency — declarative templating with efficient re-rendering has no shipped web standard equivalent yet. Once DOM Parts lands, the final row completes.

resources

Web Standards and Browser APIs Used

Testing & Development Tools

mockend serves as a mock backend with throttling functionality.

Mockend can slow down responses, which simplifies the testing of asynchronous view updates. Fetch requests in the control layer can be delayed for test purposes.

Article: Web Components, Boundary Control Entity (BCE) and Unidirectional Data Flow with redux

AI coding agents

Guidance for AI coding agents (Claude Code, Codex, Gemini CLI, ...) is maintained in AGENTS.md.

powered by airhacks.industries

About

minimal magic, minimal tooling, essential dependencies, high productivity, no transpilations and no migrations. The Web Components starter ships with integrated lit-html and redux-toolkit.

Topics

Resources

License

Stars

100 stars

Watchers

8 watching

Forks

Contributors

Languages