Created
July 5, 2019 19:44
-
-
Save KaMeHb-UA/f0c4c20311154fe86597e70bb54d9a9b to your computer and use it in GitHub Desktop.
nodejs esm loader with https protocol support
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// just place this file where you want, then exec node with --experimental-modules --loader "path-to-loader.mjs" | |
import path from 'path'; | |
import process from 'process'; | |
import Module from 'module'; | |
import https from 'https'; | |
import os from 'os'; | |
import fs from 'fs'; | |
const __tmpdir = os.tmpdir(); | |
function rand(){ | |
return Math.random().toString(36).substring(2, 15) | |
} | |
function httpsDownload(url, file){ | |
return new Promise((resolve, reject) => { | |
const fws = fs.createWriteStream(file); | |
https.get(url, response => { | |
response.pipe(fws); | |
fws.on('finish', () => fws.close(resolve)) | |
}).on('error', err => { | |
fs.unlink(file); | |
reject(err) | |
}) | |
}) | |
} | |
// will contain module file url and real url pairs | |
const httpsModuleLinksStore = {}; | |
async function httpsDownloadModule(url){ | |
const modulePath = path.resolve(__tmpdir, rand() + '.mjs'); | |
await httpsDownload(url, modulePath); | |
httpsModuleLinksStore[new URL(`${modulePath}`, 'file://').href] = url; | |
return modulePath | |
} | |
const builtins = Module.builtinModules; | |
const JS_EXTENSIONS = new Set(['.js', '.mjs']); | |
const baseURL = new URL(`${process.cwd()}/`, 'file://').href; | |
export function resolve(specifier, parentModuleURL = baseURL, defaultResolve){ | |
if (builtins.includes(specifier)) return { | |
url: specifier, | |
format: 'builtin' | |
} | |
if(specifier.startsWith('https://') || ( | |
parentModuleURL in httpsModuleLinksStore && | |
/^\.\.?/.test(specifier) | |
)){ | |
return { | |
url: new URL(specifier, httpsModuleLinksStore[parentModuleURL]).href, | |
format: 'dynamic', | |
} | |
} | |
if (/^\.{0,2}[/]/.test(specifier) !== true && !specifier.startsWith('file:')) throw new Error(`imports must begin with '/', './', or '../'; '${specifier}' does not`); | |
const resolved = new URL(specifier, parentModuleURL); | |
const ext = path.extname(resolved.pathname); | |
if (!JS_EXTENSIONS.has(ext)) throw new Error(`Cannot load file with non-JavaScript file extension ${ext}.`); | |
return { | |
url: resolved.href, | |
format: 'module' | |
} | |
} | |
export async function dynamicInstantiate(url){ | |
const fname = await httpsDownloadModule(url); | |
const exp = await import(fname); | |
fs.unlink(fname); | |
const exports = Object.getOwnPropertyNames(exp); | |
return { | |
exports, | |
execute: (exportObj) => { | |
exports.forEach(name => { | |
exportObj[name].set(exp[name]) | |
}) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment