diff --git a/lib/preload.js b/lib/preload.js index 831457b..659d463 100644 --- a/lib/preload.js +++ b/lib/preload.js @@ -1,7 +1,9 @@ 'use strict'; // Modules -const SynchronousWorker = require('@matteo.collina/worker'); +const {MessageChannel} = require('worker_threads'), + SynchronousWorker = require('@matteo.collina/worker'), + {isFunction} = require('is-it-type'); // Imports const {createChannels, wrapError} = require('./utils.js'), @@ -13,9 +15,12 @@ module.exports = function preload(loaderUrl, port, getBuiltin) { const {listen, message, post} = createChannels(port, 'inner'); port.unref(); - let loader; + let worker, loader; try { - loader = importSync(loaderUrl); + worker = new SynchronousWorker(); + const workerImport = worker.createRequire(__filename)('./import.js'); + const promise = workerImport(loaderUrl); + loader = worker.runLoopUntilPromiseResolved(promise); } catch (err) { post(0, FAIL, INIT, wrapError(err)); return; @@ -23,26 +28,30 @@ module.exports = function preload(loaderUrl, port, getBuiltin) { const {resolve, load} = loader; - listen((channelId, hook, data) => (hook === RESOLVE ? resolve : load)( - ...data, - (specifier, context) => message(channelId, NEXT, hook, [specifier, context]) - )); + listen((channelId, hook, data) => { + const promise = (hook === RESOLVE ? resolve : load)( + ...data, + (specifier, context) => message(channelId, NEXT, hook, [specifier, context]) + ); + + if (!promise || !isFunction(promise.then)) { + console.log('is not promise'); + return promise; + } + + const res = worker.runLoopUntilPromiseResolved(promise); + console.log('res:', res); + return res; + }); post(0, SUCCESS, INIT, {resolve: !!loader.resolve, load: !!loader.load}); if (loader.globalPreload) { - // TODO Proxy outer port - const preloadCode = loader.globalPreload(); - - // TODO Proxy inner port + const {port1, port2} = new MessageChannel(); + const preloadCode = loader.globalPreload.call(undefined, {port: port1}); // eslint-disable-next-line no-new-func - new Function('getBuiltin', preloadCode)(getBuiltin); + new Function('getBuiltin', 'port', preloadCode)(getBuiltin, port2); } -}; -function importSync(url) { - const worker = new SynchronousWorker(); - const workerImport = worker.createRequire(__filename)('./import.js'); - const promise = workerImport(url); - return worker.runLoopUntilPromiseResolved(promise); -} + // TODO Patch CommonJS loader +}; diff --git a/lib/utils.js b/lib/utils.js index ce5cbd2..13badc0 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -4,7 +4,7 @@ const {isFunction} = require('is-it-type'); // Imports -const {INCOMING, SUCCESS, FAIL, ERROR, OTHER} = require('./constants.js'); +const {INCOMING, SUCCESS, FAIL, NEXT, ERROR, OTHER, RESOLVE, LOAD} = require('./constants.js'); // Exports @@ -16,17 +16,20 @@ function createChannels(port, logName) { function listen(onIncoming) { port.onmessage = ({data: {id, type, hook, data}}) => { - // TODO Remove console.log - // eslint-disable-next-line no-console - console.log(`${logName} received message:`, {id, type, hook, data}); + logMessage(logName, 'received', id, type, hook, data); if (type === INCOMING) { - onIncoming(id, hook, data).then( - res => post(id, SUCCESS, hook, res), - err => post(id, FAIL, hook, wrapError(err)) - ); + let res; + try { + res = onIncoming(id, hook, data); + } catch (err) { + post(id, FAIL, hook, wrapError(err)); + return; + } + post(id, SUCCESS, hook, res); return; } + callbacks.get(id)(type, data); }; } @@ -69,9 +72,7 @@ function createChannels(port, logName) { } function post(id, type, hook, data) { - // TODO Remove console.log - // eslint-disable-next-line no-console - console.log(`${logName} sending message:`, {id, type, hook, data}); + // debugMessage(logName, 'sending', id, type, hook, data); port.postMessage({id, type, hook, data}); } @@ -106,3 +107,12 @@ function unwrapError(errDef) { Object.assign(err, errDef.props); return err; } + +function logMessage(logName, action, id, type, hook, data) { + console.log(`${logName} ${action} message:`, { // eslint-disable-line no-console + id, + type: {[INCOMING]: 'INCOMING', [SUCCESS]: 'SUCCESS', [FAIL]: 'FAIL', [NEXT]: 'NEXT'}[type] || type, + hook: {[RESOLVE]: 'RESOLVE', [LOAD]: 'LOAD'}[hook] || hook, + data + }); +}