Разработчик представил собственный ModuleLoader для Roblox

Первый фреймворк с нуля

Разработчик опубликовал свой ModuleLoader и попросил более опытных коллег оценить работу. Это его первый серьёзный фреймворк, созданный полностью самостоятельно, без использования готовых библиотек. Автор прямо признаёт, что в сети есть загрузчики модулей получше, но написал собственный ради учебного опыта и потому что было скучно.

Из курсовых знаний по структурам данных он перенёс подход к обработке зависимостей. Единственное участие ИИ ограничилось двумя вещами: форматирование текстов ошибок, чтобы они звучали профессиональнее, и помощь в исправлении бага в реализации алгоритма Кана. Шаблонные комментарии с разделителями (сервисы, константы, типы, модуль) автор использует во всех своих крупных скриптах и подчёркивает, что это не результат генерации.

Фазы загрузки и зависимости

Загрузчик проходит пять фаз: Discovering, Requiring, Initializing, Starting и Ready. На этапе обнаружения он рекурсивно обходит указанные корневые Instance, собирает все ModuleScript, отфильтровывая те, что помечены атрибутом LoaderIgnore или имеют суффиксы.spec и.test из списка IGNORE_SUFFIXES. Дубликаты имён вызывают ошибку сразу на этом шаге.

Далее каждый модуль загружается через require() внутри xpcall с замером времени. Если результат является таблицей и содержит функцию Init или Start, модуль помечается как системный, а его зависимости и приоритет читаются из полей Dependencies и Priority. Порядок инициализации вычисляется топологической сортировкой (алгоритм Кана): строится граф зависимостей, подсчитывается входящая степень, узлы с нулевой степенью идут первыми, при равенстве приоритета решается алфавитный порядок.

Циклические зависимости детектируются: если после обработки в очереди остались узлы со степенью больше нуля, все они помечаются как Failed с сообщением о цикле. Функции Start() запускаются асинхронно через task.spawn, и если за 10 секунд (READY_WARN_AFTER) часть модулей так и не завершилась, выдаётся предупреждение с именами зависших.

Публичный интерфейс модуля

Внешний API включает восемь функций. Load(options) запускает весь цикл загрузки и может быть вызвана только один раз за время работы (assert проверяет фазу Idle). Has(name) возвращает, зарегистрирован ли модуль под данным именем, GetPhase() и IsReady() дают текущее состояние, OnReady(callback) позволяет подписаться на завершение загрузки, а WaitUntilReady() блокирует корутину до готовности.

GetReport() возвращает клон таблицы всех записей Entry со статусами и временами, PrintReport() выводит в консоль сводную таблицу: для каждого модуля - статус, тип (System или Library), время require, init и start в миллисекундах, а при ошибке - первую строку сообщения. Конфигурация задаётся константами DEFAULT_PRIORITY = 100, SLOW_REQUIRE = 2, SLOW_INIT = 0.25, READY_WARN_AFTER = 10.

Автор подчёркивает, что модуль вернул как обычный return module в конце файла, и просит сообщество обратить внимание на архитектуру: разделение на приватные функции с префиксом _ и публичный API, строгую типизацию через --!strict и export type для Status, Phase, Entry и Options. Обратная связь по структуре, производительности или стилю кода будет воспринята как урок.

1 view·1 share