I've found building things with serverless really fun, and after skimming the surface of the documentation trying to build my own plugin, I wanted to start off my development using typescript, here's how I did it.
Step 1:
Setup your npm module to build the serverless plugin.
$ mkdir my-cool-plugin $ cd my-cool-plugin $ serverless create --template plugin $ ls index.js // <- What serverless made us.
Step 2:
Run npm init so we get ourselves a package.json.
$ npm init # Whilst we're here, lets initialize git and add a .gitignore file and add node_modules to it. $ git init $ echo "node_modules" >> .gitignore
Step 3:
Add typescript as a dependency along with @types/node
. We can init typescript so we get our tsconfig.json
file.
$ npm i typescript --save-dev $ npm i @types/node --save-dev $ node_modules/typescript/bin/tsc --init
Step 4:
Add a tsc
build script to our package.json
.
{ "scripts": { "build": "tsc ./src/index.ts" }, }
Good thing to note here is that scripts inside your
package.json
will look insidenode_modules
. That's why in step 3 I had to specifynode_modules/typescript/bin/tsc
when initialising.
Step 5:
Create our src
folder with a basic index.ts
file in.
$ mkdir src $ echo "console.log('hello typescript')" >> src/index.ts
Step 6: (Totally optional)
Check it's all working!
$ npm run build > my-cool-plugin@1.0.0 build /Users/karltaylor/code/my-cool-plugin > tsc ./src/index.ts
You would now have an index.js
inside your src
folder which has been compiled from typescript to normal javascript. But the src
directory isn't exactly where we want it.
Step 7:
Add a rootDir
and outDir
to our tsconfig.json
and a watch script to our package.json
to re-compile our files on save.
In our tsconfig.json
:
{ "compilerOptions": { "rootDir": "./src" "outDir": "./dist", } }
And our package.json
:
{ "scripts": { "build": "tsc", "watch": "tsc -w" }, }
Step 8:
Let's copy the contents of the index.js
file that serverless gave us when we created in step 1 into our index.ts
file.
You will be inundated with plenty of errors in the console that we now need to go and fix...
Now, unfortunately, after a lot of digging, I couldn't find the specific types for building a serverless plugin. But there is a @types/serverless file. To combat all the errors, your index.ts
should look something like this:
import Serverless from "serverless"; class ServerlessPlugin { serverless: Serverless; options: any; commands: {}; hooks: { [key: string]: Function } constructor(serverless: Serverless, options: any) { this.serverless = serverless; this.options = options; this.commands = { welcome: { usage: "Helps you start your first Serverless plugin", lifecycleEvents: ["hello", "world"], options: { message: { usage: "Specify the message you want to deploy " + "(e.g. \"--message 'My Message'\" or \"-m 'My Message'\")", required: true, shortcut: "m", }, }, }, }; this.hooks = { "before:welcome:hello": this.beforeWelcome.bind(this), "welcome:hello": this.welcomeUser.bind(this), "welcome:world": this.displayHelloMessage.bind(this), "after:welcome:world": this.afterHelloWorld.bind(this), }; } beforeWelcome() { this.serverless.cli.log("Hello from Serverless!"); } welcomeUser() { this.serverless.cli.log("Your message:"); } displayHelloMessage() { this.serverless.cli.log(`${this.options.message}`); } afterHelloWorld() { this.serverless.cli.log("Please come again!"); } } module.exports = ServerlessPlugin;
Running yarn build
in the console should successfully build your index.ts
severless plugin boilerplate into dist/index.js
Step 9
Let's create a new serverless
project in a new directory.
$ ~/code mkdir my-serverless-test-directory $ ~/code cd my-serverless-test-directory $ ~/code/my-serverless-test-directory npm init $ ~/code/my-serverless-test-directory serverless create --template=hello-world
Let's install our npm module locally simply by referencing its absolute or relative path:
$ ~/code/my-serverless-test-directory npm i --save-dev ~/code/my-cool-plugin
Open up the serverless.yml
file and add the name of your plugin to the plugins
section:
# Welcome to serverless. Read the docs # https://serverless.com/framework/docs/ # Serverless.yml is the configuration the CLI # uses to deploy your code to your provider of choice # The `service` block is the name of the service service: my-serverless-test-directory plugins: - my-cool-plugin # <------ Right here! 🚀 # The `provider` block defines where your service will be deployed provider: name: aws runtime: nodejs12.x # The `functions` block defines what code to deploy functions: helloWorld: handler: handler.helloWorld # The `events` block defines how to trigger the handler.helloWorld code events: - http: path: hello-world method: get cors: true
Step 10
Let's run our serverless boilerplate plugin to check everything is working as it should:
$ ~/code/my-serverless-test-directory serverless welcome -m "Hello World Serverless Plugin in Typescript" Serverless: Hello from Serverless! Serverless: Your message: Serverless: Hello World Serverless Plugin in Typescript Serverless: Please come again!
And voila! Your compiled typescript serverless plugin is working!
Personally I've found there is a distinct lack of documentation for building Serverless Plugins, I am very much developing in the dark and figuring out what things do what, but it's very fun to play with.
Feel free to follow me on twitter where I tweet about more tech-related adventures.
Top comments (2)
Hey, great write up, I created a new template repository for creating serverless framework plugins using Typescript.
Please check it out and let me know if I missed anything.
Thanks this, much appreciated.