From 15d8dd3c10b04b9a66f7aed4079196ee2d44d6ad Mon Sep 17 00:00:00 2001 From: Brandon Ryan Date: Tue, 15 Dec 2020 01:27:10 -0600 Subject: [PATCH] removed loader type flag in favor of auto resolution --- v14.x/bootstrap.js | 104 +++++++++++++++++++++++++++----------- v14.x/esm-loader-hook.mjs | 15 ++---- v14.x/layer.zip | Bin 25058450 -> 25059179 bytes 3 files changed, 78 insertions(+), 41 deletions(-) diff --git a/v14.x/bootstrap.js b/v14.x/bootstrap.js index 9a77763..c6e8b2a 100644 --- a/v14.x/bootstrap.js +++ b/v14.x/bootstrap.js @@ -1,5 +1,7 @@ import http from 'http' import { createRequire } from 'module' +import path from 'path' +import { stat, readFile } from "fs/promises" const RUNTIME_PATH = '/2018-06-01/runtime' @@ -14,7 +16,6 @@ const { LAMBDA_TASK_ROOT, _HANDLER, AWS_LAMBDA_RUNTIME_API, - NODE_MODULE_LOADER_TYPE = 'commonjs' // or 'module' } = process.env const [HOST, PORT] = AWS_LAMBDA_RUNTIME_API.split(':') @@ -138,49 +139,34 @@ async function postError(path, err) { } async function getHandler() { - const appParts = _HANDLER.split('.') - - if (appParts.length !== 2) { + const moduleParts = _HANDLER.split('.') + if (moduleParts.length !== 2) { throw new Error(`Bad handler ${_HANDLER}`) } - if (NODE_MODULE_LOADER_TYPE !== 'commonjs' && NODE_MODULE_LOADER_TYPE !== 'module') { - throw new Error( - `Provided NODE_MODULE_LOADER_TYPE environment variable is invalid: ` + - `${NODE_MODULE_LOADER_TYPE}. Must be either 'commonjs' or 'module' ` + - `if specified.` - ) - } - - // Only create require if the loader is set to commonjs - const require = NODE_MODULE_LOADER_TYPE === 'commonjs' - ? createRequire(import.meta.url) - : null - - const [modulePath, handlerName] = appParts + const [modulePath, handlerName] = moduleParts + const {type: moduleLoaderType, ext} = await getModuleLoaderType(`${LAMBDA_TASK_ROOT}/${modulePath}`) // Let any errors here be thrown as-is to aid debugging - const importPath = `${LAMBDA_TASK_ROOT}/${modulePath}.js` - const app = NODE_MODULE_LOADER_TYPE === 'commonjs' - ? require(importPath) - : await import(importPath) + const importPath = `${LAMBDA_TASK_ROOT}/${modulePath}.${ext}` + const module = moduleLoaderType === 'module' ? await import(importPath) : createRequire(import.meta.url)(importPath) - const userHandler = app[handlerName] + const userHandler = module[handlerName] - if (userHandler == null) { + if (userHandler === undefined) { throw new Error(`Handler '${handlerName}' missing on module '${modulePath}'`) } else if (typeof userHandler !== 'function') { throw new Error(`Handler '${handlerName}' from '${modulePath}' is not a function`) } return (event, context) => new Promise((resolve, reject) => { - context.succeed = resolve - context.fail = reject - context.done = (err, data) => err ? reject(err) : resolve(data) - const callback = (err, data) => { context[CALLBACK_USED] = true - context.done(err, data) + if(err) { + reject(err) + } else { + resolve(data) + } } let result @@ -189,12 +175,70 @@ async function getHandler() { } catch (e) { return reject(e) } - if (result != null && typeof result.then === 'function') { + if (typeof result === 'object' && result != null && typeof result.then === 'function') { result.then(resolve, reject) } }) } +/** + * @param {string} modulePath path to executeable with no file extention + * @returns {Promise<{ + * type: 'commonjs' | 'module', + * ext: 'mjs' | 'cjs' | 'js' + * }>} loader type and extention for loading module + */ +async function getModuleLoaderType(modulePath) { + //do all promises async so they dont have to wait on eachother + const [typ, mjsExist, cjsExist] = await Promise.all([ + getPackageJsonType(modulePath), + fileExists(modulePath + '.mjs'), + fileExists(modulePath + '.cjs') + ]) + + //priority here is basically cjs -> mjs -> js + //pjson.type defaults to commonjs so always check if 'module' first + if(mjsExist && cjsExist) { + if(typ === 'module') { return {type: 'module', ext: 'mjs'} } + return {type: 'commonjs', ext: 'cjs'} + } + //only one of these exist if any + if(mjsExist) { return {type: 'module', ext: 'mjs'} } + if(cjsExist) { return {type: 'commonjs', ext: 'cjs'} } + //js is the only file, determine type based on pjson + if(typ === 'module') { return {type: 'module', ext: 'js'} } + return {type: 'commonjs', ext: 'js'} +} + +async function fileExists(fullPath) { + try { + await stat(fullPath) + return true + } catch { + return false + } +} + +/** + * @param {string} modulePath path to executeable with no file extention + * @returns {Promise<'module' | 'commonjs'>} + */ +async function getPackageJsonType(modulePath) { + //try reading pjson until we reach root. i.e. '/' !== path.dirname('/') + //there is probably a way to make it search in parallel, returning the first match in the hierarchy, but it seems more trouble than its worth + for(let dir = path.dirname(modulePath); dir !== path.dirname(dir); dir = path.dirname(dir)) { + try { + const {type} = JSON.parse(await readFile(dir + path.sep + 'package.json', 'utf-8')) + return type || 'commonjs' + } catch { + //do nothing + } + } + + //if we reach root, return empty pjson + return 'commonjs' +} + function request(options) { options.host = HOST options.port = PORT diff --git a/v14.x/esm-loader-hook.mjs b/v14.x/esm-loader-hook.mjs index 39f9c79..5d72064 100644 --- a/v14.x/esm-loader-hook.mjs +++ b/v14.x/esm-loader-hook.mjs @@ -1,8 +1,7 @@ -const searchPaths = [ - 'file:///opt/nodejs/', - `file:///opt/node${getMajorVersion()}/`, - 'file:///var/runtime/' -] +import {pathToFileURL} from "url" +import path from "path" + +const searchPaths = process.env.NODE_PATH.split(path.delimiter).map(path => pathToFileURL(path).href) export async function resolve(specifier, context, defaultResolve) { try { @@ -17,9 +16,3 @@ export async function resolve(specifier, context, defaultResolve) { throw new Error(`Cannot find package '${specifier}': attempted to import from paths [${[context.parentURL, ...searchPaths].join(', ')}]`) } - - -function getMajorVersion() { - let version = process.version - return version.slice(1, version.indexOf('.')) -} diff --git a/v14.x/layer.zip b/v14.x/layer.zip index 2040cd8a787505fb2cda147f91f66fa433926e4c..743c795154a8d86e528addd857208ff94ee70f3b 100644 GIT binary patch delta 5019 zcmZYDcQ}>*|G@EcDC^kC-dkiwRvfZP2O%RPWF#{raWbM|l&mtdiIi2DN%pKLBV`w| zqNK#{_3nH9e&65s^Zn!TypH>R--qjRo%_7*cjEJH+)~pvj)q`Jx{nEi!BAixDkt2b z;UQml8nFjYIBC`+!S040a!^#{A8{uSE;@D7eYdLJ%oP86!xE z1tfqJ>;wA&86XD~0Ii_{I6w_(04<;c^nd{{f&+jF90bgO1+W4(zz#S7C*T6yfCumb zKEMwIfFKY8!axLw0x@t1hyw|57)SysAPr=IERX|7fILtDM}Z&p zTm|7E0z`r+a1BI*7;qij05`!c5DVf!JV*ey!5xqY?t&zc3{pTUNCWr4eUJ_^Kqkln z*&qiz0J$I!4C;_G5At(do;1Q?*kHHgA393Lfr~$R$DR>5+gE~+T8bBjx z0?ptBXaO%lD|iLkKs)FFouCVJgC5We`anMz0E6H)cmv*oAutTyf%jkpjDj&R4nBYh z@DY3hlVA!=gBdUj=D);#M0Gr@D_yM-SPp}Psf!|;U z`~kaQ?-qRa695Vc3MtAyl>I1VDC8&kwlR~ zkw%e0kwuY1If5dOqJVM~MG-{_MHxi}MHS^3iW-VK3LZrRMHA&XiWZ7CiVlh{iXMtS ziUEotiV?~Q6l0W=CAJ|D5p`ZP^?jGP;61opxB| zLUBfMK{o*o0*V)kH;NC6FNzV*e1XL!_Ib2QQ+KR}QJGNb z=lsNyamAK9#XL!VlWAZTmnZR&alF$&og#Q^E-&iQS3;&B-_qV)3A4+()HRkF6%$or zYfj(C@H&s8^tIcx(jMfBD;B8)@ka$JNbft9zu}TjB~5&#W&Wv5hz`5i~cI5W4oja>lH+m_nv?x@6{5q6T7F||(KduVTYWt)^@zRj6 zoSvLpFl&NpB$J%^!3K5%#^U|e?H83pG8z1|f0S;fc!kE0RiDi~K5<>GpHoBiYpb|s z&oa|wWzU=-%QVr%>m{+IAW7g&@#~$0plc&Bq@tf^X&u%vIDXyr6%(r^R#~UFwdK1e z_7tzHxs%hs&@#!TWXbFg^ihl1WxTStl?raGr7aZGF^<@#}C-(+}j+ z$Bs6R+umfAh;a4n5%20EQ1AT?SaQUX27j12z*|#i^XF&4)9Y_DeD#@4=bihl3{-a( zxn5lk)jpRIok+Wot=%hT#gUt&t*uEktW-_HRYlro&S*wg>R;8}lriq!_%xuc5+n5_ zXZm+!BwJ6EVC&MY_3fOa&llqdI%U?!R^vbJeo+2Z60lj@cgv_v!herTh@=v%)6<64IrO;G|CpF+iV=2n(Abmo)I9W zwi(ho=6*hRWjJ`lfo6+LpudMK-727?QQKNPVfpcf9q#n=1r;;7a*)PTQGVhfh~?+Qxfeglge{bkdt@aBHk7Z0vl6eW%|39Wxn(AP^g-TVekDr&;3@$qFea}ia#gqb^OHny$X8U2Ea`TYmYO}Uqew_As$ z@_KNSJu_d`vZPE5oI;DLIv5(RPHQ}Www@@RspHr)6p=DJ6S{tmrnRP16Bg8- zr97zwq3E&T&nBO{Y%nf8KdmMTN{Cfj1*V&?_Zg+Sp7fX5Jj~%(e%m$0^5u%Uuf;5j zBbDTp%0;p1J5giVEBTL-HB5CjnZH{!K5`>Q;$C!k`4vSSNPLsD?xJq&)S1%qdqTv+ zJk#MA$D1Qjs=X^64xEbYBKi`_WMrJKPdmxKBt^s?`$ZG_)16|GKI-?pVQXj#@s-bG zmxw&7UyQ3myY6f%hn|1CeSYnV(m2af>k2l5^%Yx2!knLtK>Y@lOKq^%d`hYL_)ejO z^`XbI*Xz#62Tjh)9h_HUmDdnrp-y~LA5qxz){e++M`!s?%gdu;oS9?wh(LpRjAvy2 zp=nHuHuGzxS9V&vI+gtTdL2oZ4u%nz+RY~atkg_i2nZ3o>YbuicbXGnrzyNk>PI#Te$*XpGw*Zwqs5sVvuoMn_w1#3g*^k0JkRsI$Qh1fL=U?b z(TMq{k$1QpNCrGs2KQ6;tvK?VkF5^>31v;5>6z-54P>X6J89L_MIO%h(^wY4asat%)B#`jA(JQfOVj6Oc?ycFF#CDZSS7?04$ zt%3XDZW6=7^Y)Gq9aFZe+HqQOlAs^e%Q#k>)y?TY(Myw2e->dCK-+`zS2 z`3%n#zV%5rIcUC-tYzp-_K+pvc|4s*ty@aaxcUmaxV6i}C-Kk10=u7d6zVNb(R-vc ztGv6$W})zf^m)!bwd#W`uL?%LnGoe|OJ(1OZOmV7;3LLZh#GYn9ACbF>P~LdiZ~dxjz+X7R7mqAc``o3#qN;gwOy${ygr^Lg0b3- z%Vc`QoAWZ{7cOb7F7TWOHd0*Y<*0xJo8^tqu7v9e@Gb0Y-JLFnv(fsY5 zcDe2O0TGrj5(YHiI{7n*l4E$IiS*8;2B(X1lV8rt*iy;b5IRGyZ!q?KmSHiSdg#5J zYiH9N#L@VeX6Gms)-yTuIi&!HlJQ{K39n(%o~u>WZjm*?ES^uT$bwwhgl=0;YJ^Y4 z-VdKAa338GjpO$5tlb;&Du^|3(3NPy4N@i__a^Z()eoi;(u-05NvSOS)sXmFfPC-4 zsKJAQk|Lwp2_L0!1@ffQ%Hmyvn>3Ev({){w4Q&I-^+)NjZ!c7A?U9$tnl>vjD_X5; zB#M|0V_@pvdx|HRdhw4$iOe$S^5UsqvfahrAZ4eoSS~q~5JZui=1O=LdfL;?Sm78p zsnDlF=+uQy*#=McuyC%&(lkV+$FY3;FYx-BcMD|%Zgx1BZj*1C-ko~GU&xtoINjM= zuP?fgB$jGg&~^WPf~FMKCPG#7cnu~L;~83(l_Ol@{*`q~%7eIMyyjjT=$VumXBL~8 zb*WM5>9~f$o?H|)W`^mchJRGOZN2E=0fu!dCGS69CRnq?AI{q}=pdx{f*Du|TQZ$eC zCw>7_lW0l1#1%jtIdbI2h^M6>X$-2he=_VDx1$H49iSOg|?(HunCp@1I~z& z!WPuuGn{A#D;p1MB>o=rhF6^bd_uVQ_cS~m{Ob~h{~lyn|GqsuPhj%HD`8Ci-?7%i z-`mUl)P4*p8fwvB!m03|LoJ$u|Nq5!GZ=imy)XJ-^mFu)^zi?CF^s#}p0;6FUNYY^ IVem`-2dzELr2qf` delta 4256 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