Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Serverless NodeJS File/Folder Structure

I'm setting up my first project using serverless and while I'm finding a lot of great "getting started" tutorials, I'm having a hard time finding anything about actual project structure.

My thoughts is to use the below structure for my functions, shared libs and core configuration/dependencies:

.
├── functions/
│   │
│   ├── users/
│   │   ├── handler.js
│   │   └── serverless.yml
│   │
│   └── roles/
│       ├── handler.js
│       └── serverless.yml
│
├── shared/
│   └── common.js
│   
├── node_modules/
└── package.json

My main curiosity is around deployment and how that pertains to dependencies and shared files. Additionally, automating deploy of this structure seems strange as I'm gathering I would need to deploy each of the functions separately which I can script, but wondering if that's needed or advised.

like image 309
Fluidbyte Avatar asked Jul 01 '17 19:07

Fluidbyte


1 Answers

I have dealt with this a bit and found it quite frustrating. If you deploy from your setup, what does your api look like? With individual serverless.yaml files you end up with independent api endpoints (assuming you are triggering with api calls and not something like s3).

I ended up with a structure like this:

|- serverless/
|--- serverlsss.yml
|--- web pack.config.js
|--- dist/
|--- node_modules() /* dev and common code */
|--- src/
|----- function1/
|-------- node_modules
|-------- package.json
|-------- index.js
|----- function2/
|-------- node_modules
|-------- package.json
|-------- index.js

I use the serverless webpack plugin to output the the individual functions into the dist/ directory. The serverless.yaml then points to these.

The webpack.config.js looks like this:

const nodeExternals = require('webpack-node-externals');
const path = require('path');

module.exports = {
  entry: {
    'function1': './src/function1/index.js', 
    'function2': './src/function2/index.js',
  },
  target: 'node',
  output:{
    libraryTarget: 'commonjs2',
    path: path.join(__dirname, './dist'),
    filename: '[name].js'
  },
  externals: [nodeExternals()],
  module: {
    loaders: [
      /* Babel is nice, but it's adding a some bulk and I don't need it
      {
        test: /\.js$/,
        loaders: ['babel'],
        include: __dirname,
        exclude: /node_modules/,
      }, */
      { 
        test: /\.json$/,
        loaders: ['json']} 
    ],
  },
};

//  externals: [nodeExternals()],
//  nodeExternals seems to break aws-sdk when serving locally
//  aws-sdk should be in dev-dependencies of root folder
//  that way it's available in dev but doesn't get packaged.
//  It's available to the lambdas when deployed.

After that just make sure you set the individual flag in serverless.yml

package:
  individually: true

The webpack plugin is quite nice and does most of the heavy lifting. With this I can do a single deploy and all the functions end up as individual lambda functions all under one api endpoint. You also get the Webpack dev server so you can run serverless webpack serve to test your functions.

It was a bit of a pain to setup, but it's been working pretty well.

like image 142
Mark Avatar answered Nov 15 '22 04:11

Mark