From ed943bf528e80d698316c77246885222996ffd30 Mon Sep 17 00:00:00 2001 From: Jeremy Walton Date: Sat, 5 Sep 2020 09:47:21 -0400 Subject: [PATCH 1/2] Fix for shared modules --- package.json | 1 - .../in-process-runner/InProcessRunner.js | 61 ++++++++++++++++++- .../integration/lambda-invoke/serverless.yml | 4 -- 3 files changed, 59 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 30a2cc18c..2f9fa2d1f 100644 --- a/package.json +++ b/package.json @@ -159,7 +159,6 @@ "aws-sdk": "^2.624.0", "boxen": "^4.2.0", "chalk": "^3.0.0", - "clear-module": "^4.1.1", "cuid": "^2.1.8", "execa": "^4.0.0", "extend": "^3.0.2", diff --git a/src/lambda/handler-runner/in-process-runner/InProcessRunner.js b/src/lambda/handler-runner/in-process-runner/InProcessRunner.js index 4839abdee..097ac3f58 100644 --- a/src/lambda/handler-runner/in-process-runner/InProcessRunner.js +++ b/src/lambda/handler-runner/in-process-runner/InProcessRunner.js @@ -1,5 +1,62 @@ import { performance } from 'perf_hooks' -import clearModule from 'clear-module' +import * as path from 'path' +import * as fs from 'fs' + +const clearModule = (fP, opts) => { + const options = opts ?? {} + let filePath = fP + if (!require.cache[filePath]) { + const dirname = path.dirname(filePath) + for (const fn of fs.readdirSync(dirname)) { + const fullPath = path.resolve(dirname, fn) + if ( + fullPath.substr(0, filePath.length + 1) === `${filePath}.` && + require.cache[fullPath] + ) { + filePath = fullPath + break + } + } + } + if (require.cache[filePath]) { + // Remove file from parent cache + if (require.cache[filePath].parent) { + let i = require.cache[filePath].parent.children.length + if (i) { + do { + i -= 1 + if (require.cache[filePath].parent.children[i].id === filePath) { + require.cache[filePath].parent.children.splice(i, 1) + } + } while (i) + } + } + const cld = require.cache[filePath].children + delete require.cache[filePath] + for (const c of cld) { + if (!c.filename.match(/node_modules/)) { + clearModule(c.id, { ...options, cleanup: false }) + } + } + if (opts.cleanup) { + let cleanup = false + do { + cleanup = false + for (const fn of Object.keys(require.cache)) { + if ( + require.cache[fn].id !== '.' && + require.cache[fn].parent && + require.cache[fn].parent.id !== '.' && + !require.cache[require.cache[fn].parent.id] + ) { + delete require.cache[fn] + cleanup = true + } + } + } while (cleanup) + } + } +} export default class InProcessRunner { #env = null @@ -40,7 +97,7 @@ export default class InProcessRunner { // lazy load handler with first usage if (!this.#allowCache) { - clearModule(this.#handlerPath) + clearModule(this.#handlerPath, { cleanup: true }) } const { [this.#handlerName]: handler } = await import(this.#handlerPath) diff --git a/tests/integration/lambda-invoke/serverless.yml b/tests/integration/lambda-invoke/serverless.yml index 9a882ad8d..912d3e9c4 100644 --- a/tests/integration/lambda-invoke/serverless.yml +++ b/tests/integration/lambda-invoke/serverless.yml @@ -68,7 +68,3 @@ functions: invokedAsyncHandler: handler: lambdaInvokeAsyncHandler.invokedAsyncHandler - -custom: - serverless-offline: - allowCache: true From 4eacf7ec8b7af5fa847825fd8f0091fbae2619de Mon Sep 17 00:00:00 2001 From: Jeremy Walton Date: Sat, 5 Sep 2020 10:16:52 -0400 Subject: [PATCH 2/2] Added some comments --- src/lambda/handler-runner/in-process-runner/InProcessRunner.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lambda/handler-runner/in-process-runner/InProcessRunner.js b/src/lambda/handler-runner/in-process-runner/InProcessRunner.js index 097ac3f58..75f4c031c 100644 --- a/src/lambda/handler-runner/in-process-runner/InProcessRunner.js +++ b/src/lambda/handler-runner/in-process-runner/InProcessRunner.js @@ -34,11 +34,13 @@ const clearModule = (fP, opts) => { const cld = require.cache[filePath].children delete require.cache[filePath] for (const c of cld) { + // Unload any non node_modules children if (!c.filename.match(/node_modules/)) { clearModule(c.id, { ...options, cleanup: false }) } } if (opts.cleanup) { + // Cleanup any node_modules that are orphans let cleanup = false do { cleanup = false