fix(dev): zero config support for ESM & CommonJS in dev mode (#12642)

* fix(dev): better esm errors in dev mode

* fix(dev): support esm and commonjs with zero config
This commit is contained in:
Eslam λ Hefnawy 2024-06-28 07:20:11 -07:00 committed by GitHub
parent 725b18f3ea
commit 3b39fbf0b2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 26 additions and 18 deletions

View File

@ -288,7 +288,7 @@ const runtimeWrappers = [
{
command: 'node',
arguments: [],
path: path.join(__dirname, 'runtime-wrappers/node.cjs'),
path: path.join(__dirname, 'runtime-wrappers/node.js'),
versions: ['nodejs14.x', 'nodejs16.x', 'nodejs18.x', 'nodejs20.x'],
extensions: ['.js', '.mjs', '.cjs', '.ts', '.mts', '.cts'],
},

View File

@ -1,7 +1,9 @@
const path = require('path')
const os = require('os')
const fs = require('fs')
const { inspect } = require('util')
import { pathToFileURL } from 'url'
import path from 'path'
import os from 'os'
import fs from 'fs'
import { inspect } from 'util'
import ServerlessError from '@serverlessinc/sf-core/src/utils/errors/serverlessError.js'
const originaStdoutlWrite = process.stdout.write
const originaStderrlWrite = process.stderr.write
@ -94,32 +96,38 @@ const saveInvocationResult = (result) => {
/**
* Imports the user handler function from the specified file path.
* We first try to require the file, and if it fails with ERR_REQUIRE_ESM, we import it.
* This supports both CommonJS and ESM handler files.
* If the file is already cached, it is deleted to ensure the latest version is imported
* as the user makes changes during the dev mode session
*
* @param {string} handlerFileAbsolutePath - Path to handler file
* @param {string} handlerName - The Handler Name defined in the config file
* @returns {Promise<Function>}
*/
const importFunction = async (handlerFileAbsolutePath, handlerName) => {
let handlerFunction
try {
handlerFunction = require(handlerFileAbsolutePath)[handlerName]
} catch (error) {
if (error.code === 'ERR_REQUIRE_ESM') {
handlerFunction = await import(handlerFileAbsolutePath)[handlerName]
}
throw error
// Check if the file exists
if (!fs.existsSync(handlerFileAbsolutePath)) {
throw new ServerlessError(
`Handler file was not found: ${handlerFileAbsolutePath}`,
'DEV_MODE_HANDLER_FILE_NOT_FOUND',
)
}
// Convert the file path to a file URL to ensure
// it works across different operating systems
// and for both CommonJS and ESM handler files
const fileUrl = pathToFileURL(handlerFileAbsolutePath).href
// Import the handler file. This works for both CommonJS and ESM handler files
const handlerFunction = (await import(fileUrl))[handlerName]
// Make sure the handler is a function
if (typeof handlerFunction !== 'function') {
throw new Error(`Handler is not a function`)
throw new ServerlessError(
`Handler is not a function`,
'DEV_MODE_INVALID_HANDLER',
)
}
// return the function to be invoked
return handlerFunction
}
/**