减少无服务器框架发送的节点模块 zip 的大小

Reduce the size of the node-modules zip sent by the serverless framework

我正在使用 the serverless framework 编写一些 nodejs 函数。 package.json 文件需要一些依赖项:

{
  "name": "adam-test-sls",
  "version": "0.1.0",
  "description": "Test package to play with sls/lambda",
  "main": "handler.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Adam Matan <adam@binaris.com>",
  "license": "UNLICENSED",
  "dependencies": {
    "aws-sdk": ">= 2.0.9",
    "json": "^9.0.6",
    "underscore": "^1.8.3",
    "uuid": "^3.1.0"
  },
  "devDependencies": {
    "eslint": "^4.2.0",
    "eslint-config-airbnb": "^15.0.2",
    "eslint-config-airbnb-base": "^11.2.0",
    "eslint-plugin-import": "^2.7.0"
  }
}

node-modules 目录的大小将近 50mb:

# du -smc node_modules
47  node_modules
47  total

部署时间超过 35 秒,zip 大小约为 9.5MB:

# time serverless deploy function --function hello -v
Serverless: Packaging function: hello...
Serverless: Uploading function: hello (9.46 MB)...
Serverless: Successfully deployed function: hello
serverless deploy function --function hello -v  4.28s user 1.15s system 15% cpu 35.165 total

这有点低效 - 我只更改了一个文件,但每当我进行最细微的更改时,我都必须打包所有未更改的依赖项。

知道如何减小 zip 大小(可能删除 devDependencies),或者只上传更改后的文件吗?

您可以使用无服务器功能排除一些您不需要的包(例如,您保证here the manual

不幸的是,从 1.16 版开始,似乎存在一个问题,即忽略了那些排除项(1.15.1 版创建了更小的 zip,并且从 1.16 开始,zip 包含了您 node_modules 中的任何内容)。我打开了一个 issue,但仍然无人接听。

aws-sdk 大约为 24MB,您不需要它,因为 it's already available 是 lambda 函数。一种选择是将其移至开发依赖项,然后将您的开发依赖项放入父目录的 package.json

还有一些工具可以提供帮助:

serverless-plugin-include-dependencies 插件 - 我不确定如果排除功能被破坏它的效果如何:https://github.com/dougmoscrop/serverless-plugin-include-dependencies

Webpack 也可以与 serverless-webpack 插件一起使用来控制依赖项。 Webpack 的死代码消除可以带来相当大的不同。

不理想,但您也可以在部署前 运行 npm prune --production。 (之后您需要再次 运行 npm install

为了解决这个问题,我使用了一个名为 serverless-plugin-scripts 的插件,并编写了一个在 after:package:createDeploymentArtifacts 挂钩上运行的 shell 脚本。

脚本解压部署包,removes node_modules 目录,运行 npm install --only=prod 并将所有内容打包回去。出于某种原因,npm prune --production 对我来说根本不起作用。

这是配置 (serverless.yml):

service: my-service-name
provider:
  name: aws
  runtime: nodejs8.10
  region: us-east-1
  environment:
    NODE_ENV: ${self:custom.stage}

custom:
  stage: ${opt:stage, self:provider.stage}
  region: ${opt:region, self:provider.region}
  scripts:
    hooks:
      'after:package:createDeploymentArtifacts': >
        printf "[after:package:createDeploymentArtifacts hook] Removing development dependencies " &&
        (cd .serverless && unzip -qq my-service-name.zip -d my-service-name)          && printf "." &&
        (cd .serverless && rm -rf my-service-name/node_modules)                       && printf "." &&
        (cd .serverless/my-service-name && npm install --only=prod > /dev/null 2>&1)  && printf "." &&
        (cd .serverless/my-service-name/ && zip -q -FSr ../my-service-name.zip .)     && printf ".\n" &&
        rm -rf .serverless/my-service-name/ &&
        printf "[after:package:createDeploymentArtifacts hook] Done\n"

functions:  
  scheduledHandler:
    handler: src/handlers.scheduledHandler
    events:
      - schedule: rate(10 minutes)

package:
  exclude:
  - .vscode/**
  - .idea/**
  - test/**
  - build/**
  - .build/**

plugins:
  - serverless-plugin-scripts

我为此使用了层:层用于以层的形式引入额外的代码和内容。这将使您的 lambda 函数保持较小并从层中提取依赖项在运行时。

第 1 步: 在某处创建一个名为 nodejs

的文件夹
cd Desktop
mkdir nodejs
cd nodejs
npm init

第 2 步: 在此文件夹中安装您的依赖项,这些依赖项的大小很大。例如:

npm install --save geoip-lite

第 3 步: 压缩它,给你选择的名字。

第 4 步: 登录到 aws 控制台,转到 lambda 服务,然后选择创建层。然后上传您创建的 zip 文件。 (正如它所说,如果它大于 10 mb,您可以将此 zip 文件上传到 S3)

在此步骤中,您可以通过进入 lambda 函数将图层分配给 lambda,并添加您在上述步骤中创建的自定义图层。

如果您有兴趣添加层是 yml 配置

functions:
  hello:
   handler: handler.hello
   layers:
    - arn:aws:lambda:region:XXXXXX:layer:LayerName:Y