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.