Switch Framework
Switch Framework (version 0.2.5) is an early-stage frontend library designed for building web and Electron desktop applications. It emphasizes a "runtime-first" development workflow, aiming to allow applications to run without a traditional build step or bundler for basic setups. This approach means the framework is served and executed directly at runtime. It is intended to work in conjunction with `switch-framework-backend` for full functionality. The project is currently under active maintenance, but official documentation is not yet complete. Key differentiators include its bundler-less initial setup and specific targeting of both web and Electron environments, alongside a component-based architecture featuring integrated state management utilities. The framework is primarily developed by Switcherfaiz and has a companion CLI tool, `create-switch-framework-app`, for project initialization.
Common errors
-
Cannot find module 'switch-framework-backend'
cause The companion backend package `switch-framework-backend` is not installed or properly configured, which is a required dependency for full functionality of the framework.fixInstall `switch-framework-backend` via npm (`npm install switch-framework-backend`) and ensure it's properly initialized and accessible by your `switch-framework` application. -
ReferenceError: SwitchComponent is not defined (or similar 'Class extends value #<Object> is not a constructor')
cause The `switch-framework` library, or its core components like `SwitchComponent`, was not correctly imported as an ES module or not loaded in the HTML context before component definition.fixEnsure your HTML file loads the JavaScript/TypeScript entry point as a module (`<script type='module' src='./app.js'></script>`) and that core components are correctly imported using `import { SwitchComponent } from 'switch-framework';`. -
DOMException: Failed to execute 'define' on 'CustomElementRegistry': the name 'sw-counter' has already been used with this registry
cause An attempt was made to define a custom element with a tag name (e.g., `sw-counter`) that has already been registered in the Custom Element Registry. This can happen if the script runs multiple times or if a build process duplicates registrations.fixEnsure `customElements.define` is called only once per unique custom element tag. Implement a check like `if (!customElements.get(CounterComponent.tag)) { customElements.define(CounterComponent.tag, CounterComponent); }` to prevent re-registration.
Warnings
- breaking The framework's API is currently unstable and subject to frequent changes. The package version (0.2.5) explicitly indicates it is in early development stages, meaning breaking changes can occur even between minor versions.
- gotcha Official documentation is explicitly stated as 'not ready yet' in the README and GitHub repository. This significantly hinders development, troubleshooting, and understanding best practices.
- gotcha The `switch-framework` is designed to work specifically with `switch-framework-backend`. Using the frontend framework standalone or attempting to integrate it with a different backend may lead to incomplete functionality or unexpected behavior.
- gotcha The 'runtime-first' workflow, which avoids a traditional bundler for basic setups, might introduce performance considerations or complex dependency management in larger, production-grade applications, as it relies on native browser module loading.
Install
-
npm install switch-framework -
yarn add switch-framework -
pnpm add switch-framework
Imports
- SwitchComponent
const SwitchComponent = require('switch-framework');import { SwitchComponent } from 'switch-framework'; - createState
import { createState } from 'switch-framework'; - updateState
import { updateState } from 'switch-framework'; - getState
import { getState } from 'switch-framework';
Quickstart
import { SwitchComponent, createState, updateState, getState } from 'switch-framework';
// This example assumes it's loaded as a module in an HTML file.
// e.g., <script type="module" src="./app.js"></script>
// And a <sw-counter></sw-counter> element exists in the HTML body.
// Initialize a global reactive state named 'counterValue'
createState('counterValue', 0);
export class CounterComponent extends SwitchComponent {
static tag = 'sw-counter'; // Define the custom element tag
// Subscribe to state changes for automatic re-rendering
static {
this.useState('counterValue');
}
onMount() {
// Attach a delegated click listener to the increment button
this.listener('#incrementBtn', 'click', () => {
// Update 'counterValue' state; (currentCount ?? 0) handles initial undefined
updateState('counterValue', (currentCount) => (currentCount ?? 0) + 1);
});
}
render(): string {
const count = getState('counterValue') ?? 0;
return `
<style>
.counter-wrapper {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
font-family: Arial, sans-serif;
border: 1px solid #eee;
border-radius: 8px;
max-width: 300px;
margin: 20px auto;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
.counter-button {
padding: 10px 20px;
font-size: 1.2em;
background-color: #007bff; /* Primary blue */
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s ease;
}
.counter-button:hover {
background-color: #0056b3;
}
.count-display {
margin-top: 15px;
font-size: 1.8em;
font-weight: bold;
color: #333;
}
</style>
<div class="counter-wrapper">
<button id="incrementBtn" class="counter-button">
Click to Increment
</button>
<div class="count-display">
Current Count: ${count}
</div>
</div>
`;
}
}
// Register the custom element once the class is defined
// Check if already defined to prevent errors in hot-reloading scenarios
if (!customElements.get(CounterComponent.tag)) {
customElements.define(CounterComponent.tag, CounterComponent);
}