npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

dresscodejs

v2.0.8

Published

DressCodeJS – это методология построения архитектуры JavaScript-приложений и утилита сборки JS-кода, написанного по этой методологии.

Readme

DressCodeJS

DressCodeJS – это методология построения архитектуры JavaScript-приложений и утилита сборки JS-кода, написанного по этой методологии.

Утилита построена на Jossy – сборщике JS-файлов.

Содержание

Идея

Согласно DressCodeJS, приложение состоит из компонентов – классов и статических объектов, содержащих вложенные классы, объекты или самостоятельные функции.

Главные правила:

  1. Компонент именован в CamelCase – имя начинается с заглавной буквы. Это важно: сборщик по имени определяет, что такое есть компонент.
  2. Каждый компонент лежит в своём файле с именем, совпадающим с именем компонента: MyProject/App.js описывает компонент MyProject.App.
  3. Корневой объект (объект, содержащий вложенные классы) – это папка с именем, совпадающим с именем объекта, плюс файл index.js, в котором объект объявляется: папка MyProject/Forms/ с index.js, содержащим MyProject.Forms = {}, – это компонент MyProject.Forms.
  4. Зависимости не объявляются: сборщик смотрит, какие имена используются в коде, и сам подключает нужные файлы.

Пример. Имеем такую структуру файлов:

+ js-libs
|-- + MyProject
    |-- + Forms
    |    |-- index.js
    |    |-- Abstract.js
    |-- index.js
    |-- App.js

И примерное содержимое:

js-libs/MyProject/index.js

var MyProject = {};

js-libs/MyProject/App.js

MyProject.App = Bricks.inherit({
    constructor: function() {
        this._form = new MyProject.Forms.Abstract();
    }
});

js-libs/MyProject/Forms/index.js

MyProject.Forms = {};

js-libs/MyProject/Forms/Abstract.js

MyProject.Forms.Abstract = Bricks.inherit();

(Bricks – библиотека базовых классов, написанная в терминах DressCodeJS.)

Теперь, если мы где-либо вызовем new MyProject.App() и соберём файл, в результирующий файл попадут все перечисленные выше: сборщик увидел обращение к MyProject.Forms.Abstract и подключил нужный файл. А если вызовем new MyProject.Forms.Abstract(), то подключатся все файлы, кроме MyProject/App.js – он нигде не используется. И в обоих случаях подключится лишь необходимый кусок файла Bricks/index.js, в котором описана функция Bricks.inherit, а не весь файл.

В директории js-libs рядом с MyProject могут лежать и другие папки с исходниками – например, папка OtherProject, в которой описан корневой объект OtherProject.

Структура проекта

Типовой проект выглядит так:

