Если вы создаете бессерверные приложения, а точнее если вы создаете приложения с бессерверной структурой, вы неизбежно будете использовать некоторые плагины, которые представляют собой не что иное, как код javascript, который расширяет, перезаписывает или добавляет новый функциональные возможности фреймворка.

Некоторые из плагинов, которые мы часто используем, - это, например, Offline, который позволяет имитировать Lambda и API Gateway для локальной разработки, или WarmUp, который решает проблему холодного старта Lambda или Split Stacks, который переносит ресурсы Cloud Formation во вложенный стек для обхода ограничения ресурсов CF.

Когда мы начали использовать AWS и Serverless, я смотрел на плагины как на что-то, код которых должен быть очень сложным или сложным.

они «взламывают» ядро ​​фреймворка !!

На самом деле, когда вы смотрите на исходный код, вы видите, что реализация часто очень проста (объем одного плагина должен быть очень ограничен - поэтому в основном это всего лишь пара методов, использующих некоторый код из AWS SDK (или других поставщиков). ´)

Уже доступны тысячи подключаемых модулей, созданных сообществом, поэтому часто просто нужно понять, что вам нужно в вашем проекте, и поискать нужный подключаемый модуль в Google, но иногда вы можете захотеть поэкспериментировать или добавить некоторые настраиваемые функции, специфичные для вашего проекта. компания или проект.

Недавно мы поняли, что «простой сценарий оболочки», который мы написали для автоматизации некоторых задач после завершения sls deploy, вырос, как это часто бывает, до сотни строк.
Поэтому мы решили попробовать собственные плагины.

Если это ваш случай, очень хорошее начало - статьи на бессерверном веб-сайте:

Поэтому я не буду утомлять вас еще одним базовым руководством, а скорее расскажу о некоторых небольших аспектах, которые сначала замедлили меня при разработке нашего первого плагина.

Как запустить и протестировать разрабатываемый мной плагин?

Чтобы использовать бессерверный плагин, вы просто запускаете npm install, чтобы добавить его к вашим зависимостям package.json, а затем добавляете его в раздел «плагины» вашего файла serverless.yml.

Чтобы использовать еще не опубликованный плагин, вы можете указать папку, в которой он находится:

plugins - myplugins/my-first-awesome-serverless-plugin
plugins - ./my-first-awesome-serverless-plugin

Просто имейте в виду, что передача локального пути за пределами вашего корня не будет работать, хотя

plugins - ../../my-first-awesome-serverless-plugin #this won't work

Если вы не собираетесь когда-либо публиковать его, и он всегда будет находиться рядом с кодовой базой вашего проекта, просто поместите его в предложенную папку по умолчанию .serverless_plugins

и импортировать его в обычном режиме, как если бы он исходил из опубликованного пакета

plugins - my-first-awesome-serverless-plugin

Если, с другой стороны, вы знаете, что ваш плагин будет повторно использоваться, и вы хотите опубликовать его в npm (общедоступном или, как в нашем случае, в частном реестре с ограниченной областью видимости), вы можете сохранить его в другой папке снаружи и либо использовать npm link (хотя я всегда находил npm link немного громоздким).

Преимущество заключается в том, что вы можете установить пакет как обычно, и ничего не изменится, когда вы выпустите плагин и зафиксируете бессерверный проект.

plugins - my-first-awesome-serverless-plugin

Другой вариант - просто установить пакет из локального каталога.

npm install -D ../../my-first-awesome-serverless-plugin

