- PVSM.RU - https://www.pvsm.ru -
В этой статье рассмотрим использование компилятора для js-кода облачных функций.
Создаем проект. Добавляем Firebase функцию.
// index.js
export const helloWorld = https.onRequest(/** … */);
Через некоторое время добавляем ещё несколько.
// index.js
export const helloWorld = https.onRequest(/** … */);
export const lol = https.onRequest(/** … */);
export const pirojok = https.onRequest(/** … */);
Ещё через некоторое время ещё и ещё.
А так как мы пишем код для людей, поэтому помимо кода, в нём будут комментарии и документация.
Проект Firebase Functions — это node модуль. В index.js
экспортируются все функции.
При первом запуске любой функции загружаются и инициализируются все импортированные файлы, от всех функций. Node.js загружает index.js
и весь связанный код через require
и/или import
. Это особенность node модулей.
На время инициализации node модуля также влияют выражения, вычисляемые в этот момент.
Следующий пример будет вычисляться при каждой инициализации node модуля:
// constants.js
const ONE_MINUTES_IN_MS = 60 * 1000;
Далее происходит обработка события функцией.
Поэтому, чем больше кода и чем он сложнее, тем больше времени нужно для инициализации каждой функции.
Если сократить, упростить код и загружать только используемые модули для запущенной функции, то можно сократить время инициализации функций.
Как можно сократить код? Существуют несколько вариантов, среди них минификация и/или компиляция.
Грубо говоря, минификация сделает имена переменных короткими, а компиляция — уберёт неиспользуемый код, пред вычислит и упростит выражения, например: 50 + 50
превратит в 100
.
До:
const hello = sayHello("Pirojok");
console.log(hello, 40 + 2);
function sayHello(name) {
return `Hi, ${name}!`;
}
После:
"use strict";
const a = b("Pirojok");
console.log(a, 40 + 2);
function b(a) {
return `Hi, ${a}!`;
}
До:
const hello = sayHello("Pirojok");
console.log(hello, 40 + 2);
function sayHello(name) {
return `Hi, ${name}!`;
}
После:
"use strict";
var name;
const hello = `Hi, ${(name = "Pirojok")}!`;
console.log(hello, 42);
До:
const hello = sayHello("Pirojok");
console.log(hello, 40 + 2);
function sayHello(name) {
return `Hi, ${name}!`;
}
После:
"use strict";
var a;
const b = `Hi, ${(a = "Pirojok")}!`;
console.log(b, 42);
Основная идея — загружать модули в момент выполнения, а не инициализации функций.
Всё что нужно сделать — поместить загрузку модулей в тело обработчика функции.
До:
import {https, logger} from "firebase-functions";
import {initializeApp} from "firebase-admin";
initializeApp();
export const helloWorld = https.onRequest((request, response) => {
logger.info("Hello logs!", {structuredData: true, computed: 50 + 50});
response.send("Hello from Firebase!");
});
После:
import {https, logger} from "firebase-functions";
let app_inited_by_helloWorld = false;
export const helloWorld = https.onRequest(async (request, response) => {
if (!app_inited_by_helloWorld) {
const {initializeApp} = await import("firebase-admin");
initializeApp();
app_inited_by_helloWorld = true;
}
logger.info("Hello logs!", {structuredData: true, computed: 50 + 50});
response.send("Hello from Firebase!");
});
Глобальная переменная app_inited_by_helloWorld
нужна, чтобы firebase-admin
приложение инициализировалось, только один раз.
В глобальные переменные также можно помещать переменные из импортированных модулей.
Подробнее про этот трюк [1] можно почитать в документации Firebase.
В качестве компилятора и/или минификатора можно использовать проект SWC или любой другой.
Я выбрал SWC, он умеет минифицировать и компилировать код одновременно.
Установить SWC можно по инструкции [2].
Чтобы создать конфигурационный файл .swcrc
и подобрать нужные вам настройки, я рекомендую использовать playground [3] проекта. Получить конфигурацию можно нажав кнопку Edit as JSON.
Для Firebase Functions рекомендую сразу задать Env Targets
= node 16
и убрать jsc.target
в конечном файле.
Playground добавляет в конфигурационный файл опцию "isModule"
= true
, её потребуется удалить, если компилятор, будет выдавать ошибку в вашем проекте.
Бонусом можно настроить использование es-модулей, весь старый код, использующий require
, и новый будут прекрасно жить вместе. Отличная возможность для плавного перехода на es-модули.
Для того, чтобы код можно было компилировать и использовать, его нужно как-то разделять между собой. Отличным способом является разделение по директориям src
и lib
. Если весь код лежит в корне пакета, то это сильно осложнит процесс.
После подготовки можно настроить скрипты для компиляции проекта.
В package.json
нужно изменить точку входа и добавить скрипты:
{
"main": "lib/index.js",
"scripts": {
"dev": "swc src -w -d lib",
"build": "swc src -d lib"
}
}
build
компилирует код из директории src
в lib
, а dev
следит за изменениями файлов и перекомпилирует их. dev
может потребоваться для удобной работы с эмулятором, для него потребуется установить дополнительный пакет [4].
Чтобы не забыть перед деплоем компилировать проект, рекомендую установить predeploy скрипт. Это можно сделать в firebase.json
.
{
"functions": {
"predeploy": [
"npm --prefix "$RESOURCE_DIR" run lint",
"npm --prefix "$RESOURCE_DIR" run build"
]
}
}
Теперь при вызове команды firebase deploy
, код предварительно будет собран.
Пример [5] уже настроенного Firebase проекта можно посмотреть на GitHub.
Если во время выполнения кода появится ошибка, то прочитать её стектрейс будет затруднительно из-за модификаций кода.
Эта проблема решается генерацией source maps и подключением модуля source-map-support [6].
Use TypeScript for Cloud Functions [7] (Firebase Documentation)
Tips & tricks [8] (Firebase Documentation)
Поздравляю! Теперь ваш проект компилируемый и вы сделали небольшой шаг в его оптимизации.
Чтобы одним из первых прочитать мою следующую статью, можно подписаться на мой канал [9] в Телеграм.
Если у вас возникли вопросы или замечания, можно свободно писать их в комментариях.
Лицензировано под Attribution 4.0 International (CC BY 4.0) [10].
Автор: Артур
Источник [11]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/375961
Ссылки в тексте:
[1] этот трюк: https://firebase.google.com/docs/functions/tips#use_global_variables_to_reuse_objects_in_future_invocations
[2] инструкции: https://swc.rs/#overview
[3] playground: https://swc.rs/playground
[4] пакет: https://swc.rs/docs/usage/cli#--watch--w
[5] Пример: https://github.com/arthurgubaidullin/using-swc-with-firebase-functions
[6] source-map-support: https://github.com/evanw/node-source-map-support
[7] Use TypeScript for Cloud Functions: https://firebase.google.com/docs/functions/typescript
[8] Tips & tricks: https://firebase.google.com/docs/functions/tips
[9] канал: https://t.me/arthur_g_wrotes
[10] Attribution 4.0 International (CC BY 4.0): https://creativecommons.org/licenses/by/4.0/
[11] Источник: https://habr.com/ru/post/670954/?utm_source=habrahabr&utm_medium=rss&utm_campaign=670954
Нажмите здесь для печати.