Предыстория
Однажды столкнулся с, казалось бы, небольшой проблемой — организация облачных функций Firebase. Уверен многие столкнулись с тем, что при создании некоего приложения мы обязаны создавать каждую функцию отдельно, а это фактически клонирование модулей Node.Js, особенно критично это в условиях большого приложения. Уверен, многим первой пришла мысль, создавать функции в отдельных файлах/каталогах и require`ить их в index.js.
Отличная идея… для медленного сервиса
Дело в том, что таким образом:
// index.js
exports.function1 = require('./function1.js');
exports.function2 = require('./function2.js');
exports.function3 = require('./function3.js');
etc.
Firebase при запуске одной функции будет инициализировать все что находится в index.js включая все зависимости внутри, а все это, естественно, занимает время. Согласитесь, в 2018 году никто не будет ждать загрузку страницы более 5 секунд. А учитывая так называемый "Cold start", инициализация будет проходить достаточно часто, что тоже неприемлемо.
Решение проблемы
Поискав немного информацию по этому вопросу вы наткнетесь на вот такой комментарий в GitHub:
И поверьте, на сегодняшний день этот простой цикл — лучшее решение данной проблемы.
С помощью его и индексовый файл будет чист, и будет единое соглашение об имени файла (camelCase в данном случае), а это особенно полезно при работе в команде. Так же Firebase будет инициализировать только нужную функцию перед её исполнением.
Но есть ещё одна проблема: Google Cloud Platform (GCP) осуществляет запуск кода только в среде Node.Js v6, что лишает нас async/await и подобных, а все таки Node.js v8 уже имеет статус LTS.
Моё решение состоит в использовании транскомпилятора Babel, но код вовсе не обязательно транскомпилировать перед деплоем! Оказалось, что GCP поддерживает транскомпиляцию "на лету". То есть, используя опыт зарубежных коллег, мы чуть изменим этот цикл:
//index.js
const glob = require("glob");
const camelCase = require("camelcase");
// Настройка babel
require("babel-register")({
ignore: './node_modules',
extensions: [ ".js"],
cache: true,
});
const files = glob.sync('./**/*.f.js', { cwd: __dirname, ignore: './node_modules/**' });
for (let f = 0, fl = files.length; f < fl; f++) {
let file = files[f];
const functionName = camelCase(file.slice(0, -5).split('/').join('_'));
if (!process.env.FUNCTION_NAME || process.env.FUNCTION_NAME === functionName) {
exports[functionName] = require(file);
}
}
Вывод
Таким образом мы имеет удобную организацию кода с соглашением об именах и поддержкой функциональных особенностей Node.Js v8 и выше.
Удачи в познаниях.
Автор: Валера