Модуль автозагрузки для вызова функций из файлов указанной директории.
- Не требует настройки перед использованием (zero configuration).
- Обход файлов строго в указанной директории (без рекурсии).
- Передача любого количества аргументов в вызываемые функции.
- Гарантированный порядок вызова благодаря алфавитно-числовой сортировке.
- Поддержка асинхронных функций с ожиданием завершения выполнения.
- Вызов только
export defaultфункций (классы и другие типы пропускаются). - Автоматическая фильтрация тестовых файлов (
*.test.js,*.spec.js). - Быстрая остановка выполнения (fail-fast) при возникновении ошибок.
При разработке серверных приложений типична ситуация, когда точка входа превращается в длинный список ручных импортов и вызовов подключения источников данных, регистрации моделей, объявления маршрутов и т.п. Каждый новый файл требует правки главного модуля, что увеличивает риск ошибки и усложняет поддержку кода по мере роста проекта.
import {defineRoleModel} from './models/role-model.js';
import {defineUserModel} from './models/user-model.js';
import {defineRoleRoutes} from './routes/role-routes.js';
import {defineUserRoutes} from './routes/user-routes.js';
// const orm = ...
// const router = ...
defineRoleModel(orm);
defineUserModel(orm);
defineRoleRoutes(router);
defineUserRoutes(router);Модуль избавляет от необходимости перечислять подключаемые файлы вручную.
Достаточно поместить файлы в отдельную директорию, а функция invokeFromDir
найдет их, импортирует и вызовет функции, экспортированные по умолчанию,
в предсказуемом порядке.
import {invokeFromDir} from '@e22m4u/js-autoload';
// const orm = ...
// const router = ...
await invokeFromDir(`${import.meta.dirname}/models`, orm);
await invokeFromDir(`${import.meta.dirname}/routes`, router);Такой подход упрощает организацию инициализации приложения, когда каждый файл директории отвечает за свою часть настройки и получает произвольный набор аргументов, будь то контейнер сервисов, схема базы данных или объект маршрутизатора. Логика запуска остается компактной, а порядок выполнения явным и читаемым прямо из структуры файловой системы.
npm install @e22m4u/js-autoloadМодуль поддерживает ESM и CommonJS стандарты.
ESM
import {invokeFromDir} from '@e22m4u/js-autoload';CommonJS
const {invokeFromDir} = require('@e22m4u/js-autoload');Функция invokeFromDir(dirPath, ...args) обходит указанную директорию,
находит JavaScript-файлы, импортирует их и вызывает содержащиеся в них
функции, если они переданы как экспорт по умолчанию.
- Экспорт по умолчанию для ESM
export default function() { ... } - Экспорт по умолчанию для CJS
module.exports = function() { ... }
Примечание. В примерах ниже используются числовые префиксы (01-, 02-
и т.д.) исключительно для наглядной демонстрации алфавитно-числового порядка
вызова файлов. На практике использовать числовые префиксы не рекомендуется,
так как при добавлении нового файла в начало или середину списка может
потребоваться переименование нескольких соседних файлов для сохранения нужного
порядка. Модуль ориентирован прежде всего на управление порядком вызова групп
файлов, где каждая группа обрабатывается отдельным вызовом invokeFromDir.
Например, сначала модели, затем маршруты, затем middleware и т.д. Порядок
внутри одной группы обычно не имеет значения, если файлы не зависят друг
от друга.
Приведенный ниже пример предназначен для стандарта ESM. Данное уточнение
обусловлено применением оператора await на верхнем уровне модуля. Подобный
синтаксис нативно поддерживается ESM режимом, но вызывает синтаксическую
ошибку в CommonJS. Реализация аналогичной логики для CommonJS описана
в разделе «Поддержка CommonJS».
Структура файлов:
project/
scripts/
01-init.js
02-process.js
index.js
Содержимое 01-init.js
export default function(context) {
context.initialized = true;
}Содержимое 02-process.js
// имитация асинхронного выполнения
export default async function(context) {
context.status = 'done';
};Содержимое index.js
import {invokeFromDir} from '@e22m4u/js-autoload';
const appState = {
initialized: false,
status: 'pending',
};
await invokeFromDir(`${import.meta.dirname}/scripts`, appState);
// import.meta.dirname доступен только для Node.js 20.11 и выше
console.log(appState);
// { initialized: true, status: 'done' }Рекомендуется передавать абсолютный путь до целевой директории (как это показано
выше), так как относительный путь вычисляется от места вызова команды node,
а не от файла в котором используется данная утилита.
Функция invokeFromDir принимает неограниченное количество аргументов
после пути к директории. Все переданные аргументы будут отправлены в каждую
вызываемую функцию без изменений.
import {invokeFromDir} from '@e22m4u/js-autoload';
// ...
await invokeFromDir('./src/actions', arg1, arg2, arg3);Современный стандарт ESM позволяет применять оператор await на верхнем
уровне модуля. Стандарт CommonJS не поддерживает такую возможность.
Использование оператора await в корне файла приводит к синтаксической ошибке.
Для обхода описанного ограничения создается асинхронная функция-обертка. Внутри
такой функции оператор await работает в штатном режиме. Вся стартовая логика
приложения помещается в тело этой функции. Пример реализации подобного подхода
приводится ниже.
Структура файлов:
project/
scripts/
01-init.js
02-process.js
index.js
Содержимое 01-init.js
module.exports = function(context) {
context.initialized = true;
};Содержимое 02-process.js
// имитация асинхронного выполнения
module.exports = async function(context) {
context.status = 'done';
};Содержимое index.js
const path = require('path');
const {invokeFromDir} = require('@e22m4u/js-autoload');
const appState = {
initialized: false,
status: 'pending'
};
async function main() {
await invokeFromDir(path.join(__dirname, './scripts'), appState);
console.log(appState);
// { initialized: true, status: 'done' }
}
main();Утилита invokeFromDir выполняет исключительно функции, которые экспортированы
по умолчанию. При работе со стандартом CommonJS присвоение целевой функции
объекту module.exports автоматически трактуется средой выполнения как экспорт
по умолчанию. По этой причине подобные функции успешно распознаются
и вызываются данной утилитой.
При вызове функции invokeFromDir применяются следующие правила:
Вложенность
Обрабатываются только файлы на первом уровне указанной директории. Вложенные
каталоги игнорируются.
Расширения
Загружаются только файлы с расширениями .js, .mjs и .cjs.
Файлы с другими расширениями игнорируются.
Исключения
Файлы, имена которых оканчиваются на .test.js или .spec.js, пропускаются.
Порядок выполнения
Перед выполнением список путей сортируется по алфавиту с учетом числовых
значений в строках. Именование файлов с числовыми префиксами
(01-*, 02-* и т.д.) гарантирует строгую последовательность
вызова.
Проверка экспорта
Выполняются только функции, предоставленные как export default. Именованные
экспорты игнорируются. Строки, объекты или другие типы данных пропускаются.
Классы
Если экспортом по умолчанию является класс (ES6 class), он игнорируется
и не инстанцируется.
Асинхронность
Если функция возвращает Promise, выполнение приостанавливается до разрешения
промиса. Следующий файл будет обработан только после завершения работы
предыдущего.
Ошибки
В случае отсутствия указанной директории или возникновения ошибки внутри
выполняемой функции, процесс останавливается, и ошибка пробрасывается
в вызывающий код.
npm run testMIT