Catalog npm
Back to packageRELEASE DETAILS

0.1.2

npm

2mqjs

A tiny performance-first architecture toolkit for framework-free web apps: lazy components, event ports, workers, tasks, and an off-main-thread store.

event-busfrontend-architecturelazy-loadingstate-managementtypescriptvanilla-jsweb-performanceweb-workers
Published23 Jul 2026
Direct dependencies4
Transitive dependenciesNot calculated

README

Current package documentation

2mqjs

2mqjs logo

npm version CI CodeQL install size TypeScript strict MIT license

Маленький performance-first архитектурный набор для веб-приложений без фреймворков.

English version · Components · Ports · Workers · Tasks · Store · Events


Что это?

2mqjs помогает разбить vanilla TypeScript/JavaScript сайт на небольшие runtime-слои:

  • UI-компоненты загружаются только тогда, когда они реально нужны.
  • Бизнес-логика может уехать в Web Workers.
  • События идут через явные ports, а не через скрытые связи между модулями.
  • Tasks управляют порядком запуска, видимостью, idle-временем, готовностью данных и воркеров.
  • Store может жить вне main thread и сохраняться между перезагрузками.

Библиотека нужна для страниц, где важны маленький 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';

Быстрый старт

1. Ленивые UI-компоненты

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', () => {
    // Тяжёлая логика стартует только после появления компонента.
  });
}

2. Ports: явные события приложения

import { emitPort, onPort } from '2mqjs/ports';

const off = onPort<{ id: string }>('cart:add', ({ id }) => {
  console.log('Добавить товар', id);
});

emitPort('cart:add', { id: 'sku-42' });
off();

3. Tasks: предсказуемый порядок запуска

import { registerTask, runTasks } from '2mqjs/tasks';

registerTask({
  id: 'hydrate-products',
  stage: 'bootstrap',
  when: 'idle',
  run: async () => {
    // Некритичная работа ждёт idle-времени.
  },
});

await runTasks('bootstrap');

4. Workers: тяжёлая логика вне main thread

import { registerWorker, emitPort } from '2mqjs/workers';

await registerWorker({
  name: 'productData',
  src: () => import('./workers/productData.worker.js'),
});

emitPort('productData:init', { page: 'catalog' });

5. Store: состояние в dedicated worker

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/replay2mqjs/ports
WorkersРегистрация воркеров и port-based messaging2mqjs/workers
TasksОркестрация запуска, зависимости и runtime-условия2mqjs/tasks
StoreГлобальное состояние вне main thread + persist2mqjs/store
EventsDOM-утилиты: делегирование событий и resize subscriptions2mqjs/events

Принципы runtime

  • Откладывать по умолчанию. Запускать дорогой UI и логику только когда они нужны.
  • Держать слои явными. UI, данные, воркеры и orchestration общаются через маленькие контракты.
  • Не привязывать к фреймворку. Можно использовать рядом с SSR, islands, виджетами или обычным HTML.
  • Следить за размером. Subpath exports и release smoke checks защищают package shape и bundle budgets.

Текущий roadmap

Следующий цикл разработки сфокусирован на production-grade производительности:

  • lazy components без потери первого interaction;
  • shared observers и cache в component loader;
  • cleanup жизненного цикла listeners в ports/tasks/events/workers;
  • patch-based store updates вместо отправки всего state;
  • SharedWorker mode для синхронизации стора между вкладками;
  • улучшение scheduler: DAG validation, cancellation, timeouts, concurrency limits;
  • browser smoke tests, benchmarks и bundle-size budgets.

Подробный backlog — в open issues.

Релизы

2mqjs теперь использует GitHub automation:

  • CI гоняет release gate на поддерживаемых версиях Node.js.
  • CodeQL сканирует JavaScript/TypeScript код.
  • Dependabot группирует обновления npm и GitHub Actions.
  • Release Please создаёт release PR из Conventional Commits.
  • npm-публикация идёт через GitHub Actions с provenance.

Локальная проверка перед релизом:

npm run release:check

Лицензия

MIT

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Declared dependencies 4

Native requirements
4 direct targetsNot calculated transitive count
Package / targetRequirementRelationship
vite
Environment
{
  "local_name": "vite",
  "alias": false,
  "peer_metadata": null
}
^6.4.3development
vitest
Environment
{
  "local_name": "vitest",
  "alias": false,
  "peer_metadata": null
}
^3.2.7development
typescript
Environment
{
  "local_name": "typescript",
  "alias": false,
  "peer_metadata": null
}
^7.0.2development
@playwright/test
Environment
{
  "local_name": "@playwright/test",
  "alias": false,
  "peer_metadata": null
}
^1.61.0development

Distribution files

1 collected
Distribution 1

Source distribution

Source file
Checksums from source
{
  "shasum": "5a61a92f2ed52165e5c5eef206f8396a415f6128",
  "tarball": "https://registry.npmjs.org/2mqjs/-/2mqjs-0.1.2.tgz",
  "fileCount": 22,
  "integrity": "sha512-f1nuqHoJkbaq8mSB4WPhpeeRBimXTXOzymR8Y3NZRpLeeAj1sg2nl6cRb2DKegqxxZ6YTIthtTpj8ivEGDB+hg==",
  "signatures": [
    {
      "sig": "MEUCIQC8LwSdLr6Ocq6cvC6sHsjsN89hZ5LDASHBQ2E5+G2SvQIgOmm5op3tK2/hmeSs6ngxvNR9RkjvcGr3aEEHSW4CYmA=",
      "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"
    }
  ],
  "attestations": {
    "url": "https://registry.npmjs.org/-/npm/v1/attestations/2mqjs@0.1.2",
    "provenance": {
      "predicateType": "https://slsa.dev/provenance/v1"
    }
  },
  "unpackedSize": 71294
}

Repository

PENDING
poliklot/2mqjs

Shared repository data · GitHub

License detected in repository
Not collected

Repository

PENDING
your-org/2mqjs

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 19:15 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package_version:109b316ea2d44b6524ff5d3c07c5baa31a348a4681bce7d65f155bcf79366ca5

Other collected versions

0.1.611 Aug0.1.529 Jul0.1.428 Jul0.1.323 Jul0.1.129 Jun0.1.029 JunView all collected versions →