From 69ec303d04dbe02867e02b8c28d58c9179de9df2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Serkan=20=C3=96ZAL?= Date: Tue, 29 Oct 2024 13:02:10 +0300 Subject: [PATCH] Activate ESM loader hook of the "import-in-the-middle" library for ES (EcmaScript) based user handlers --- nodejs/packages/layer/scripts/otel-handler | 2 +- nodejs/packages/layer/src/loader.mjs | 71 ++++++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 nodejs/packages/layer/src/loader.mjs diff --git a/nodejs/packages/layer/scripts/otel-handler b/nodejs/packages/layer/scripts/otel-handler index e5b5aed846..d6329b28e3 100755 --- a/nodejs/packages/layer/scripts/otel-handler +++ b/nodejs/packages/layer/scripts/otel-handler @@ -2,7 +2,7 @@ set -ef -o pipefail -export NODE_OPTIONS="${NODE_OPTIONS} --require /opt/wrapper.js" +export NODE_OPTIONS="${NODE_OPTIONS} --import /opt/loader.mjs --require /opt/wrapper.js" if [[ $OTEL_RESOURCE_ATTRIBUTES != *"service.name="* ]]; then export OTEL_RESOURCE_ATTRIBUTES="service.name=${AWS_LAMBDA_FUNCTION_NAME},${OTEL_RESOURCE_ATTRIBUTES}" diff --git a/nodejs/packages/layer/src/loader.mjs b/nodejs/packages/layer/src/loader.mjs new file mode 100644 index 0000000000..817901fba0 --- /dev/null +++ b/nodejs/packages/layer/src/loader.mjs @@ -0,0 +1,71 @@ +import { register } from 'module'; +import * as path from 'path'; +import * as fs from 'fs'; + +function _hasFolderPackageJsonTypeModule(folder) { + if (folder.endsWith('/node_modules')) { + return false; + } + let pj = path.join(folder, '/package.json'); + if (fs.existsSync(pj)) { + try { + let pkg = JSON.parse(fs.readFileSync(pj).toString()); + if (pkg) { + if (pkg.type === 'module') { + return true; + } else { + return false; + } + } + } catch (e) { + console.warn(`${pj} cannot be read, it will be ignored for ES module detection purposes.`, e); + return false; + } + } + if (folder === '/') { + return false; + } + return _hasFolderPackageJsonTypeModule(path.resolve(folder, '..')); +} + +function _hasPackageJsonTypeModule(file) { + let jsPath = file + '.js'; + if (fs.existsSync(jsPath)) { + return _hasFolderPackageJsonTypeModule(path.resolve(path.dirname(jsPath))); + } + return false; +} + +function _resolveHandlerFileName() { + const taskRoot = process.env.LAMBDA_TASK_ROOT; + const handlerDef = process.env._HANDLER; + const handler = path.basename(handlerDef); + const moduleRoot = handlerDef.substr(0, handlerDef.length - handler.length); + const [module, _] = handler.split('.', 2); + return path.resolve(taskRoot, moduleRoot, module); +} + +function _isHandlerAnESModule() { + const handlerFileName = _resolveHandlerFileName(); + if (fs.existsSync(handlerFileName + '.mjs')) { + return true; + } else if (fs.existsSync(handlerFileName + '.cjs')) { + return false; + } else { + return _hasPackageJsonTypeModule(handlerFileName); + } +} + +if (_isHandlerAnESModule()) { + /* + We could activate ESM loader hook of the "import-in-the-middle" library, + - by "--loader=import-in-the-middle/hook.mjs" Node CLI option, but "--loader" option has been deprecated + - or by "--import=import-in-the-middle/hook.mjs" Node CLI option, but in this case, + there will always be "import-in-the-middle" hook initialization overhead even for non-ESM (CommonJS) modules + + Hence, instead, we initialize "import-in-the-middle" hook only for ES (EcmaScript) based user handlers + to prevent redundant "import-in-the-middle" hook initialization overhead during coldstart + of the CommonJS based user handlers. + */ + register('import-in-the-middle/hook.mjs', import.meta.url); +}