Это добавит зависимость к вашему package.json и создаст символическую ссылку на вашу папку (но вы должны не забыть изменить зависимость в пакете json на реальную публикацию, как только вы ее опубликуете.

И последнее, если у вас есть пакет с ограниченной областью видимости, просто помните, что вам нужно использовать кавычки для импорта плагина в ваш yml, иначе вы получите исключение форматирования:

- "@yourscope/your-plugin"

События жизненного цикла, хуки и команды

Команда - это функциональность, которую вы хотите добавить в свой плагин.

События жизненного цикла запускаются последовательно во время выполнения команды. По сути, это логические шаги в его процессе / функциональности.

Хуки привязывают ваш код к этому конкретному этапу процесса.

Вы можете определить свои команды в конструкторе вашего плагина:

this.commands = { 
setDomainName: 
     { usage: "Sets Hosted UI Domain Name used by Cognito User Pool App Integration", 
      lifecycleEvents: ['set'], 
      options: { 
        domainName: { usage: 'Specify the domain name you want to set ' + '(e.g. "--domain-name \'my-app\'" or "-dn \'my-app\'")', required: true, shortcut: 'dn', }, }, }, };

И вы можете указать код, который должен выполняться в секции хуков конструктора:

this.hooks = { 'setDomainName:set': this.addDomainName.bind(this) };

не забудьте создать CommandName: LifecycleEvent при создании имени ключа в ваших хуках

Ваша команда будет отображаться, когда вы запустите sls help, и вы можете вызвать ее просто sls yourCommand --yourparams

Если вам не нужна собственная команда, но вы просто хотите переопределить или добавить некоторые функции в существующие события жизненного цикла, просто укажите секцию привязки, связывающую ваш код с событием:

this.hooks = { 'before:package:finalize': this.myCustomCode.bind(this) }

Плагин Контекст

Плагин всегда получает в конструкторе параметры options и serverless. бессерверная конфигурация глобальной службы.

Вначале я нашел очень полезным протоколирование всего бессерверного параметра, чтобы понять все свойства, к которым у меня был доступ:

console.log('Serverless instance: ', this.serverless); // use the normal console otherwise you will get an error this.serverless.cli.log(JSON.stringify(this.serverless), 'Serverless instance: ') // Error: Converting circular structure to JSON

И то, к чему у вас есть доступ, - это в основном все, что есть в вашем бессерверном yml-файле. Вам просто нужно выяснить вложение и имена опор:

this.serverless.service.provider.name this.serverless.service.resources.Resources.IdentityPool.Properties.IdentityPoolName

Более подробную информацию можно найти здесь.

То, что вы часто видите в исходном коде многих плагинов, и это определенно то, что вам понадобится в вашем, - это имя стека:

get stackName() { return `${this.serverless.service.service}-${this.options.stage}`; }

и особенно, если - как в нашем случае - вам нужно действовать на развернутых ресурсах, которые вы хотите знать обо всех ресурсах в вашем стеке CloudFormation:

async retrieveOutputs() { return this.serverless.getProvider('aws').request( 'CloudFormation', 'describeStacks', {StackName: this.stackName}, this.serverless.getProvider('aws').getStage(), this.serverless.getProvider('aws').getRegion() ).then(described=> described.Stacks[0].Outputs) }

Просто имейте в виду, что это будет работать только после того, как стек был развернут, поэтому вы можете использовать его в команде - но если это команда, предназначенная для автономного запуска - она ​​будет работать, только если ваш стек был развернут хотя бы один раз. .

Куда пойти отсюда

Определите свой основной метод, привязанный к хуку, и напишите все, что вам нужно - обычно это просто набор команд, взаимодействующих с AWS SDK.
Содержимое вашего плагина может быть абсолютно всем, и это действительно зависит от того, что вам нужно и чего вы хотите достичь.

Как обычно, предлагаю - чтобы не изобретать велосипед - поискать что-то уже доступное и прочитать исходный код.

Это может быть именно то, что вы ищете, например,
плагин для очистки S3 Bucket перед удалением стека или плагин для уведомления Slack о завершении развертывания, или он может в любом случае служить в качестве отправная точка (и база обучения) для того, что вы хотите реализовать.

Я надеюсь, что это помогает.

Первоначально опубликовано на https://dev.to 17 декабря 2019 г.