Перейти к содержанию
Mercury
Русский
Дизайн книга
Меню
Русский

Инструменты: от нового проекта до архива

Создайте приложение, проверьте исходники и подготовьте пакет с проверкой у отдельного потребителя.

Этот урок описывает сборку mx из исходников 0e08e7af. Она сообщает mx 0.1.1; публикация соответствующего выпуска ещё не подтверждена. Наличие этой версии в выводе не доказывает, что публичный архив или npm-пакет содержит те же команды. Для установки сначала проверьте готовность выбранного пути.

Создайте приложение из кеша

mx new hello создаёт приложение на Hyperscript и Mercury UI из локального кеша модулей. Сначала заполните кеш при доступной сети. Если у вас уже настроена доверенная база контрольных сумм, сохраните эту настройку. Для первого заполнения без подписанной базы установщик использует такое разовое исключение:

MXNOSUMDB='registry.npmjs.org/fiberfx/*' mx mod cache

Это явный выбор доверия: для перечисленных пакетов Mercury контрольные суммы принимаются без подтверждения подписанной базой. Исключение действует только в этом запуске; не переносите его в постоянные настройки оболочки. Без настроенной базы или такого исключения первое заполнение может завершиться отказом. Просмотрите итог команды, включая отдельное сообщение о загрузке компилятора TypeScript.

Затем, в каталоге для нового проекта:

mx new hello
cd hello
mx verify
mx dev

Откройте адрес, который напечатал сервер, и проверьте работу страницы. После остановки сервера через Ctrl-C выполните mx build. Генератор создаёт package.json, mx.mod, mx.sum, index.html, src/main.tsx и установленное хранилище зависимостей. Версии Hyperscript и UI берутся из кеша; они не зашиты в команду. Эта сборка записывает mx 0.1.1 в новый mx.mod. Не меняйте версии в существующих mx.mod и mx.work только ради совпадения с номером исполняемого файла.

Непустой каталог и отсутствующие модули в кеше дают отказ с кодом 1. Не удаляйте существующий проект: выберите другое имя. Отсутствующее имя даёт код 2. Создание и работа без сети возможны после заполнения нужных кешей, а не на пустой машине.

Проверьте и исправьте исходники

Выполните эти команды из корня отдельного учебного проекта без зависимостей, описанного в следующем разделе:

mx lint
mx fmt --check
mx typecheck
mx quality

lint ищет проблемы в коде; fmt --check проверяет оформление без записи. typecheck проверяет проект TypeScript и требует конфигурацию, описанную ниже. quality выполняет все три проверки, даже если одна уже завершилась ошибкой, и возвращает наибольший код завершения.

Для исправлений используйте:

mx lint --fix
mx fmt
mx quality --fix

lint --fix применяет безопасные автоматические исправления, fmt перезаписывает оформление. quality --fix совмещает исправление lint и форматирование, затем оценивает результат. Исправление одной проблемы не означает успех всей проверки: например, лишнее переименование импорта устраняется автоматически, а debugger остаётся ошибкой. Просмотрите diff и повторите проверки; повторное форматирование уже оформленного файла не должно давать новых изменений.

Код Результат этих проверок
0 проверка выполнена, ошибок нет; предупреждения возможны
1 найдены ошибки или требуется форматирование
2 неверные аргументы
3 инструмент недоступен либо проверку не удалось выполнить

Для автоматизации добавьте --json. Отдельная команда возвращает объект с полями stage, outcome, detail, files, fixed, findings; quality — массив результатов этапов. Оценивайте и JSON, и код процесса. Формат ответа относится к этим командам, а не ко всему mx.

Проверьте типы проекта

mx typecheck
mx typecheck --root /path/to/app
mx typecheck tsconfig.json

Без явного файла команда требует tsconfig.json в корне проекта.

Для первого упражнения создайте отдельный каталог course-typecheck с подкаталогом src и четырьмя файлами. Этот проект не использует зависимости:

package.json:

{"name":"course-typecheck","type":"module"}

mx.mod:

