Serverless.com project with Lerna and NPM workspaces
Hello. I'm writing a Lambda "tick" function to simulate the universe for my game. It's a different architecture than my previous idea of maintaining a 24/7 server, which simulates a busy real-time game loop. I wanted to give it a try.
In this post, I want to share the project structure I used, which consists of Lerna, and two packages: one for the game's logic and one for the serverless.com framework for deploying the Lambda. I had some fun with dependencies and Lambda not finding the game logic's dependency.
Project Structure
Here's what my project looks like:
.
├── lerna.json
├── package-lock.json
├── package.json
└── packages
├── logic
│ ├── build
│ │ ├── index.d.ts
│ │ └── index.js
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ │ └── index.ts
│ └── tsconfig.json
└── serverless
├── functions
│ └── handler.ts
├── package.json
├── serverless.yml
└── tsconfig.json
Game Logic Package Setup
Nothing too interesting here. I decided to understand CJS modules and ES modules' output this time. Targeting the Node 18.x runtime by AWS Lambda, I saw that ES modules are supported and decided to go with the future of everything by making TypeScript emit an ES module. It looks something like this:
# PARTIAL tsconfig.json compiler options
{
"target": "ES2016",
"module": "Node16",
"declaration": true,
"outDir": "./build"
}
# PARTIAL package.json, scripts/license/boring parts omitted
{
"name": "@ags9/logic",
"exports": {
"import": "./build/index.js"
},
"types": "./build/index.d.ts",
"type": "module",
"scripts": {
"test": "jest",
"build": "tsc -p .",
"start": "node build/index.js",
"dev": "tsc -w -p ."
},
}
Note the "type": "module"
which tells Node to run .js
files as ES modules. "types"
for letting the importer of this package know it has nice types ("declaration": true
in tsconfig.json
, important for type-safety in the Lambda handler). The exports.import
field is for telling ES module importers of @ags9/logic
what to load. Notice the matching "outDir"
path in tsconfig.json
.
Serverless Setup
I decided against using the aws-nodejs-typescript
serverless template as it was too complicated and outdated. Instead, I used the regular aws-nodejs
template and installed this serverless-typescript plugin for TypeScript support.
The interesting setup here would be two key aspects. First, the tsconfig.json
which references the projects' packages. Second, the patterns for including/excluding the right files from the Lambda package by Serverless.
How did I find out nothing works and why?
I used sls package
, which gave me a zip file under the .serverless
output folder. Examining the contents of the zip file, I noticed that no node_modules
existed there, especially my @ags9/logic
package. I then tried some combinations for the package.patterns
in serverless.yml
and eventually nailed the correct configuration, which looks like this:
# part of serverless.yml
package:
individually: true
patterns:
- ../../node_modules/@ags9/**
- "!../../node_modules/@ags9/*/src/**"
- "!../../node_modules/@ags9/serverless/**"
It's a bit confusing that in my filesystem I omitted @ags9/
from the path, but inside node_modules
, the correct package name from the package.json
is used, e.g. ags9/logic
.
Next Steps For Me
Install regular NPM packages in both
logic
andserverless
and ensure they are packaged correctly by Serverless.Build a game.
Subscribe to my newsletter
Read articles from Amir Eldor directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by