project/
|-- .dresscode
|-- static/
|   |-- js-dev/           # скрипты, подключаемые на страницы сайта
|   |   `-- index.js
|   `-- js-libs/          # библиотека
|       `-- MyProject/
|           |-- index.js
|           `-- App.js
`-- node_modules/
  • Библиотека (js-libs) – каталог, который объявлен в файле .dresscode. В библиотеках нет запускаемого кода, только описания классов и функций: если собрать библиотечный файл со всеми зависимостями и подключить его на страницу, ничего не произойдёт.
  • Приложение (js-dev) – скрипты, подключаемые на страницы сайта: здесь создание всех необходимых объектов, их настройка и добавление в нужные части страницы. При выкладке сайта все скрипты из этой папки собираются утилитой dresscodejs в готовые js-файлы.

Файл .dresscode

Файл .dresscode объявляет, какие каталоги являются библиотеками. Это обычный текстовый файл: одна строка – один относительный (или абсолютный) путь до каталога-библиотеки:

static/js-libs
node_modules/<имя пакета>/lib

Для собираемого файла утилита ищет подходящий .dresscode: сначала в директории файла, затем в директории выше, и так далее, до корня. Обычно файл один на весь проект и лежит в корне проекта.

Если библиотека выпускается отдельным пакетом, в корне библиотеки лежит её собственный .dresscode – с ним утилита найдёт компоненты пакета.

Путь, по которому каталог не найден, молча пропускается: одна и та же библиотека может быть объявлена несколькими путями, если её расположение меняется в зависимости от layout установки. Например, при разработке библиотеки Quantum её зависит Botex: в .dresscode Botex указаны и node_modules/dresscode-quantum/lib (когда Quantum разрабатывается рядом), и ../../../node_modules/dresscode-quantum/lib (когда Botex установлен в проекте, куда npm поднял и Quantum в корень). В каждом layout существует ровно один из двух путей, отсутствующий ничего не даёт и ошибку не вызывает. Если же оба пути существуют одновременно, утилита завершится с ошибкой: одно и то же имя компонента достижимо из двух мест, и сборке не за чем выбирать. Проверьте .dresscode и оставьте один путь.

Структура библиотеки

Сборщик видит как компоненты:

  • index.js в папке – корневой объект с именем папки (MyProject/index.js → MyProject);
  • файлы Имя.js в подпапке – члены корневого объекта (MyProject/App.js → MyProject.App);
  • подпапки – вложенные объекты (MyProject/Forms/index.js → MyProject.Forms).

Имя папки или файла – это имя компонента: начинается с заглавной буквы и состоит из букв и цифр. Файлы в корне библиотеки и файлы со строчными именами сборщик не видит – положите их в папку.

При подключении компонента вместе с ним всегда подключается и объявление его корневого объекта (содержимое соответствующего index.js). Поэтому в результирующем коде родительские объекты MyProject и MyProject.Forms объявлены, даже если код напрямую их не использует.

Как работает сборка

Если в коде написано new MyProject.App(), то файл с компонентом MyProject.App автоматически попадёт в сборку – вместе со всем, что использует этот файл, и так далее. Объявлять зависимости не нужно.

Как сборщик понимает, где брать компоненты:

| Как написано | Что это | Что попадёт в сборку | |---|------------------------|--------------------------------------------------------------| | Foo.bar – со строчной буквы | свойство компонента | компонент Foo; из его файла – только используемые свойства | | Foo.Bar – в CamelCase | вложенный компонент | файл компонента Foo.Bar | | Foo.VERSION – целиком в капсе | «константа» компонента | компонент Foo |

Два момента, которые стоит знать:

  • В сборку попадает только нужное: из index.js корневого объекта, содержащего много свойств, попадут лишь те свойства, которые реально используются в коде.
  • Подключаемые файлы выводятся в начале выходного файла, перед его собственным кодом. Если файл завернут в скоуп (например, в замыкание) и подключаемые файлы должны попасть внутрь него, переместите блок подключений директивой //#imports в нужное место.

Все библиотеки, которые используются в коде, должны быть объявлены в .dresscode – иначе сборщик не увидит их компоненты.

Установка и настройка проекта

  1. Установите dresscodejs в devDependencies:

     npm install --save-dev dresscodejs
  2. Создайте директорию для подключаемых на страницы js-файлов – обычно static/js-dev.

  3. Создайте библиотечную директорию – обычно static/js-libs.

  4. В корне проекта создайте файл .dresscode и запишите в нём путь static/js-libs.

  5. Если нужны внешние библиотеки, установите их через npm в devDependencies и добавьте пути до каталогов-библиотек в .dresscode – например, node_modules/<имя пакета>/lib.

  6. Настройте Yaxy для сборки js-файлов на лету.

Внешние библиотеки подключаются по пути, а не по версии: в билд попадает ровно тот код, который сейчас лежит по указанному пути в node_modules. За версиями следит npm (package.json + package-lock.json): зафиксированные версии дают воспроизводимую сборку.

Сборка

Командная строка

./node_modules/.bin/dresscodejs -i static/js-dev/index.js -o static/js/index.js

Параметры:

| Параметр | Назначение | |---|---| | -i, --input <path> | (обязательно) файл, который нужно собрать, или папка: тогда собираются все js-файлы в ней (рекурсивно, см. Сборка папки) | | -o, --output <path> | файл результата; если не указан – результат в stdout (только в файл-режиме; в папочном режиме – папка и обязателен) | | -d, --debug | не переименовывать приватные имена (см. $$) + эквивалент --set debug | | --set <flag> | (можно многократно) булевы флаги для директивы //#if | | --layer <name> | собрать только код из слоя //#layer name; несовместимо с --layers | | --layers <name> | (можно многократно) базовый код плюс перечисленные слои; несовместимо с --layer | | --private-dict <path.json> | файл словаря приватных имён: читается перед сборкой, записывается после; обязателен, если код собирается в несколько выходных файлов (см. $$) | | --fail-on-errors | при ошибке сборки завершить процесс с кодом 1 (по умолчанию ошибка вкладывается в результат как throw new Error(...) и сборка завершается успешно) |

Пример боевой сборки с условной компиляцией и стабильным словарём:

./node_modules/.bin/dresscodejs -i static/js-dev/index.js -o static/js/index.js --set ie --private-dict private-names.json

Про ошибки: по умолчанию при ошибке сборки (неизвестная директива, компонент из #require не найден и т.п.) в результат вкладывается строка throw new Error("DresscodeError: …") – файл соберётся, но упадёт с диагностикой при выполнении. Для CI удобнее --fail-on-errors. Ошибка из-за дубликата имени компонента (см. Файл .dresscode) в любом режиме завершает сборку с кодом 1: результат такой сборки был бы некорректен.

Сборка папки

Если в -i передать папку, а не файл, собираются все js-файлы в ней (рекурсивно, включая вложенные каталоги). Каждый файл получает собственный файл результата в папке -o с сохранением структуры: js-dev/app/page.js → js/app/page.js.

./node_modules/.bin/dresscodejs -i static/js-dev -o static/js --private-dict private-names.json

Нюансы режима:

  • -o (папка) обязателен: несколько файлов в stdout вывести нельзя. Если путь в -o существует и является файлом – ошибка.
  • Вся папка собирается одним экземпляром DressCode: словарь приватных имён общий, так что одно и то же имя $$ получает одно и то же приватное имя во всех выходных файлах. Если код собирается в несколько выходных файлов, один и тот же --private-dict передавать во все сборки обязательно (см. $$) – иначе имена не будут стабильны между сборками.
  • Файлы собираются в детерминированном (отсортированном) порядке – индексы новых приватных имён стабильны между пересборками.
  • Сам выходной каталог в сбор не попадает, если он лежит внутри входного (напр. -i . -o build): пересборка не перебирает собственные результаты.
  • Семантика ошибок та же, что в файл-режиме: без --fail-on-errors ошибка вкладывается в результат соответствующего файла, остальные файлы собираются; с --fail-on-errors – сборка прерывается на первой ошибке, словарь не пишется, код выхода 1.

Использование из Node.js

var {DressCode} = require('dresscodejs');

var dresscode = new DressCode(
    false /* debug: не переименовывать приватные имена */,
    false /* failOnErrors: выбрасывать исключение при ошибке сборки */
);

dresscode.compile('static/js-dev/index.js', {debug: true}).then((result) => {
    fs.writeFileSync('static/js/index.js', result);
});

compile(file, context, labels, layers) – context – объект булевых флагов для //#if, labels – массив областей собираемого файла, которые попадут в вывод, layers – строка (собрать только этот слой) или массив строк (базовый код плюс перечисленные слои).

compileCode(virtualFile, content) – собирает строку кода как файл по указанному пути (виртуальный файл; его директория участвует в поиске .dresscode).

Прочитанные файлы кэшируются в экземпляре класса: один экземпляр DressCode удобно использовать для сборки нескольких связанных файлов. Кэш не перепроверяется по диску – если исходные файлы изменились, вызовите dresscode.clearCache() либо создайте новый экземпляр.

Директивы

Директива пишется на отдельной строке (//#имя аргумент) или инлайном в строке (/*#имя аргумент#*/).

| Директива | Назначение | |---|----------------------------------------------------------------------------------------------------------------------------------| | //#require Component | явно подключить компонент библиотеки по имени – вместе со всем, что он использует | | //#require Component.member | явно подключить компонент, но из его файла – только свойство member | | //#require Component['member'] | то же, что и Component.member, к квадратных скобках может быть только строковый литерал | | //#imports | вывести блок подключённых файлов в этой точке файла (по умолчанию блок выводится в начало файла) | | //#without file.js | исключить из сборки файл вместе с тем, что подключает он; удобно, когда код разделён на два билда (общая часть и часть страницы) | | //#if flag / //#endif | выводить код в зависимости от флага | | //#set flag / //#unset flag | задать / снять флаг | | //#layer name / //#endlayer | слой кода (см. ниже) |

#require в большинстве случаев не нужен, DressCode сам подключает зависимости. Явное указание #require может быть нужно, чтобы в базовый js-файл сайта попал код, который в этом файле не используется, но используется во всех остальных. Например, имеем компоненты MyProject.AbstractApp, MyProject.App1, MyProject.App2. App1 и App2 наследуют AbstractApp. Код собирается в файлы index.js, app1.js и app2.js. Имеет смысл вынести код компонента MyProject.AbstractApp в файл index.js, но он там нигде не вызывается. В этом случае в файле index.js указываем //#require MyProject.AbstractApp, а в файлах app1.js и app2.js не забываем про //#without index.js.

DressCode поддерживает и другие директивы Jossy.

Макрос $$

В компонентном файле (файле, описывающем компонент) сборщик заменяет все вхождения $$ на имя компонента. Допускается суффикс: $$, $$__suffix (буквы, цифры, _, -). Это позволяет задавать имена методов и CSS-классов, не пересекающихся с именами из других файлов.

  • Debug-сборка (-d): $$ заменяется именем компонента, в котором точки заменены подчёркиваниями: MyProject_Forms_Abstract.
  • Production-сборка: заменяется коротким приватным именем _0_, _1_, … Одно и то же имя получает одно и то же приватное имя в пределах сборки.

Стабильность имён между сборками – только через --private-dict: словарь читается перед сборкой и записывается после. Если код проекта собирается в несколько выходных файлов (страницы, бандлы), словарь обязателен: передавайте один и тот же файл словаря во все сборки – иначе «один и тот же» приватный член в разных файлах получит разные имена.

Сборки, работающие с одним и тем же файлом словаря, нельзя запускать параллельно: последовательность «прочитать – собрать – записать» не защищена от гонок, последний завершившийся процесс перезаписывает имена, добавленные остальными, – и в разных выходных файлах возникнут конфликты приватных имён. Запускайте такие сборки последовательно; пересборка, не добавившая новых имён, словарь не переписывает.

Подстановка происходит по всему файлу, в том числе внутри строк-литералов.

Условная сборка и слои

Флаги --set и директивы //#set///#if позволяют компилировать разные версии кода:

//#if lang_ru
alert('Русский интерфейс');
//#endif

//#if debug
console.log(...);
//#endif

//#if not debug
sendTelemetry();
//#endif

-d, --debug автоматически задаёт флаг debug – удобно для отладочных строк, которые никогда не попадают в боевые сборки.

Слои (//#layer) позволяют получить только код слоя, исключив базовый:

//#layer test
MyProject.App = FakeApp;
//#endlayer
realInit();
  • без параметров в сборку попадает только базовый код (realInit());
  • --layer test – только код слоя (MyProject.App = FakeApp);
  • --layers test – базовый код плюс слой.

Разработка через Yaxy

Для разработки удобнее не собирать файлы вручную, а использовать прокси-сервер Yaxy: он подменяет запрашиваемые сайтом ресурсы на локальные. Правая часть правила поддерживает протокол bin:, который выполняет команду и возвращает её stdout – этим и собирается js на лету:

# .yaxy
site.my/static/js/index.js => bin: dresscodejs -i ~/static/js-dev/index.js
site.my => localhost:3000

Запустите:

yaxy --config .yaxy

Каждый запрос к site.my/static/js/index.js в браузере получает свежесобранный файл.

Существующие библиотеки

Библиотеки, написанные в терминах DressCodeJS:

  • Bricks – базовые классы и функции (Bricks.inherit);
  • dresscode-quantum – Quantum: объекты с изменяющимся значением и синхронно обновляющиеся цепочки – удобные для синхронизации UI с состоянием;
  • dresscode-botex – Botex: шаблонизатор и библиотека построения UI;
  • dresscode-binary – Binary: кодирование данных в компактный бинарный формат (localStorage, трафик);
  • dresscode-resources – компилятор бинарных файлов в JS-код: встраивает ресурсы в сборку;
  • dresscode-polyfills – коллекция полифиллов для старых браузеров.

Ограничения

  • Код разбирается как ES2022 (esprima-next): ?., ??, class fields, BigInt поддерживаются; более новый синтаксис не поддерживается.