From c2ac229f2072f7c5d463d2c6270f5cd01f3911e5 Mon Sep 17 00:00:00 2001 From: Jeremy Benoist Date: Mon, 14 Jun 2021 11:08:48 +0200 Subject: [PATCH 1/2] Do not run webpack on a single non-node function --- lib/utils.js | 11 ++++++++--- lib/validate.js | 13 +++++++++---- tests/validate.test.js | 25 +++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/lib/utils.js b/lib/utils.js index 47c4449f0..935e868d9 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -108,12 +108,16 @@ function splitLines(str) { return _.split(str, /\r?\n/); } +function isNodeRuntime(runtime) { + return runtime.match(/node/); +} + function getAllNodeFunctions() { const functions = this.serverless.service.getAllFunctions(); return _.filter(functions, funcName => { const func = this.serverless.service.getFunction(funcName); - const runtime = func.runtime || this.serverless.service.provider.runtime || 'nodejs'; - return runtime.match(/node/); + + return isNodeRuntime(func.runtime || this.serverless.service.provider.runtime || 'nodejs'); }); } @@ -125,5 +129,6 @@ module.exports = { spawnProcess, safeJsonParse, splitLines, - getAllNodeFunctions + getAllNodeFunctions, + isNodeRuntime }; diff --git a/lib/validate.js b/lib/validate.js index 32f8c890b..af5afa12e 100644 --- a/lib/validate.js +++ b/lib/validate.js @@ -7,7 +7,7 @@ const glob = require('glob'); const lib = require('./index'); const _ = require('lodash'); const Configuration = require('./Configuration'); -const { getAllNodeFunctions } = require('./utils'); +const { getAllNodeFunctions, isNodeRuntime } = require('./utils'); /** * For automatic entry detection we sort the found files to solve ambiguities. @@ -113,14 +113,19 @@ module.exports = { const functions = getAllNodeFunctions.call(this); if (this.options.function) { const serverlessFunction = this.serverless.service.getFunction(this.options.function); - const entry = getEntryForFunction.call(this, this.options.function, serverlessFunction); - _.merge(entries, entry); + const runtime = serverlessFunction.runtime || this.serverless.service.provider.runtime; + + // only package that lonely function if it's a node function + if (isNodeRuntime(runtime)) { + const entry = getEntryForFunction.call(this, this.options.function, serverlessFunction); + _.merge(entries, entry); + } } else { _.forEach(functions, (func, index) => { const loadedFunc = this.serverless.service.getFunction(func); const runtime = loadedFunc.runtime || this.serverless.service.provider.runtime || 'nodejs'; - if (runtime.match(/node/)) { + if (isNodeRuntime(runtime)) { // runtimes can be 'nodejsX.Y' (AWS, Azure) or 'google-nodejs' (Google Cloud) const entry = getEntryForFunction.call(this, functions[index], loadedFunc); _.merge(entries, entry); diff --git a/tests/validate.test.js b/tests/validate.test.js index 7eca04b6f..f7eea7aa4 100644 --- a/tests/validate.test.js +++ b/tests/validate.test.js @@ -596,6 +596,31 @@ describe('validate', () => { }); }); + it('should ignore the requested function if `options.function` is defined and the function is not a node one', () => { + const testOutPath = 'test'; + const testFunction = 'func5'; + const testConfig = { + entry: 'test', + context: 'testcontext', + output: { + path: testOutPath + } + }; + _.set(module.serverless.service, 'custom.webpack.config', testConfig); + module.serverless.service.functions = testFunctionsConfig; + module.options.function = testFunction; + globSyncStub.callsFake(filename => [_.replace(filename, '*', 'js')]); + return expect(module.validate()).to.be.fulfilled.then(() => { + const lib = require('../lib/index'); + const expectedLibEntries = {}; + + expect(lib.entries).to.deep.equal(expectedLibEntries); + expect(globSyncStub).to.not.have.been.called; + expect(serverless.cli.log).to.not.have.been.called; + return null; + }); + }); + it('should ignore non-node runtimes', () => { const testOutPath = 'test'; const testFunctionsConfig = { From 688211ab25e7d1eb254509b5540845a1e7ae1110 Mon Sep 17 00:00:00 2001 From: Jeremy Benoist Date: Tue, 29 Jun 2021 14:05:27 +0200 Subject: [PATCH 2/2] Skip non-node function at a higher level --- index.js | 16 +++++++++++----- index.test.js | 3 +++ lib/validate.js | 14 +++++--------- tests/validate.test.js | 25 ------------------------- 4 files changed, 19 insertions(+), 39 deletions(-) diff --git a/index.js b/index.js index fa1b8b64d..07c1ae0ca 100644 --- a/index.js +++ b/index.js @@ -14,6 +14,7 @@ const prepareOfflineInvoke = require('./lib/prepareOfflineInvoke'); const prepareStepOfflineInvoke = require('./lib/prepareStepOfflineInvoke'); const packExternalModules = require('./lib/packExternalModules'); const packageModules = require('./lib/packageModules'); +const { isNodeRuntime } = require('./lib/utils'); const lib = require('./lib'); class ServerlessWebpack { @@ -104,11 +105,16 @@ class ServerlessWebpack { 'after:package:createDeploymentArtifacts': () => BbPromise.bind(this).then(this.cleanup), - 'before:deploy:function:packageFunction': () => - BbPromise.bind(this) - .then(() => this.serverless.pluginManager.spawn('webpack:validate')) - .then(() => this.serverless.pluginManager.spawn('webpack:compile')) - .then(() => this.serverless.pluginManager.spawn('webpack:package')), + 'before:deploy:function:packageFunction': () => { + const runtime = this.serverless.service.getFunction(this.options.function).runtime; + + if (isNodeRuntime(runtime)) { + return BbPromise.bind(this) + .then(() => this.serverless.pluginManager.spawn('webpack:validate')) + .then(() => this.serverless.pluginManager.spawn('webpack:compile')) + .then(() => this.serverless.pluginManager.spawn('webpack:package')); + } + }, 'before:invoke:local:invoke': () => BbPromise.bind(this) diff --git a/index.test.js b/index.test.js index 45a349966..950c446f2 100644 --- a/index.test.js +++ b/index.test.js @@ -44,6 +44,7 @@ describe('ServerlessWebpack', () => { }; sandbox.stub(serverless.pluginManager, 'spawn').returns(BbPromise.resolve()); + sandbox.stub(serverless.service, 'getFunction').returns({ runtime: 'nodejs12.x' }); }); afterEach(() => { @@ -222,6 +223,8 @@ describe('ServerlessWebpack', () => { name: 'before:deploy:function:packageFunction', test: () => { it('should spawn validate, compile and package', () => { + slsw.options.function = functionName; + return expect(slsw.hooks['before:deploy:function:packageFunction']()).to.be.fulfilled.then(() => { expect(slsw.serverless.pluginManager.spawn).to.have.been.calledThrice; expect(slsw.serverless.pluginManager.spawn.firstCall).to.have.been.calledWithExactly( diff --git a/lib/validate.js b/lib/validate.js index af5afa12e..e057a4575 100644 --- a/lib/validate.js +++ b/lib/validate.js @@ -113,13 +113,8 @@ module.exports = { const functions = getAllNodeFunctions.call(this); if (this.options.function) { const serverlessFunction = this.serverless.service.getFunction(this.options.function); - const runtime = serverlessFunction.runtime || this.serverless.service.provider.runtime; - - // only package that lonely function if it's a node function - if (isNodeRuntime(runtime)) { - const entry = getEntryForFunction.call(this, this.options.function, serverlessFunction); - _.merge(entries, entry); - } + const entry = getEntryForFunction.call(this, this.options.function, serverlessFunction); + _.merge(entries, entry); } else { _.forEach(functions, (func, index) => { const loadedFunc = this.serverless.service.getFunction(func); @@ -232,6 +227,7 @@ module.exports = { const func = this.serverless.service.getFunction(funcName); const handler = getHandlerFileAndFunctionName(func); const handlerFile = path.relative('.', getHandlerFile(handler)); + return { handlerFile, funcName, @@ -276,8 +272,8 @@ module.exports = { // Webpack config can be a Promise, If it's a Promise wait for resolved config object. if (this.webpackConfig && _.isFunction(this.webpackConfig.then)) { return BbPromise.resolve(this.webpackConfig.then(config => processConfig(config))); - } else { - return processConfig(this.webpackConfig); } + + return processConfig(this.webpackConfig); } }; diff --git a/tests/validate.test.js b/tests/validate.test.js index f7eea7aa4..7eca04b6f 100644 --- a/tests/validate.test.js +++ b/tests/validate.test.js @@ -596,31 +596,6 @@ describe('validate', () => { }); }); - it('should ignore the requested function if `options.function` is defined and the function is not a node one', () => { - const testOutPath = 'test'; - const testFunction = 'func5'; - const testConfig = { - entry: 'test', - context: 'testcontext', - output: { - path: testOutPath - } - }; - _.set(module.serverless.service, 'custom.webpack.config', testConfig); - module.serverless.service.functions = testFunctionsConfig; - module.options.function = testFunction; - globSyncStub.callsFake(filename => [_.replace(filename, '*', 'js')]); - return expect(module.validate()).to.be.fulfilled.then(() => { - const lib = require('../lib/index'); - const expectedLibEntries = {}; - - expect(lib.entries).to.deep.equal(expectedLibEntries); - expect(globSyncStub).to.not.have.been.called; - expect(serverless.cli.log).to.not.have.been.called; - return null; - }); - }); - it('should ignore non-node runtimes', () => { const testOutPath = 'test'; const testFunctionsConfig = {