Hardhat: пакет, npx и структура проекта
- Зачем это нужно
- Не программа, а пакет
- Шесть шагов от пустой папки
- Первая ошибка: инструмент есть, проекта нет
- Три заготовки, и какую брать
- Что появилось в папке
- Одна строка, которую Hardhat переписал сам
- Откуда npx берёт команду
- Диапазон, замок и то, что на диске
- Семь часов без интернета
- Типичные ошибки
- Слова главы
- Тренажёр: набрать вслепую
- На чемпионате
- Куда углубиться
- Куда дальше: проверенные ресурсы
Зачем это нужно
Сеть есть. Контракты писать умеем. Но между исходником на Solidity и адресом в сети лежит работа, которую никто не делает руками: скачать компилятор нужной версии, собрать байт-код, разложить результат по файлам, отправить транзакцию развёртывания, дождаться её, достать адрес, прогнать тесты.
Hardhat — программа, которая делает всё это одной командой. Задание требует её прямым текстом, но дело не в требовании: без такого инструмента развёртывание десятка контрактов превращается в полдня ручной работы.
Эта глава — про то, откуда он берётся, куда ставится и почему у двух соседних папок могут быть разные его версии. Без этого следующая глава — про файл настроек — читается как заклинание.
Не программа, а пакет
Инструменты ставят двумя способами, и Hardhat относится ко второму.
Системная программа — как geth из прошлой главы. Один исполняемый файл, установленный на компьютер, один на всех. Версия одна, и она общая для всех проектов.
Пакет проекта — как Hardhat. Живёт внутри папки проекта, в node_modules. Устанавливается вместе с проектом, версия своя у каждого.
Разница не косметическая. Задание на чемпионате приносят в готовом виде, решение сдают папкой, а принимающий разворачивает его у себя. Если версия инструмента прописана в проекте, у всех получится одно и то же. Если она «какая стояла на компьютере» — не получится ни у кого.
Ставить Hardhat глобально (npm i -g) можно, но не нужно: первый же проект с другой версией сломает второй. Все руководства последних лет ставят его только в проект — и мы тоже.
Шесть шагов от пустой папки
Первая модель проходит путь с нуля и печатает, что происходит на каждом шаге:
── шаг 1: пустая папка ──
файлов: 0
── шаг 2: npm init -y ──
появился package.json, в нём:
name: hh-fresh
version: 1.0.0
main: index.js
type: commonjs
── шаг 3: npm i --save-dev hardhat ──
added 50 packages, and audited 51 packages in 9s
found 0 vulnerabilities
заняло: 8.7 c
папок в node_modules : 30
размер node_modules : 81M
версия в package.json: ^3.16.0
версия на диске : 3.16.0
Три вещи здесь стоят внимания.
--save-dev — значит «нужен для разработки». Hardhat не попадает в то, что уезжает в сеть: в блокчейн уезжает только байт-код контракта. Поэтому он записывается в отдельный список зависимостей.
50 пакетов вместо одного. Hardhat притащил за собой всё, на что опирается сам. Это норма для этой экосистемы, и именно поэтому node_modules никогда не кладут в репозиторий.
"type": "commonjs" в только что созданном описании — та самая строка из главы про модули. Запомните её: через полминуты она изменится сама.
Первая ошибка: инструмент есть, проекта нет
── шаг 4: запускаем hardhat, ничего больше не сделав ──
Error HHE3: No Hardhat config file found.
You can initialize a new project by running Hardhat with --init
For more info go to https://hardhat.org/HHE3 or run Hardhat with --show-stack-traces
Установленный пакет сам по себе ничего не умеет: ему нужен файл настроек, по которому он поймёт, что за проект перед ним. Нет файла — нет проекта, и любая команда упирается в этот отказ.
Заодно обратите внимание на форму сообщения: код ошибки (HHE3), человеческое объяснение, подсказка, что делать, и ссылка. Так выглядят все ошибки Hardhat — по коду можно искать, а не гадать.
Три заготовки, и какую брать
── шаг 5: какие заготовки есть ──
Available templates:
- node-test-runner-viem
- mocha-ethers
- minimal
minimal — только файл настроек, дальше сами. Годится, когда точно знаешь, что делаешь.
node-test-runner-viem — тесты встроенным средством Node, работа с сетью через библиотеку viem.
mocha-ethers — тесты через mocha, работа с сетью через ethers. Берём эту: ethers мы уже видели в главе про запросы к узлу, а в этой связке написано подавляющее большинство примеров в интернете.
── шаг 6: npx hardhat --init --template mocha-ethers ──
npm install --save-dev "@nomicfoundation/hardhat-toolbox-mocha-ethers@^3.0.7" …
added 212 packages, and audited 263 packages in 30s
Dependencies installed
Project initialized
заняло: 35.7 c
Что появилось в папке
── что появилось в папке ──
.gitignore
AGENTS.md
README.md
contracts/Counter.sol
contracts/Counter.t.sol
hardhat.config.ts
ignition/modules/Counter.ts
package-lock.json
package.json
scripts/send-op-tx.ts
test/Counter.ts
tsconfig.json
── и сколько всё это весит ──
папок в node_modules : 167
всего пакетов в lock : 293
node_modules : 188M
исходники и настройки: 204K
Разбор по назначению:
hardhat.config.ts— единственный обязательный файл. Версия компилятора, список сетей, подключаемые части. Ему посвящена следующая глава целиком.contracts/— исходники на Solidity. Заметьте два файла: обычный контракт иCounter.t.sol— тест, тоже написанный на Solidity.test/— тесты на TypeScript.ignition/modules/— описания развёртывания: что за чем разворачивать и с какими параметрами.scripts/— обычные скрипты, запускаемые вручную.tsconfig.json— настройки компилятора типов для этого проекта..gitignore— список того, что не кладут в репозиторий. Первой строкой тамnode_modules.
Соотношение 204 КБ против 188 МБ — главное число этой секции. В репозиторий кладут первое; второе восстанавливается одной командой.
Одна строка, которую Hardhat переписал сам
Сравните описание проекта до и после создания:
// после npm init -y
"type": "commonjs"
// после npx hardhat --init
"type": "module"
Это та самая строка из главы про модули, и переписана она не случайно: Hardhat третьей версии работает только с современной системой модулей. Файл настроек и тесты у него написаны через import, а не через старую форму подключения.
Отсюда следствие, которое стоит держать в голове: в этом проекте все файлы .ts и .js читаются как современные модули. Пример из интернета, написанный под Hardhat 2 со старой формой подключения, здесь упадёт с уже знакомой ошибкой про require.
Заодно tsconfig.json пришёл с параметром "verbatimModuleSyntax": true. Он означает «не переписывай мои импорты»: как написано, так и останется. Ровно то, о чём была секция про расширения в путях.
Откуда npx берёт команду
Вторая модель запускает одну и ту же команду в трёх разных папках:
── есть ли hardhat в системе вообще ──
which hardhat → не найдено: глобально не установлен
── что такое node_modules/.bin/hardhat ──
новый проект: node_modules/.bin/hardhat → ../hardhat/dist/src/cli.js
старый проект: node_modules/.bin/hardhat → ../hardhat/internal/cli/bootstrap.js
── одна и та же команда в двух папках ──
hh-fresh: npx hardhat --version → 3.16.0 (1.00 c)
hh-old : npx hardhat --version → 2.29.1 (1.03 c)
── а в папке, где проекта нет ──
npm warn exec The following package was not found and will be installed: hardhat@2.22.19
заняло: 6.7 c — npx полез в интернет
Порядок поиска у npx такой: сначала node_modules/.bin текущей папки, потом то же самое в папках выше, и только если нигде не нашлось — установка из интернета во временный каталог.
node_modules/.bin/hardhat — не программа, а ссылка на файл внутри установленного пакета. Видно даже, что в разных версиях она указывает на разные файлы: путь у третьей версии отличается от пути у второй.
Глобально Hardhat не установлен вовсе — which его не находит. И тем не менее команда работает в обеих папках проекта. Это и есть смысл пакета проекта.
Последняя строка прогона — про чемпионат. npx в папке без проекта уходит в интернет. В модуле интернета нет: команда, которая дома отрабатывает за шесть секунд, там просто не выполнится. Единственная защита — заранее установленные зависимости в папке проекта.
Диапазон, замок и то, что на диске
Третья модель удаляет node_modules и восстанавливает его:
── что переживает удаление node_modules ──
до : node_modules 188M, файлов проекта 14
после : node_modules нет, файлов проекта 14
команда на месте? нет: node_modules/.bin/hardhat исчез вместе с папкой
── npm ci: восстановить ровно то, что записано в замке ──
added 262 packages, and audited 263 packages in 3s
заняло: 3.3 c (из кеша, без интернета)
версия: 3.16.0
── а если package.json и замок разошлись ──
npm error code EUSAGE
npm error `npm ci` can only install packages when your package.json and
package-lock.json or npm-shrinkwrap.json are in sync. Please update your
lock file with `npm install` before continuing.
Три файла говорят о версии разное, и путать их нельзя.
package.json: "hardhat": "^3.16.0" — это диапазон. Значок ^ означает «любая версия 3.x, начиная с 3.16.0». Через полгода та же строка установит 3.20 — и поведение проекта может измениться.
package-lock.json: "version": "3.16.0" — это ровно одна версия, и так для всех 293 пакетов, включая те, о которых мы никогда не слышали.
npm i может поставить новее в рамках диапазона и переписать замок. npm ci ставит строго по замку и замок не трогает вовсе. Поэтому на чужой машине и в проверке используют второе.
Восстановление заняло 3,3 секунды и прошло из кеша, без интернета — потому что эти пакеты уже скачивались на эту машину раньше. Это важная деталь для следующей секции.
Семь часов без интернета
Условия модуля: интернета нет, принести с собой нельзя ничего. Значит, всё, что обычно скачивается, должно быть скачано заранее — организаторами, на тот компьютер, за которым вы сидите.
Что именно скачивается и когда:
| что | когда тянется | сколько |
|---|---|---|
пакеты из node_modules | npm i или npm ci | 188 МБ, 293 пакета |
| компилятор Solidity | первая команда сборки | по версии, отдельно каждая |
npx без проекта | каждый раз | размер пакета |
Порядок первых минут, который стоит отработать:
- проверить, что папка проекта уже содержит
node_modules— если да, ничего не трогать; - если нет —
npm ci, и смотреть, прошло ли оно; кеш на машине может быть, а может и не быть; - сразу запустить сборку один раз: если компилятор не скачан, лучше узнать об этом на первой минуте, а не на пятом часу;
- запомнить версию:
npx hardhat --version. Все дальнейшие вопросы «почему пример не работает» начинаются с неё.
Вторая и третья версии Hardhat несовместимы по файлу настроек. Прежде чем брать пример из интернета, посмотрите на его hardhat.config: если там require и module.exports — это Hardhat 2, и здесь он не заработает.
Типичные ошибки
Error HHE3: No Hardhat config file found. Запустили не из той папки. Hardhat ищет настройки в текущей папке и выше — так же, как npx ищет команду.
npm warn exec The following package was not found and will be installed. Эта строка означает, что npx не нашёл команду в проекте и полез в сеть. Дома незаметно, на чемпионате — отказ.
npm error EUSAGE. Кто-то поправил список зависимостей руками и не обновил замок. Лечится обычным npm i, после которого замок надо обязательно положить в репозиторий вместе с изменением.
Пример из интернета не запускается. Первым делом — версия. Hardhat 2 и Hardhat 3 отличаются файлом настроек, системой модулей и способом подключения к сети. Между ними нельзя «немного поправить».
node_modules в репозитории. Формально работает, практически — 188 МБ мусора, конфликты при слиянии и путаница с версиями. Для этого и существует .gitignore, который Hardhat положил сам.
Слова главы
- Пакет проекта — инструмент, установленный в папку, а не в систему; версия своя у каждого проекта.
--save-dev— «нужен только при разработке»: в результат не попадает.npx— запустить команду из пакета: сначала ищет в проекте, потом выше, потом в сети.node_modules/.bin— папка со ссылками на команды установленных пакетов.- Файл настроек — без него Hardhat отказывается работать:
HHE3. - Заготовка проекта — готовый набор файлов; берём тот, что на mocha и ethers.
- Диапазон версий —
^3.16.0означает «любая 3.x не ниже указанной». - Замок версий — точные версии всех 293 пакетов; ставится командой
npm ci.
Тренажёр: набрать вслепую
Цель: скорость ≥ 100 зн/мин, точность ≥ 88%
npm init -y
На чемпионате
Задание сдают папкой, и папку эту разворачивает не автор. Отсюда три правила, которые ничего не стоят, пока про них помнят.
Замок версий — в репозиторий обязательно. Без него принимающий получит другие версии пакетов и, возможно, другое поведение.
node_modules — никогда. Но в инструкции к решению напишите одну строку: «установка — npm ci». Иначе проверяющему придётся угадывать.
Версию инструмента назовите явно. Одна строка в README — «Hardhat 3.16, Node 24» — снимает половину вопросов ещё до запуска.
И последнее, про время. Создание проекта заняло 35 секунд с установкой 212 пакетов. Восстановление из кеша — 3 секунды. Скачивание компилятора — ещё столько же на первую сборку. Это не те цифры, из-за которых стоит нервничать, но и не ноль: первую сборку лучше сделать сразу, а не в конце.
Куда углубиться
- Что ещё умеет
npx— запуск конкретной версии одной командой, без установки в проект. - Как устроены зависимости зависимостей — почему из одного пакета вырастает 293.
npm audit— отчёт об известных уязвимостях в установленном; при создании проекта он сразу показал несколько.- Другие инструменты той же роли — Foundry: те же задачи, но тесты пишут на Solidity, а не на TypeScript.
Сводная проверка по всей главе: 8 вопросов, 5:00 на всё, без подсказок по ходу. Вопросы показываются по одному, ответ изменить нельзя. Если время выйдет — экзамен завершится с тем, что успел ответить. Пересдавать можно сколько угодно раз.
Куда дальше: проверенные ресурсы
- Hardhat: Getting started — официальное начало работы с третьей версией.
- Hardhat: Migrating from Hardhat 2 — чем именно отличаются версии.
- npm: package.json — зависимости, диапазоны версий, поля описания.
- npm ci — когда и почему используют именно её.
- npx — порядок поиска команды и запуск без установки.
Комментарии
Обсуждение живёт в GitHub Discussions и грузится с чужого домена — поэтому только по нажатию.