From ee6e0acc2e5986b762d1b614bdab55faef6227b5 Mon Sep 17 00:00:00 2001 From: Khiet Tam Nguyen Date: Fri, 20 Oct 2023 17:50:11 +1100 Subject: [PATCH] Implementation and documentation updated - now allows for pure-esm to be imported into cjs --- README.md | 2 ++ src/files.ts | 17 ----------------- src/import.ts | 35 +++++++++++++++++++++++++---------- 3 files changed, 27 insertions(+), 27 deletions(-) delete mode 100644 src/files.ts diff --git a/README.md b/README.md index 472f4b0..8be7376 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,8 @@ Synchronously import dynamic ECMAScript Modules similar to CommonJS [require](ht Basic wrapper around [esm](https://github.com/standard-things/esm) for compatibility with both ES6 and CJS projects in NodeJS +Capable of importing pure-esm libraries such as node-fetch@3 in CJS projects + [![Try with Replit](https://replit.com/badge?caption=Try%20with%20Replit)](https://replit.com/@nktnet1/import-sync-example#index.js) diff --git a/src/files.ts b/src/files.ts deleted file mode 100644 index 00493fb..0000000 --- a/src/files.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Get the file path of the caller function. - * - * Implementation inspired by: - * - https://www.npmjs.com/package/callsite?activeTab=code - * - * @returns {string} absolute path or an empty string if no caller - */ -export const getCallerFilePath = (): string => { - const orig = Error.prepareStackTrace; - Error.prepareStackTrace = (_, stack) => stack; - const err = new Error(); - Error.captureStackTrace(err, getCallerFilePath); - const stack = err.stack as any; - Error.prepareStackTrace = orig; - return stack[1].getFileName(); -}; diff --git a/src/import.ts b/src/import.ts index 14acf8c..5d8e3d3 100644 --- a/src/import.ts +++ b/src/import.ts @@ -1,21 +1,36 @@ +import esm from 'esm'; import path from 'path'; -import { getCallerFilePath } from './files'; +import fs from 'fs'; import { ESMOptions, Options } from './types'; /** * Creates an esm-compatible require function that can import ES Modules * - * Removes the error for "[ERR_REQUIRE_ESM]: require() of ES Module", as per - * - https://github.com/standard-things/esm/issues/855#issuecomment-657982788 - * * @returns an ESM-compatible require function */ +/* istanbul ignore next */ const createEs6Require = (esmOptions: ESMOptions) => { - /* istanbul ignore next */ + /** + * Removes the error for "[ERR_REQUIRE_ESM]: require() of ES Module", as per + * - https://github.com/standard-things/esm/issues/855#issuecomment-657982788 + */ require('module').Module._extensions['.js'] = (m: any, filename: string) => { - m._compile(require('fs').readFileSync(filename, 'utf-8'), filename); + m._compile(fs.readFileSync(filename, 'utf-8'), filename); + }; + const loader = esm(module, esmOptions); + + const newModule = module.constructor.length > 1 ? module.constructor : loader('module'); + const oldResolveFilename = newModule._resolveFilename; + /** + * Referencing + * - https://github.com/kenotron/esm-jest/commit/624b9524ee698f5cbd16ee2481dc4cd0dec52e42 + * - https://github.com/standard-things/esm/issues/331#issuecomment-377056717 + */ + newModule._resolveFilename = function(request: string, parent: any, isMain: boolean) { + const newRequest = request.startsWith('node:') ? request.substring(5) : request; + return oldResolveFilename.call(this, newRequest, parent, isMain); }; - return require('esm')(module, esmOptions); + return loader; }; /** @@ -26,13 +41,13 @@ const createEs6Require = (esmOptions: ESMOptions) => { * @param {Options} [options] - options as defined in types.ts * @returns the imported module */ -const importSync = (relativePath: string, options: Options = {}) => { +const importSync = (id: string, options: Options = {}) => { const defaultOptions: Required = { - basePath: path.dirname(getCallerFilePath()), + basePath: require.main?.path || '', esmOptions: {}, }; const opts = { ...defaultOptions, ...options }; - const filePath = path.join(opts.basePath, relativePath); + const filePath = path.join(opts.basePath, id); const es6Require = createEs6Require(opts.esmOptions); try { return es6Require(filePath);