Observed since 20 Oct, 19:15 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
A tiny performance-first architecture toolkit for framework-free web apps: lazy components, event ports, workers, tasks, and an off-main-thread store.
Маленький performance-first архитектурный набор для веб-приложений без фреймворков.
English version · Components · Ports · Workers · Tasks · Store · Events
2mqjs помогает разбить vanilla TypeScript/JavaScript сайт на небольшие runtime-слои:
Библиотека нужна для страниц, где важны маленький initial JS, меньше работы в main thread и предсказуемый порядок инициализации.
npm i 2mqjs
# или
pnpm add 2mqjs
# или
yarn add 2mqjs
Проект должен использовать ESM:
{
"type": "module"
}
2mqjs публикует subpath exports, чтобы bundler мог не тянуть лишнее:
import { registerComponent } from '2mqjs/components';
import { emitPort, onPort } from '2mqjs/ports';
import { registerTask } from '2mqjs/tasks';
Корневой экспорт тоже доступен, если удобнее:
import { registerComponent, emitPort, registerTask } from '2mqjs';
import { registerComponent, runComponentLoader } from '2mqjs/components';
registerComponent({
name: 'product-card',
load: () => import('./components/product-card.js'),
when: 'visible',
hasDisplay: true,
});
runComponentLoader();
<article data-component="product-card"></article>
Модуль компонента:
export function display(el: Element) {
el.innerHTML = '<button data-add>Добавить в корзину</button>';
}
export function boot(el: Element) {
el.querySelector('[data-add]')?.addEventListener('click', () => {
// Тяжёлая логика стартует только после появления компонента.
});
}
import { emitPort, onPort } from '2mqjs/ports';
const off = onPort<{ id: string }>('cart:add', ({ id }) => {
console.log('Добавить товар', id);
});
emitPort('cart:add', { id: 'sku-42' });
off();
import { registerTask, runTasks } from '2mqjs/tasks';
registerTask({
id: 'hydrate-products',
stage: 'bootstrap',
when: 'idle',
run: async () => {
// Некритичная работа ждёт idle-времени.
},
});
await runTasks('bootstrap');
import { registerWorker, emitPort } from '2mqjs/workers';
await registerWorker({
name: 'productData',
src: () => import('./workers/productData.worker.js'),
});
emitPort('productData:init', { page: 'catalog' });
import { defineGlobalStore } from '2mqjs/store';
const app = defineGlobalStore({
name: 'shop',
initial: { cart: [] as string[] },
persist: ['cart'],
});
await app.ready;
app.watch('cart', cart => {
console.log('Корзина изменилась', cart);
});
app.add('cart', 'sku-42');
| Модуль | Для чего | Импорт |
|---|---|---|
| Components | Ленивые UI-модули, display/boot, запуск по видимости и взаимодействию | 2mqjs/components |
| Ports | Лёгкий pub/sub со snapshot/replay | 2mqjs/ports |
| Workers | Регистрация воркеров и port-based messaging | 2mqjs/workers |
| Tasks | Оркестрация запуска, зависимости и runtime-условия | 2mqjs/tasks |
| Store | Глобальное состояние вне main thread + persist | 2mqjs/store |
| Events | DOM-утилиты: делегирование событий и resize subscriptions | 2mqjs/events |
Следующий цикл разработки сфокусирован на production-grade производительности:
SharedWorker mode для синхронизации стора между вкладками;Подробный backlog — в open issues.
2mqjs теперь использует GitHub automation:
Локальная проверка перед релизом:
npm run release:check
Download counts and popularity will appear here as the collector receives them.
This describes our collected data; it is not a security assessment.
Observed since 20 Oct, 19:15 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:0d3495a27ce629d8cae1f3e6eda8e403bbcad77456be70456ccb7d6fd9d4cddb