UNPKG

jsboost

Version:

A tiny library that extends the capability of javascript

146 lines (123 loc) 4.96 kB
/** * ISC License * * Copyright (c) 2019, J. Cloud Yu * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. **/ /** * Version: 1.0.1 * Author: JCloudYu * Create: 2019/07/12 * * I've been encountered a stupid situation in which I want to write es module compatible libraries that * can be shared between nodejs and browser, but I have to rename my file in mjs to enable es module in nodejs * and at the same time, I have to provide correct mime type to make the browser accepts files ended with .mjs * extension. Here's why this module comes out! This module makes the nodejs environment accept files ended with * .esm.js to be a es module. Then I don't have to modify the server to tell the browser what a .js file is! * * Moreover, this module is also designed to provide path searching logic similar to what the browsers do. * This module interpret the module path according to the following rules. * * Assume that the entry module is located a path /a/b/c/entry.esm.js, then * 1. If the imported path is /i/j/k/module.esm.js, * then the path resolved to /a/b/c/j/j/k/module.esm.js * * 2. If the imported path is //i/j/k/module.esm.js, * the path is resolved to /node_modules/i/j/k/modules.esm.js * * 3. If the imported path is ./i/j/k/module.esm.js or ../i/j/k/module.esm.js * and the module which imports the path is locate a /a/b/c/d/e/module.esm.js * the path is resolved to /a/b/c/d/e/./i/j/k/module.esm.js or /a/b/c/d/e/../i/j/k/module.esm.js, respectively * * 4. If the imported path doesn't matches the above conditions, * then the path will be prefixed with ./ and use the condition 3 to process the path **/ // Source: https://gist.github.com/JCloudYu/87b4a5caff65320557452167e3466dbb import process from 'process'; import os from 'os'; // ES Modules' identifier is renamed into 'module' after NodeJS v12 const [NJS_MAJOR] = process.versions.node.split('.'); const ESM_IDENTIFIER = (NJS_MAJOR >= 12) ? 'module' : 'esm'; const CJM_IDENTIFIER = (NJS_MAJOR >= 12) ? 'commonjs' : 'cjs'; const NODE_JS_STYLED_MODULE_ROOT = true; const IS_WINDOWS = (os.platform().substring(0,3) === "win"); const IS_WIN_ABSOLUTE_PATH = /^[a-zA-Z]:\/[^/].*$/; const IS_COMPLETE_PATH = /^(\/\/|\/|\.\/|\.\.\/)(.*)$/; const PATHS = [ null, // Reserved for main module dir null, // Reserved for main module path `file://${IS_WINDOWS?'/':''}${process.cwd()}/` ]; export function resolve(specifier, parentModuleURL, defaultResolve) { // This specifier must be the main module with absolute path! (Without leading file://) if ( parentModuleURL === undefined ) { /** * We don't need to detect the leading C:/ in windows env here... * It has been processed to /C:/Users/XXX/Desktop/xxx.mjs already...awkward = =+ **/ const _MAIN_MODULE_PATH = PATHS[1] = `file://${specifier}`; const DIVIDER_POS = _MAIN_MODULE_PATH.lastIndexOf('/')+1; PATHS[0] = _MAIN_MODULE_PATH.substring(0, DIVIDER_POS); specifier = `./${_MAIN_MODULE_PATH.substring(DIVIDER_POS)}`; } // NOTE: Resolve the module type let _resolved_type = null; if ( specifier.substr(-7) === ".esm.js" ) { _resolved_type = ESM_IDENTIFIER; } else if ( specifier.substr(-3) === ".js" ) { _resolved_type = CJM_IDENTIFIER; } else if ( NJS_MAJOR >= 12 && specifier.substr(-5) === ".wasm" ) { _resolved_type = "wasm"; } // NOTE: If type is detected if ( _resolved_type !== null ) { let matches = null; if ( IS_WINDOWS && IS_WIN_ABSOLUTE_PATH.test(specifier) ) { specifier = `file:///${specifier}`; } else if ( (matches=specifier.match(IS_COMPLETE_PATH)) !== null ) { switch( matches[1] ) { case "//": specifier = `${PATHS[0]}node_modules/${specifier.substring(2)}`; break; case "/": specifier = `${PATHS[0]}${specifier.substring(1)}`; break; case "./": case "../": default: break; } } else { if ( NODE_JS_STYLED_MODULE_ROOT ) { specifier = `${PATHS[0]}node_modules/${specifier}`; } else { specifier = "./" + specifier } } return { url: new URL(specifier, parentModuleURL||PATHS[0]).href, format:_resolved_type }; } // NOTE: Fallback to standard nodejs module detection algorithm return defaultResolve(specifier, parentModuleURL); }