module registry.npmjs.org/course-typecheck

mx 0.1.1

tsconfig.json:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "strict": true,
    "skipLibCheck": true
  },
  "include": ["src"]
}

src/main.ts:

export const value: number = 1;

Из каталога course-typecheck выполните mx typecheck. Ожидается код 0: один файл проверен, ошибок и предупреждений нет; файлы проекта не изменяются. skipLibCheck: true исключает проверку содержимого файлов деклараций, но не ошибки собственного кода.

Теперь добавьте src/type-error.ts:

export const x: number = "s";

Повторный mx typecheck должен вернуть код 1 с TS2322: строку нельзя присвоить переменной типа number. Удалите только созданный для упражнения src/type-error.ts и выполните mx quality --json; все три этапа должны пройти с кодом 0.

mx запускает отдельный нативный компилятор TypeScript 7.0.2. Его архив закреплён контрольной суммой SHA-256 и хранится в tools внутри кеша модулей. mx mod cache пытается загрузить его заранее и отдельно сообщает неудачу; заполненные пакеты ещё не доказывают наличие компилятора. При первой проверке загрузка также возможна, если сеть разрешена.

Импорты разрешает mx. Временная конфигурация ссылается на найденные модули и их декларации, не использует node_modules и автоматически подключаемые ambient-типы. Проверка не записывает конфигурацию или скомпилированные файлы в проект.

Если MXPROXY=off или цепочка содержит только file:// и off, загрузка компилятора запрещена. Уже закешированный компилятор можно использовать без сети; отсутствующий даёт unavailable и код 3. Архив с неверной контрольной суммой даёт could not run и код 3. Код 1 означает найденные ошибки типов, а не отсутствие компилятора. При коде 3 восстановите нужный инструмент или конфигурацию и повторите проверку.

Проверьте созданное приложение

Вернитесь в приложение hello из первого раздела. Создайте в его корне tsconfig.json:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "jsx": "react-jsx",
    "jsxImportSource": "@fiberfx/hyperscript",
    "strict": true,
    "skipLibCheck": true
  },
  "include": [
    "src"
  ]
}

Выполните mx typecheck из каталога hello. Для использованных в упражнении пакетов Hyperscript и UI 4.1.1 ожидается typecheck: 0 errors, 0 warnings in 1 file и код 0. Строгая проверка остаётся включённой: mx находит декларации пакетов и подключает типы для обслуживаемых им импортов CSS.

Добавьте src/planted.ts со строкой export const x: number = "s"; и повторите проверку. Ожидается TS2322 в строке 1, столбце 14 и код 1. Удалите только этот учебный файл: следующая проверка снова должна завершиться с кодом 0. Проверка типов не меняет файлы проекта. Правила кеширования компилятора из предыдущего упражнения действуют и здесь.

mx test

usage: mx test [<path>...] [--root <dir>] [--timeout <seconds>] [--filter <words>]

mx test выполняет тесты модуля в браузере без графического интерфейса, который mx запускает сам, используя тот же граф, который обслуживает mx dev. Успех не предполагается: каждый результат должен вернуться в mx. Запуск без тестов, с потерянным отчётом или без завершения считается неуспешным.

  • Какие файлы. Все файлы *.test.* или *.spec.* с расширением js, mjs, jsx, ts, mts или tsx под корнем. В node_modules, dist, target и coverage поиск не выполняется. Если файлов нет: mx test: no tests under <root>, код 1.
  • Сначала импорты. Если импорты тестового файла не разрешаются, до запуска браузера фиксируется ошибка с его именем: FAIL <url> > (its imports): <why>. Остальные файлы продолжают выполняться.
  • Браузер. Его задаёт MX_BROWSER. Иначе mx ищет самый новый Chromium, затем headless shell Playwright в PLAYWRIGHT_BROWSERS_PATH, ~/Library/Caches/ms-playwright или ~/.cache/ms-playwright.
  • --timeout ограничивает весь запуск, по умолчанию 120 с: the run didn't end within <n> s. Отдельно определяется зависание страницы, которая молчит ещё 30 с после истечения тайм-аутов всех её тестов; оставшаяся часть этого файла не выполняется.
  • --filter <words> оставляет тесты, у которых <file> > <name> содержит заданный текст, а остальные считает исключёнными фильтром.
