diff --git a/src/NodeAsyncHttpRuntime/LoadFileChunkLoadingRuntimeModule.js b/src/NodeAsyncHttpRuntime/LoadFileChunkLoadingRuntimeModule.js index de8e648..37c0ed8 100644 --- a/src/NodeAsyncHttpRuntime/LoadFileChunkLoadingRuntimeModule.js +++ b/src/NodeAsyncHttpRuntime/LoadFileChunkLoadingRuntimeModule.js @@ -11,7 +11,7 @@ const { getInitialChunkIds } = require("webpack/lib/javascript/StartupHelpers"); const compileBooleanMatcher = require("webpack/lib/util/compileBooleanMatcher"); const { getUndoPath } = require("webpack/lib/util/identifier"); -const rpcLoadTemplate = require("../templates/rpcLoad"); +const rpcLoadFromBaseURITemplate = require("../templates/rpcLoadFromBaseURI"); class ReadFileChunkLoadingRuntimeModule extends RuntimeModule { constructor(runtimeRequirements, options, context) { @@ -26,7 +26,7 @@ class ReadFileChunkLoadingRuntimeModule extends RuntimeModule { */ generate() { const { chunkGraph, chunk } = this; - const { baseURI, getBaseUri } = this.options; + const { baseURI, customRpcLoadFromBaseURITemplate, getBaseUri } = this.options; const { webpack } = this.context; const { runtimeTemplate } = this.compilation; const fn = RuntimeGlobals.ensureChunkHandlers; @@ -154,8 +154,8 @@ class ReadFileChunkLoadingRuntimeModule extends RuntimeModule { )} + ${ RuntimeGlobals.getChunkScriptFilename }(chunkId));`, - rpcLoadTemplate, - `rpcLoad(${ + customRpcLoadFromBaseURITemplate || rpcLoadFromBaseURITemplate, + `rpcLoadFromBaseURI(${ getBaseUri ? `await ${getBaseUri(baseURI)}` : `"${baseURI}"` @@ -201,9 +201,9 @@ class ReadFileChunkLoadingRuntimeModule extends RuntimeModule { `var filename = require('path').join(__dirname, ${JSON.stringify( rootOutputDir )} + ${RuntimeGlobals.getChunkUpdateScriptFilename}(chunkId));`, - rpcLoadTemplate, - `rpcLoad(${ - promiseBaseURI ? `await ${promiseBaseURI}` : `"${baseURI}"` + customRpcLoadFromBaseURITemplate || rpcLoadFromBaseURITemplate, + `rpcLoadFromBaseURI(${ + getBaseUri ? `await ${getBaseUri(baseURI)}` : `"${baseURI}"` }, ${ RuntimeGlobals.getChunkUpdateScriptFilename }(chunkId), function(err, content) {`, diff --git a/src/NodeAsyncHttpRuntime/index.js b/src/NodeAsyncHttpRuntime/index.js index 26fb669..bc54d17 100644 --- a/src/NodeAsyncHttpRuntime/index.js +++ b/src/NodeAsyncHttpRuntime/index.js @@ -33,6 +33,7 @@ class NodeAsyncHttpRuntime { { asyncChunkLoading: true, baseURI: compiler.options.output.publicPath, + customRpcLoadFromBaseURITemplate: this.options.customRpcLoadFromBaseURITemplate, getBaseUri: this.options.getBaseUri, }, this.context diff --git a/src/NodeModuleFederation/index.js b/src/NodeModuleFederation/index.js index ba69fb5..91e89ae 100644 --- a/src/NodeModuleFederation/index.js +++ b/src/NodeModuleFederation/index.js @@ -1,26 +1,5 @@ const rpcLoadTemplate = require("../templates/rpcLoad"); - -const rpcPerformTemplate = ` - ${rpcLoadTemplate} - function rpcPerform(remoteUrl) { - const scriptUrl = remoteUrl.split("@")[1]; - const moduleName = remoteUrl.split("@")[0]; - return new Promise(function (resolve, reject) { - rpcLoad(scriptUrl, function(error, scriptContent) { - if (error) { reject(error); } - //TODO using vm?? - const remote = eval(scriptContent + '\\n try{' + moduleName + '}catch(e) { null; };'); - if (!remote) { - reject("remote library " + moduleName + " is not found at " + scriptUrl); - } else if (remote instanceof Promise) { - return remote; - } else { - resolve(remote); - } - }); - }); - } -`; +const rpcPerformTemplate = require("../templates/rpcPerform"); const rpcProcessTemplate = (mfConfig) => ` function rpcProcess(remote) { @@ -44,9 +23,13 @@ const rpcProcessTemplate = (mfConfig) => ` } `; -function buildRemotes(mfConf, getRemoteUri) { +function buildRemotes( + mfConf, + { customRpcLoadTemplate, customRpcPerformTemplate, getRemoteUri } +) { const builtinsTemplate = ` - ${rpcPerformTemplate} + ${customRpcLoadTemplate || rpcLoadTemplate} + ${customRpcPerformTemplate || rpcPerformTemplate} ${rpcProcessTemplate(mfConf)} `; return Object.entries(mfConf.remotes || {}).reduce((acc, [name, config]) => { @@ -54,9 +37,7 @@ function buildRemotes(mfConf, getRemoteUri) { external: `external (async function() { ${builtinsTemplate} return rpcPerform(${ - getRemoteUri - ? `await ${getRemoteUri(config)}` - : `"${config}"` + getRemoteUri ? `await ${getRemoteUri(config)}` : `"${config}"` }).then(rpcProcess).catch((err) => { console.error(err); }) }())`, }; @@ -71,14 +52,23 @@ class NodeModuleFederation { } apply(compiler) { - const { getRemoteUri, ...options } = this.options; + const { + customRpcLoadTemplate, + customRpcPerformTemplate, + getRemoteUri, + ...options + } = this.options; // When used with Next.js, context is needed to use Next.js webpack const { webpack } = this.context; new (webpack?.container.ModuleFederationPlugin || require("webpack/lib/container/ModuleFederationPlugin"))({ ...options, - remotes: buildRemotes(options, getRemoteUri), + remotes: buildRemotes(options, { + customRpcLoadTemplate, + customRpcPerformTemplate, + getRemoteUri, + }), }).apply(compiler); } } diff --git a/src/templates/rpcLoad.js b/src/templates/rpcLoad.js index 98d53fb..fc2b328 100644 --- a/src/templates/rpcLoad.js +++ b/src/templates/rpcLoad.js @@ -1,21 +1,11 @@ /** - * rpcLoad(baseURI, fileName, cb) - * rpcLoad(scriptUrl, cb) + * rpcLoad(url, cb) */ module.exports = ` - function rpcLoad() { - var url; - var cb = arguments[arguments.length - 1]; + function rpcLoad(url, cb) { if (typeof cb !== "function") { throw new Error("last argument should be a function"); } - if (arguments.length === 2) { - url = arguments[0]; - } else if (arguments.length === 3) { - url = new URL(arguments[1], arguments[0]).toString(); - } else { - throw new Error("invalid number of arguments"); - } //TODO https support let request = (url.startsWith('https') ? require('https') : require('http')).get(url, function(resp) { if (resp.statusCode === 200) { diff --git a/src/templates/rpcLoadFromBaseURI.js b/src/templates/rpcLoadFromBaseURI.js new file mode 100644 index 0000000..5ce008e --- /dev/null +++ b/src/templates/rpcLoadFromBaseURI.js @@ -0,0 +1,25 @@ +/** + * rpcLoadFromBaseURI(baseURI, fileName, cb) + */ +module.exports = ` + function rpcLoadFromBaseURI(baseURI, fileName, cb) { + var url = new URL(arguments[1], arguments[0]).toString(); + if (typeof cb !== "function") { + throw new Error("last argument should be a function"); + } + //TODO https support + let request = (url.startsWith('https') ? require('https') : require('http')).get(url, function(resp) { + if (resp.statusCode === 200) { + let rawData = ''; + resp.setEncoding('utf8'); + resp.on('data', chunk => { rawData += chunk; }); + resp.on('end', () => { + cb(null, rawData); + }); + } else { + cb(resp); + } + }); + request.on('error', error => cb(error)); + } +`; diff --git a/src/templates/rpcPerform.js b/src/templates/rpcPerform.js new file mode 100644 index 0000000..579d0b7 --- /dev/null +++ b/src/templates/rpcPerform.js @@ -0,0 +1,23 @@ +/** + * rpcPerform(remoteUrl) + */ +module.exports = ` + function rpcPerform(remoteUrl) { + const moduleName = remoteUrl.split("@")[0]; + const scriptUrl = remoteUrl.split("@")[1]; + return new Promise(function (resolve, reject) { + rpcLoad(scriptUrl, function(error, scriptContent) { + if (error) { reject(error); } + //TODO using vm?? + const remote = eval(scriptContent + '\\n try{' + moduleName + '}catch(e) { null; };'); + if (!remote) { + reject("remote library " + moduleName + " is not found at " + scriptUrl); + } else if (remote instanceof Promise) { + return remote; + } else { + resolve(remote); + } + }); + }); + } +`;