Created
June 8, 2018 00:25
-
-
Save SMotaal/a8880ff65e366ef1c446614ac57408cc to your computer and use it in GitHub Desktop.
JS Bin
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
* { | |
font-family: sans-serif; | |
} |
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
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="width=device-width"> | |
<title>JS Bin</title> | |
<script> | |
console.clear(); | |
</script> | |
</head> | |
<body> | |
</body> | |
</html> |
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
/* | |
This is a very basic isomorphic Loader | |
which works by rewriting the specifiers | |
for static imports and exports. | |
*/ | |
(function (helpers) { | |
const { | |
runtime: { global, DynamicImport, RegisterModule }, | |
performance: { START, END, ENTRIES }, | |
symbols: { StateSymbol, MethodSymbol, RecordSymbol } | |
} = helpers; | |
console.log(helpers); | |
/** | |
* Global Modules Namespace | |
*/ | |
const Modules = global.Modules = { | |
// Methods | |
Define: MethodSymbol('define'), | |
Resolve: MethodSymbol('resolve'), | |
Load: MethodSymbol('load'), | |
Import: MethodSymbol('import'), | |
// Status | |
Uninstantiated: StateSymbol('uninstantiated'), | |
Instantiating: StateSymbol('instantiating'), | |
Instantiated: StateSymbol('instantiated'), | |
Evaluating: StateSymbol('evaluating'), | |
Evaluated: StateSymbol('evaluated'), | |
// Records | |
Status: RecordSymbol('Status'), | |
EvaluationError: RecordSymbol('EvaluationError'), | |
}; | |
/** | |
* ModuleSources | |
*/ | |
const ModuleSources = global['[[ModuleSources]]'] = { | |
// 'xyz': `export default 'xyz'`, | |
}; | |
(() => { | |
const { | |
// Methods | |
Resolve, Import, Load, Define, | |
// Status | |
Evaluated, Evaluating, Instantiated, Instantiating, Uninstantiated, | |
// Records | |
Status, EvaluationError | |
} = Modules; | |
const ModuleLoader = global['[[ModuleLoader]]'] = { | |
[Resolve]: (specifier, referrer) => { | |
}, | |
[Load]: (sourceURL) => { | |
if (sourceURL in ModuleMap) | |
return ModuleMap[sourceURL]; | |
if (sourceURL in ModuleSources) | |
return ModuleMap[Define](ModuleSources[sourceURL], sourceURL); | |
throw `Failed to load module from "${sourceURL}"`; | |
}, | |
[Import]: (specifier, referrer) => { | |
return ModuleLoader[Load](specifier).namespace(); | |
} | |
}; | |
const ModuleMap = global['[[ModuleMap]]'] = { | |
[Define]: (source, sourceURL = SRC()) => { | |
START('[1] define', sourceURL); | |
const links = []; | |
let k = 0; | |
START('[2] prelink', sourceURL); | |
const rawSource = source | |
// Replace ModuleDeclarations with ««—k—type———…»» | |
.replace( | |
/((?:import +(?:\* +as \w+|(?:\w+, *)?\{[^}]*?\}|\w+)|export +(?:\*|\{[^}]*?\})) +from +(['"]))(.*?)(\2)/ug, | |
(declaration, head, quote, specifier, tail, index) => { | |
const length = declaration.length; | |
const type = declaration[0] === 'i' ? 'import' : 'export'; | |
const marker = `${`««—${k++}—${type}—`.padEnd(length - 2, '—')}»»`; | |
links.push({ | |
declaration, type, head, quote, specifier, tail, marker, index, length | |
}); | |
return marker; | |
} | |
); | |
END('[2] prelink', sourceURL); | |
const module = { | |
links, source, rawSource, sourceURL, | |
[Status]: Uninstantiated, | |
async link() { | |
const module = this; | |
const sourceURL = module.sourceURL; | |
if (module.url) return module.url; | |
START('[3] link', sourceURL); | |
let linkedSource = module.rawSource; | |
module[Status] = Instantiating; | |
for (const { marker, specifier: originalSpecifier, head, tail } of links) { | |
const requiredModule = ModuleMap[originalSpecifier]; | |
const specifier = requiredModule && ( | |
requiredModule.url | |
|| (await requiredModule.link()) | |
) || ( | |
await (await ModuleLoader[Load](originalSpecifier)).link() | |
) || originalSpecifier; | |
const declaration = `${head}${specifier}${tail}` | |
linkedSource = linkedSource.replace(marker, declaration); | |
} | |
module.linkedSource = linkedSource; | |
const url = module.url = RegisterModule(linkedSource, sourceURL); | |
ModuleMap[sourceURL] = ModuleMap[url] = module; | |
END('[3] link', sourceURL); | |
return url; | |
}, | |
async evaluate() { | |
const module = this; | |
const sourceURL = module.sourceURL; | |
// if (module[Status] !== Uninstantiated) | |
// throw EvalError('Failed to link module with invalid status'); | |
// Link | |
const url = await this.link(); | |
// Instantiate | |
START('[4] evaluate', sourceURL); | |
const instantiate = DynamicImport(url); | |
module[Status] = Instantiated; | |
// Evaluate | |
await 0; | |
module[Status] = Evaluating; | |
module.namespace = async () => await instantiate; | |
try { | |
await instantiate; | |
} catch (exception) { | |
module[EvaluationError] = exception; | |
} finally { | |
module[Status] = Evaluated; | |
} | |
END('[4] evaluate', sourceURL); | |
return ModuleMap[sourceURL] = ModuleMap[url] = module; | |
}, | |
async namespace() { | |
return (await this.evaluate()).namespace(); | |
}, | |
}; | |
END('[1] define', sourceURL); | |
return ModuleMap[sourceURL] = module; | |
}, | |
} | |
return ModuleSources; | |
})(); | |
(async (sources = { | |
'typescript': ` | |
export const typescript = true; | |
export default "TypeScript" | |
`, | |
'ts1': ` | |
export * from 'typescript' | |
`, | |
'index': ` | |
import ts from 'typescript'; | |
// import ts, {a, b, c} from 'typescript'; | |
export * from 'typescript'; | |
export const index = true; | |
export { ts }; | |
`, | |
'fails': ` | |
import x from 'xyz'; | |
` | |
}) => { | |
const ModuleLoader = global['[[ModuleLoader]]']; | |
Object.assign(ModuleSources, sources); | |
const results = {}, namespaces = {}; | |
const specifiers = Object.keys(sources); // .reverse(); | |
// for (const specifier of [...specifiers, ...specifiers]) { | |
for (const specifier of specifiers) { | |
try { | |
results[specifier] = await ModuleLoader[Modules.Load](specifier); | |
namespaces[specifier] = await ModuleLoader[Modules.Import](specifier); | |
} catch (exception) { | |
results[specifier] = exception; | |
} | |
} | |
console.dir(results); | |
console.dir(ENTRIES.reduce( | |
(timing, { name, duration }) => (timing[name] = duration, timing), {} | |
)); | |
console.dir(namespaces); | |
})(); | |
console.log(global['[[ModuleMap]]']) | |
console.log(global['[[ModuleSources]]']); | |
})({ | |
runtime: RuntimeHelpers(), | |
performance: PerformanceHelpers(), | |
symbols: SymbolHelpers(), | |
}); | |
function RuntimeHelpers() { | |
const | |
JS = 'text/javascript', | |
UID = () => ~~(1e6 * Math.random()), | |
SRC = (uid = UID()) => | |
`VirtualModule-${uid}`, | |
SourceText = (source, url = SRC()) => | |
`${source}\n\n//# sourceURL=${url}\n`; | |
if (typeof process === 'undefined' && typeof window !== 'undefined') { | |
let importModule = async (url) => eval(`import("${url}")`); | |
importModule(`data:text/javascript,export default ''`) | |
.catch(() => { | |
/** | |
* Can't find my experiment for that one so thanks to uupaa et al | |
* | |
* @source https://github.com/uupaa/dynamic-import-polyfill/blob/dda7fd22eaceb6e9642dc3189fadc89db405f9b5/importModule.js#L7 | |
*/ | |
importModule = (url) => new Promise((resolve, reject) => { | |
const vector = "$importModule$" + Math.random().toString(32).slice(2); | |
const script = document.createElement("script"); | |
const destructor = () => { | |
delete window[vector]; | |
script.onerror = null; | |
script.onload = null; | |
script.remove(); | |
URL.revokeObjectURL(script.src); | |
script.src = ""; | |
}; | |
script.defer = "defer"; | |
script.type = "module"; | |
script.onerror = () => { | |
reject(new Error(`Failed to import: ${url}`)); | |
destructor(); | |
}; | |
script.onload = () => { | |
resolve(window[vector]); | |
destructor(); | |
}; | |
const absURL = url; // toAbsoluteURL(url); | |
const loader = `import * as m from "${absURL}"; window.${vector} = m;`; // export Module | |
const blob = new Blob([loader], { type: "text/javascript" }); | |
script.src = URL.createObjectURL(blob); | |
document.head.appendChild(script); | |
}); | |
}); | |
const | |
SourceFile = (source, url = SRC(), type = JS) => | |
new File([SourceText(source, url)], url, { type }), | |
SourceFileURL = (source, url = SRC(), type = JS) => | |
URL.createObjectURL(SourceFile(source, url, type)), | |
RegisterModule = (source, sourceURL) => | |
SourceFileURL(SourceText(source, sourceURL)), | |
DynamicImport = (url) => importModule(url); | |
return { global: window, RegisterModule, DynamicImport }; | |
} | |
if (typeof process === 'undefined') | |
throw Error('Unsupported runtime'); | |
const ModuleWrap = ((natives) => { | |
const requireNative = process.NativeModule | |
? process.NativeModule.require | |
: require || require(''); | |
if (natives.includes('internal/loader/ModuleWrap')) | |
return requireNative('internal/loader/ModuleWrap').ModuleWrap; | |
if (natives.includes('internal/modules/esm/create_dynamic_module')) | |
return requireNative('internal/modules/esm/create_dynamic_module') | |
('').module.constructor; | |
})(Object.keys(process.binding('natives'))); | |
const | |
ModuleMap = {}, | |
LinkModule = async (module) => { | |
const wrap = module.wrap; | |
const links = module.links = []; | |
await wrap.link(async (dependencySpecifier) => { | |
const module = ModuleMap[dependencySpecifier]; | |
if (!module) | |
throw ReferenceError(`Failed to link module: "${url}"`); | |
links.push(module); | |
return module.wrap; | |
}); | |
return Promise.all(links); | |
}, | |
RegisterModule = (source, sourceURL) => { | |
const url = sourceURL; // `vm:${UID()}`; | |
if (url in ModuleMap) | |
return RegisterModule(source, sourceURL); | |
const module = ModuleMap[url] = { | |
wrap: new ModuleWrap(SourceText(source, sourceURL), url), | |
} | |
console.log(`Constructed: ${module.wrap.url}`); | |
module.linked = LinkModule(module); | |
return url; | |
}, | |
InitializeModule = async (module) => { | |
const wrap = module.wrap; | |
await module.linked; | |
console.log(`Linked: ${module.wrap.url}`); | |
const links = module.links || []; | |
// TODO: Instantiate ModuleWrap for Node | |
await (module.instantiated || ( | |
module.instantiated = await Promise.all([ | |
...links.map(InitializeModule), | |
]).then(() => wrap.instantiate()) | |
)); | |
console.log(`Instantiated: ${module.wrap.url}`, Object.keys(wrap)); | |
await (module.evaluated || ( | |
module.evaluated = wrap.evaluate(-1, false) | |
)); | |
console.log(`Evaluated: ${module.wrap.url}`); | |
const namespace = await (module.namespace || ( | |
module.namespace = await wrap.namespace() | |
)); | |
console.log(`Imported: ${module.wrap.url}`, namespace); | |
return namespace; | |
}, | |
DynamicImport = async (url) => { | |
const module = ModuleMap[url]; | |
if (!module) | |
throw ReferenceError(`Failed to load module: "${url}"`); | |
console.log(`Import: ${module.wrap.url}`); | |
return InitializeModule(module); | |
} | |
return { global, RegisterModule, DynamicImport } | |
} | |
function PerformanceHelpers() { | |
const performanceEntries = []; | |
if (typeof performance !== 'undefined') { | |
if (typeof PerformanceObserver !== 'undefined') { | |
const performanceObserver = new PerformanceObserver((list, observer) => { | |
const entries = list.getEntries(); | |
performanceEntries.push(...entries); | |
// console.info(entries); | |
}); | |
performanceObserver.observe({ entryTypes: ['measure'] }); | |
} | |
return { | |
START: (OP, ID) => performance.mark(`START: «${ID}» — ${OP}`), | |
END: (OP, ID) => performance.measure( | |
`«${ID}» — ${OP}`, `START: «${ID}» — ${OP}`, | |
performance.mark(`END: «${ID}» — ${OP}`) | |
), | |
ENTRIES: performanceEntries, | |
}; | |
} | |
const noop = () => { }; | |
return { | |
START: noop, END: noop, ENTRIES: performanceEntries, | |
} | |
} | |
function SymbolHelpers( | |
StateSymbol = (state) => `"${state.toUpperCase()}"`, | |
MethodSymbol = (name) => `@@${name.replace(/^[A-Z]+/, s => s.toLowerCase())}`, | |
RecordSymbol = (name) => `[[${name}]]` | |
) { | |
return { | |
StateSymbol, MethodSymbol, RecordSymbol | |
}; | |
}; |
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
{"processors":{}} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment