Signalize is a client-side JavaScript framework designed for swift web development with minimal JavaScript.
Signalize:
- Leverages modern ES modules and import maps.
- Imports only a small 2 KB core, allowing you to decide what to import and when.
The goal is to provide functionality similar to modern frameworks like Vue, Svelte, Solid, and Qwik, but with minimal JavaScript, the smallest possible learning curve, a simple codebase, no dependencies, and no need for a JavaScript backend.
Signalize in a Nutshell
Let's start with a simple example of how Signalize works:
- Signalize is split into several JavaScript modules.
- Each module provides different functionality.
- To use Signalize, you need to define an import map first.
- Then, you import the core and create a new Signalize instance.
- This new instance will provide you with the
resolve
function for loading modules. - Every time you need some functionality, you import it using the resolve function.
- Signalize internally reuses modules and automatically loads dependencies in the correct order to keep the framework small.
<!-- 1. Configure the importmap -->
<script type="importmap">
{
"imports": {
"signalizejs": "https://cdn.jsdelivr.net/npm/signalizejs@latest/+esm",
"signalizejs/mutation-observer": "https://cdn.jsdelivr.net/npm/signalizejs@latest/mutation-observer/+esm",
"signalizejs/dom/ready": "https://cdn.jsdelivr.net/npm/signalizejs@latest/dom/ready/+esm",
"signalizejs/event": "https://cdn.jsdelivr.net/npm/signalizejs@latest/event/+esm"
}
}
</script>
<script type="module">
// 2. Import the Signalize core
import Signalize from 'signalizejs';
// 3. Create a new Signalize instance
const { resolve } = new Signalize();
// 4.1 Resolve the Event module because we need the "on" function
// 4.2 The Event module will automatically import the Mutation Observer module
const { on } = await resolve('event', 'dom/ready');
// 5. Use the on function
on('dom:ready', () => alert('Hello World!'));
</script>
The Ecosystem
The Signalize ecosystem currently contains 25 modules focused on solving web development problems such as reactivity, web components, Ajax, SPA, error logging, and various utilities. The number of modules will definitely grow.
Here is a list of a few of them:
- Signals & Reactivity: signal, bind
- Directives
- Web Components
- SPA
- Dialogs
- Logger
- Web Perf: Task
- Utils: Ajax
The Mindset
The basic idea is to import only what you need. Not everything needs to be a complex app with tons of features:
- I need some simple reactivity: Use the Signals and Binding modules.
- I have a carousel with dynamic products: Use the Ajax module and manually redraw Snippets.
- I need reusable components: Use Web Components
- I need more complex forms: Import Directives
- I want to turn my website into an SPA: Add the SPA module.
A simple example with Signals & Reactivity.
You can edit this example in the playground
<button>
Count: <span></span>
</button>
<script type="importmap">
{
"imports": {
"signalizejs": "https://cdn.jsdelivr.net/npm/signalizejs/+esm",
"signalizejs/bind": "https://cdn.jsdelivr.net/npm/signalizejs/bind/+esm",
"signalizejs/event": "https://cdn.jsdelivr.net/npm/signalizejs/event/+esm",
"signalizejs/mutation-observer": "https://cdn.jsdelivr.net/npm/signalizejs/mutation-observer/+esm",
"signalizejs/scope": "https://cdn.jsdelivr.net/npm/signalizejs/scope/+esm",
"signalizejs/signal": "https://cdn.jsdelivr.net/npm/signalizejs/signal/+esm"
}
}
</script>
<script type="module" defer>
import Signalize from 'signalizejs';
const { resolve } = new Signalize();
// You code goes here
const { signal, bind } = await resolve('signal', 'bind');
const number = signal(0);
document.querySelector('button').addEventListener(
'click',
() => number(number() + 1)
);
bind(document.querySelector('span'), { text: number });
</script>
A simple example with Astro.build
Do you like Astro.build? It converts JavaScript into ES modules, so Signalize works very well with Astro. I wrote a guide on how to use Signalize in Astro.
Bellow is a simplified example:
1 - Install Signalize:
npm i signalizejs
2 - Create src/assets/layout.js
import Signalize from 'signalizejs';
export const signalize = new Signalize();
3 - Create src/layouts/main.astro
---
// 1. Get signalizejs url
import signalize from 'signalizejs?url';
// 2. Get event module url. This applies for all modules you will need.
import eventModuleUrl from 'signalizejs/event?url';
// 3. Define importmap
const importMap = JSON.stringify({
imports: {
// 4. Configure necessary modules
'signalizejs/event': eventModuleUrl,
// Other modules you need
}
});
---
<html>
<head>
<!-- 5. Embed the import map -->
<script type="importmap" :html={importMap}></script>
<!-- 6. Create a global Signalize instance -->
<script>
import "../assets/layout.js";
</script>
</head>
<body>
<slot />
</body>
</html>
4 - Create src/pages/index.astro
---
// src/pages/index.astro
import MainLayout from '../layouts/main.astro';
---
<MainLayout>
<script>
import { signalize } from '../assets/layout.js';
const { on } = await signalize.resolve('event');
</script>
</MainLayout>
Let me know what you think!
If you like the idea, let me know by starring the Signalize repo.
I welcome any feedback because Signalize is a new library and there is definitely room for improvement. 🙂
Stay in Touch!
I plan to write about the reactivity inspired by Solid and Angular Signals, the bindings and directives inspired by Svelte, and the ES module loader for dependency injection inspired by Qwik's loader.
If you want to get inspired for your next project or learn something new, it's a great place to start.
Top comments (10)
Looks very interesting, particularly for using with Astro.
Do you have more examples of using signalize with Astro?
Thanks!
Hi. Thanks!
In which examples you would be interested in?
I use it on my websites but they run in Symfony (prace.dev) and Go (travellingvisio.com) so not probably what you have in mind.
Also a little Vite plugin would be helpful to intialize and expose singnilize globally. Will look into it now :)
Thanks for your reply!
Can singnilize substitute state management to share state across pages and componentes?
Hi!
Globals
Every Signalize instance has
global
object within (mentioned in configuration section).When you want to provide global data for "everything" within the instance, you put the data here. This way it is not poluting the window object and globals are automatically passed for example into directives.
This way you can basically create a "store" using signals and a simple class for example for a shopping cart.
Sharing State
Sharing data between components
Yes
watch
method .Unlike in Alpine, you must define properties and pass data to child component. The flow is from top to down. It's a bit more work but you know from where you got the data.
Thank you for reply. Will try this in Astro, though not sure globals will persist between pages.
Many thanks 🙏
If you use the SPA module, it will redraw snippets instead of performing a full page reload.
Do you want to keep global variables without using the SPA module? Because if so, Signalize doesn't have any mechanism for that. I can't think of any safe way to achieve this either. The only possible safe solution would be to keep data on the server side.
Another way I think of is to serialize/deserialize state via storage api (index db) and use it across Astro pages and components.
Will try the SPA mode 🙏
Yes, that's possible, but only for secure data with no personal information. Cleaning data becomes complicated when the browser window closes. It would need to be tied to a session with expiration timers in place.
I didn't need that functionality yet, but if the demand for this module arises from more people, I may look into it further.
Sure, depending on the need and use case. Syncing state via storage might provide an easy option to share the state.
User data can be set via Astro middleware to locals object on each request, while signalize can be client state layer.
Hopefully get spare time to experiment soon enough 🤞