Код завершения Значение
0 все тесты прошли
1 тест упал, ни один не выполнялся или запуск нарушен
2 ошибка использования
3 проверку выполнить не удалось: браузер не найден

Код 3 никогда не означает успех. mx перечисляет проверенные пути, затем выводит Set MX_BROWSER to a Chromium binary..

Что импортирует тестовый файл

Тестовый файл импортирует из vitest, но карта импортов страницы направляет этот импорт в собственную среду выполнения mx, а не в Vitest. Она предоставляет:

  • describe, it и test, а также хуки beforeAll, afterAll, beforeEach и afterEach;
  • expect с проверками;
  • vi: vi.fn, vi.spyOn, vi.stubGlobal, подменённые таймеры (vi.useFakeTimers, vi.advanceTimersByTime, vi.runAllTimers и другие), а также vi.setSystemTime;
  • expectTypeOf и assertType, которые ничего не проверяют во время выполнения: типы относятся к работе компилятора;
  • собственный visit mx.

Как и в Vitest, тесту отводится 5 с, хуку — 10 с. vi.mock отсутствует: его вызов выбрасывает vi.mock is not in mx test: a module is mocked by import map, later (mercury.mx.13).

Управление страницей через visit

async function visit(url, { width = 0, height = 0, scale = 1, mobile = false, scheme = null, ready = null } = {})

visit открывает страницу HTTP-origin в браузере текущего запуска через протокол DevTools, эмулируя заданные размер области просмотра, масштаб, мобильный режим и scheme как prefers-color-scheme. Промис разрешается, когда CSS-селектор ready находит элемент, а без него — после загрузки страницы. Если width или height не заданы, сохраняются размеры браузера.

Возвращённый объект предоставляет два метода:

  • evaluate(fn, ...args) выполняет fn на этой странице и разрешает промис её JSON-значением либо отклоняет его выброшенной ошибкой;
  • close() закрывает страницу.

Незакрытая страница visit закрывается после завершения её тестового файла. Если DevTools браузера перестаёт работать, mx завершает файл с указанием его имени.

Как читать результат запуска

Одна строка на тест, затем итоговые числа:

ok    <file> > <name>
skip  <file> > <name>
FAIL  <file> > <name>: <message>
mx test: <passed> passed, <failed> failed, of <total>

По карте исходников компилятора стек ошибки привязывается к исходной строке. Запуск также проверяет собственную полноту:

  • если число тестов со страниц не совпадает с числом полученных отчётов, выводится the pages counted N tests and M reports arrived и запуск считается неуспешным;
  • при --filter выводится число исключённых тестов;
  • если фильтр исключил все тесты, выводится no tests ran: the filter matched none, код завершения — 1.

mx lsap

usage: mx lsap [--mcp] | mx lsap --version

mx lsap запускает языковой сервер Hyperscript, hyperscript-lsap, который должен быть установлен в том же каталоге, что и mx. Другой сервер mx не запускает и запасного варианта не использует. Он передаёт серверу собственный путь через HYPERSCRIPT_LSAP_MX, чтобы импорты разрешались этим экземпляром mx, затем завершается с кодом сервера. Во время сеанса stdout сервера несёт протокол, поэтому сам mx туда ничего не пишет.

Релиз, собранный release.sh, содержит сервер: hyperscript-lsap-<target> лежит рядом с mx-<target>. Его нужно установить в тот же каталог, что и mx, под именем hyperscript-lsap. Исключение — Windows. Сервер поддерживает только Unix, поэтому Windows-релиз содержит лишь mx, а mx lsap отказывает с The language server isn't built for Windows in this release.

  • --mcp передаётся серверу без изменений.
  • --version выводит версии mx и установленного сервера. Смотрите фактический вывод своей установки: версии двух программ не обязаны совпадать. Например, проверенный архив вывел:
