1 | 'use strict';
|
2 |
|
3 | const path = require('path');
|
4 |
|
5 | const semver = require('semver');
|
6 | const micromatch = require('micromatch');
|
7 |
|
8 | const getDependencyList = require('./get-dependency-list');
|
9 |
|
10 | function union(a, b) {
|
11 | const arr = a || [];
|
12 | return Array.from(new Set(arr.concat(b || [])));
|
13 | }
|
14 |
|
15 | module.exports = class IncludeDependencies {
|
16 |
|
17 | constructor(serverless, options) {
|
18 | if (!semver.satisfies(serverless.version, '>= 1.2')) {
|
19 | throw new Error('serverless-plugin-include-dependencies requires serverless 1.2 or higher!');
|
20 | }
|
21 | this.serverless = serverless;
|
22 | this.options = options;
|
23 | this.hooks = {
|
24 | 'before:deploy:function:packageFunction': this.functionDeploy.bind(this),
|
25 | 'before:deploy:createDeploymentArtifacts': this.createDeploymentArtifacts.bind(this)
|
26 | };
|
27 | }
|
28 |
|
29 | functionDeploy() {
|
30 | return this.processFunction(this.options.function);
|
31 | }
|
32 |
|
33 | createDeploymentArtifacts() {
|
34 | const service = this.serverless.service;
|
35 | if (typeof service.functions === 'object') {
|
36 | Object.keys(service.functions).forEach(functionName => {
|
37 | this.processFunction(functionName);
|
38 | });
|
39 | }
|
40 | }
|
41 |
|
42 | processFunction(functionName) {
|
43 | const service = this.serverless.service;
|
44 |
|
45 | const functionObject = service.functions[functionName];
|
46 | const runtime = this.getFunctionRuntime(functionObject);
|
47 |
|
48 | functionObject.package = functionObject.package || {};
|
49 |
|
50 | service.package = service.package || {};
|
51 | service.package.exclude = union(service.package.exclude, ['node_modules/**']);
|
52 |
|
53 | if (runtime.match(/nodejs*/)) {
|
54 | this.processNodeFunction(functionObject);
|
55 | }
|
56 | }
|
57 |
|
58 | processNodeFunction(functionObject) {
|
59 | const service = this.serverless.service;
|
60 |
|
61 | const fileName = this.getHandlerFilename(functionObject.handler);
|
62 |
|
63 | if (service.package && service.package.individually) {
|
64 | const exclude = union(service.package.exclude, functionObject.exclude);
|
65 | const dependencies = this.getDependencies(fileName, exclude);
|
66 |
|
67 | this.include(functionObject, dependencies);
|
68 | } else {
|
69 | const exclude = service.package.exclude;
|
70 | const dependencies = this.getDependencies(fileName, exclude);
|
71 |
|
72 | this.include(service, dependencies);
|
73 | }
|
74 | }
|
75 |
|
76 | getFunctionRuntime(functionObject) {
|
77 | const service = this.serverless.service;
|
78 |
|
79 | const functionRuntime = functionObject.runtime;
|
80 | const providerRuntime = service.provider && service.provider.runtime;
|
81 |
|
82 | return functionRuntime || providerRuntime || 'nodejs4.3';
|
83 | }
|
84 |
|
85 | getHandlerFilename(handler) {
|
86 | const handlerPath = handler.slice(0, handler.lastIndexOf('.'));
|
87 | return require.resolve((path.join(this.serverless.config.servicePath, handlerPath)));
|
88 | }
|
89 |
|
90 | getDependencies(fileName, exclude) {
|
91 | const servicePath = this.serverless.config.servicePath;
|
92 | const dependencies = this.getDependencyList(fileName);
|
93 |
|
94 | const relativeDependencies = dependencies.map(p => path.relative(servicePath, p));
|
95 |
|
96 | return relativeDependencies.filter(p => {
|
97 | return !exclude.some(e => {
|
98 | if (e.indexOf('node_modules') !== 0 || e === 'node_modules' || e === 'node_modules/**') {
|
99 | return false;
|
100 | }
|
101 |
|
102 | return micromatch.contains(p, e);
|
103 | });
|
104 | });
|
105 | }
|
106 |
|
107 | getDependencyList(fileName) {
|
108 | return getDependencyList(fileName, this.serverless);
|
109 | }
|
110 |
|
111 | include(target, dependencies) {
|
112 | target.package.include = union(target.package.include, dependencies);
|
113 | }
|
114 |
|
115 | };
|