Skip to content

Commit

Permalink
fix: Ensure CommonJS mode works correctly.
Browse files Browse the repository at this point in the history
Rollup mangles dynamic imports and without a way to override that, I
instead switched the source code to CommonJS and then have it exported
from an ESM module for compatibility.

Fixes #6
  • Loading branch information
nzakas committed Aug 18, 2022
1 parent 2bb6775 commit cf54a0b
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 72 deletions.
11 changes: 6 additions & 5 deletions package.json
Expand Up @@ -2,16 +2,17 @@
"name": "@humanwhocodes/module-importer",
"version": "1.0.0",
"description": "Universal module importer for Node.js",
"main": "dist/module-importer.cjs",
"module": "dist/module-importer.js",
"main": "src/module-importer.cjs",
"module": "src/module-importer.js",
"type": "module",
"types": "dist/module-importer.d.ts",
"exports": {
"require": "./dist/module-importer.cjs",
"import": "./dist/module-importer.js"
"require": "./src/module-importer.cjs",
"import": "./src/module-importer.js"
},
"files": [
"dist"
"dist",
"src"
],
"publishConfig": {
"access": "public"
Expand Down
81 changes: 81 additions & 0 deletions src/module-importer.cjs
@@ -0,0 +1,81 @@
/**
* @fileoverview Universal module importer
*/

//-----------------------------------------------------------------------------
// Imports
//-----------------------------------------------------------------------------

const { createRequire } = require("module");
const { pathToFileURL } = require("url");

//-----------------------------------------------------------------------------
// Helpers
//-----------------------------------------------------------------------------

const SLASHES = new Set(["/", "\\"]);

/**
* Normalizes directories to have a trailing slash.
* Resolve is pretty finicky -- if the directory name doesn't have
* a trailing slash then it tries to look in the parent directory.
* i.e., if the directory is "/usr/nzakas/foo" it will start the
* search in /usr/nzakas. However, if the directory is "/user/nzakas/foo/",
* then it will start the search in /user/nzakas/foo.
* @param {string} directory The directory to check.
* @returns {string} The normalized directory.
*/
function normalizeDirectory(directory) {
if (!SLASHES.has(directory[directory.length-1])) {
return directory + "/";
}

return directory;
}

//-----------------------------------------------------------------------------
// Exports
//-----------------------------------------------------------------------------

/**
* Class for importing both CommonJS and ESM modules in Node.js.
*/
exports.ModuleImporter = class ModuleImporter {

/**
* Creates a new instance.
* @param {string} [cwd] The current working directory to resolve from.
*/
constructor(cwd = process.cwd()) {

/**
* The base directory from which paths should be resolved.
* @type {string}
*/
this.cwd = normalizeDirectory(cwd);
}

/**
* Resolves a module based on its name or location.
* @param {string} specifier Either an npm package name or
* relative file path.
* @returns {string|undefined} The location of the import.
* @throws {Error} If specifier cannot be located.
*/
resolve(specifier) {
const require = createRequire(this.cwd);
return require.resolve(specifier);
}

/**
* Imports a module based on its name or location.
* @param {string} specifier Either an npm package name or
* relative file path.
* @returns {Promise<object>} The module's object.
*/
import(specifier) {
const location = this.resolve(specifier);
return import(pathToFileURL(location).href);
}

}
73 changes: 7 additions & 66 deletions src/module-importer.js
Expand Up @@ -7,75 +7,16 @@
//-----------------------------------------------------------------------------

import { createRequire } from "module";
import { pathToFileURL } from "url";
import { fileURLToPath } from "url";
import { dirname } from "path";

//-----------------------------------------------------------------------------
// Helpers
//-----------------------------------------------------------------------------

const SLASHES = new Set(["/", "\\"]);
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const require = createRequire(__dirname + "/");
const { ModuleImporter } = require("./module-importer.cjs");

/**
* Normalizes directories to have a trailing slash.
* Resolve is pretty finicky -- if the directory name doesn't have
* a trailing slash then it tries to look in the parent directory.
* i.e., if the directory is "/usr/nzakas/foo" it will start the
* search in /usr/nzakas. However, if the directory is "/user/nzakas/foo/",
* then it will start the search in /user/nzakas/foo.
* @param {string} directory The directory to check.
* @returns {string} The normalized directory.
*/
function normalizeDirectory(directory) {
if (!SLASHES.has(directory[directory.length-1])) {
return directory + "/";
}

return directory;
}

//-----------------------------------------------------------------------------
// Exports
//-----------------------------------------------------------------------------

/**
* Class for importing both CommonJS and ESM modules in Node.js.
*/
export class ModuleImporter {

/**
* Creates a new instance.
* @param {string} [cwd] The current working directory to resolve from.
*/
constructor(cwd = process.cwd()) {

/**
* The base directory from which paths should be resolved.
* @type {string}
*/
this.cwd = normalizeDirectory(cwd);
}

/**
* Resolves a module based on its name or location.
* @param {string} specifier Either an npm package name or
* relative file path.
* @returns {string|undefined} The location of the import.
* @throws {Error} If specifier cannot be located.
*/
resolve(specifier) {
const require = createRequire(this.cwd);
return require.resolve(specifier);
}

/**
* Imports a module based on its name or location.
* @param {string} specifier Either an npm package name or
* relative file path.
* @returns {Promise<object>} The module's object.
*/
import(specifier) {
const location = this.resolve(specifier);
return import(pathToFileURL(location).href);
}

}
export { ModuleImporter };
2 changes: 1 addition & 1 deletion tests/pkg.test.cjs
Expand Up @@ -3,5 +3,5 @@
*/

const { ModuleImporter } = require("../");
new ModuleImporter();
(new ModuleImporter()).import("./src/module-importer.js");
console.log("CommonJS load: success");

0 comments on commit cf54a0b

Please sign in to comment.