mx 0.1.1
hyperscript-lsap 0.1.0

Если рядом с mx нет сервера, команда завершается с кодом 1 и выводит Error: mx lsap found no language server beside mx., проверенный путь и Put hyperscript-lsap in <dir>: a release of mx ships it there..

Сервер написан на Rust. Сейчас это перенесённый языковой сервер TypeScript, собранный по правилам Mercury; собственные сведения Mercury он пока не предоставляет.

mx run

У mx run две формы, выбор между которыми определяется каталогом.

Задача. Если в package.json текущего каталога есть скрипт с указанным именем, mx run <name> запускает его как кешируемую задачу. Ключ — sha256 от:

  • скрипта, его аргументов и положения модуля в рабочей области;
  • NODE_ENV и имён, перечисленных в MXRUN_ENV;
  • sha256 каждого входного файла и используемых инструментов.

При попадании в кеш mx проверяет каждый сохранённый объект, восстанавливает выходные файлы и воспроизводит журнал: mx run: <member> <task>: hit <key>, restored N files. При промахе указывается первое различие: mx run: <member> <task>: miss (<why>). Сохраняются только результаты с кодом 0. Каталог задач задаёт MXRUN_CACHE; без него используется $XDG_CACHE_HOME/mx/run, а если эта переменная не задана — ~/.cache/mx/run. MXCACHE относится к модулям и не меняет каталог задач.

На macOS и Linux два кеша имеют разные назначения:

Переменная Назначение Каталог по умолчанию
MXCACHE модули и инструменты, включая TypeScript ~/.mercury/modules
MXRUN_CACHE результаты задач mx run $XDG_CACHE_HOME/mx/run, иначе ~/.cache/mx/run

Флаги ставятся перед именем скрипта:

Флаг Действие
--no-cache выполнить скрипт, не читая и не сохраняя запись кеша
--verify при попадании в кеш повторно выполнить задачу и сверить выходные файлы с сохранёнными
-r, --recursive выполнить задачу у каждого участника рабочей области
--filter <member> выполнить задачу у названных по каталогу или имени пакета участников и у всех участников, от которых они зависят
-j <n> число параллельных задач; по умолчанию число процессоров, но не более 4

-r и --filter требуют mx.work: mx run: -r and --filter need an mx.work at or above <dir>. Скрипт mx test никогда не кешируется, поскольку mx test читает всю рабочую область из исходников: mx run: <member> <task>: uncached: mx test reads the workspace from source.

Хост. Любое другое имя сохраняет форму для хоста: mx run <command> [args] собирает хост (MX3), затем передаёт управление команде, сохраняя её сигналы и код завершения. Пример из исходников mx — mx run mix phx.server.

Если имя не задано, mx run отвечает mx run: a command is required.

Подготовьте архив пакета

Из каталога библиотеки с корректным package.json и готовыми выходными файлами:

mx pack --npm

Можно передать несколько каталогов: mx pack --npm <package dir>…. Команда записывает архивы .tgz в .mx/pack/ каждого пакета. Состав определяется package.json, включая files и карту экспортов; одинаковые входные файлы дают одинаковые байты архива.

Затем mx проверяет архив на отдельном потребителе вне рабочих областей: устанавливает пакет и peer-зависимости, разрешает экспортируемые пути, импорты доступных через них модулей и импорты деклараций типов. Для зависимостей нужны подходящие прокси или заполненный кеш; проверка может обращаться к сети.

Отсутствующие, неверные или устаревшие результаты сборки дают отказ с кодом 1. Если в пакете есть скрипт build, выполните mx run build и повторите упаковку. Архив, не прошедший проверку потребителем, удаляется. Существование .tgz само по себе не заменяет успешный итог команды.

Если добавить в package.json скрипт "pack": "mx pack --npm", mx run pack может восстановить архив из кеша задачи, но проверка потребителем выполняется заново и при попадании в кеш. Упаковка ничего не публикует: отправка в реестр — отдельное действие.