diff --git a/lib/APIPlugin.js b/lib/APIPlugin.js index ffc21052c26..f7d8fe07370 100644 --- a/lib/APIPlugin.js +++ b/lib/APIPlugin.js @@ -63,6 +63,12 @@ const REPLACEMENTS = { type: "string", assign: true }, + __webpack_cache_storage__: { + expr: RuntimeGlobals.cacheStorage, + req: [RuntimeGlobals.cacheStorage], + type: "string", + assign: true + }, __webpack_hash__: { expr: `${RuntimeGlobals.getFullHash}()`, req: [RuntimeGlobals.getFullHash], diff --git a/lib/ExternalModule.js b/lib/ExternalModule.js index e6831dbab4e..0e3cb0fb985 100644 --- a/lib/ExternalModule.js +++ b/lib/ExternalModule.js @@ -298,13 +298,25 @@ const getSourceForScriptExternal = (urlAndGlobal, runtimeTemplate) => { url )}, ${runtimeTemplate.basicFunction("event", [ `if(typeof ${globalName} !== "undefined") return resolve();`, - "var errorType = event && (event.type === 'load' ? 'missing' : event.type);", - "var realSrc = event && event.target && event.target.src;", - "__webpack_error__.message = 'Loading script failed.\\n(' + errorType + ': ' + realSrc + ')';", - "__webpack_error__.name = 'ScriptExternalLoadError';", - "__webpack_error__.type = errorType;", - "__webpack_error__.request = realSrc;", - "reject(__webpack_error__);" + `mfCache.match('${url}') + .then((response) => { + var reader = response.body.getReader(); + + reader.read().then((data) => { + new Function(new TextDecoder().decode(data.value).replace('var remote', 'window.remote'))(); + resolve(); + }); + }) + .catch(() => { + "var errorType = event && (event.type === 'load' ? 'missing' : event.type);", + "var realSrc = event && event.target && event.target.src;", + "__webpack_error__.message = 'Loading script failed.\\n(' + errorType + ': ' + realSrc + ')';", + "__webpack_error__.name = 'ScriptExternalLoadError';", + "__webpack_error__.type = errorType;", + "__webpack_error__.request = realSrc;", + "reject(__webpack_error__);" + }); + ` ])}, ${JSON.stringify(globalName)});` ] )}).then(${runtimeTemplate.returningFunction( diff --git a/lib/RuntimeGlobals.js b/lib/RuntimeGlobals.js index 90d16b07632..2fb2d1fc977 100644 --- a/lib/RuntimeGlobals.js +++ b/lib/RuntimeGlobals.js @@ -160,6 +160,11 @@ exports.uncaughtErrorHandler = "__webpack_require__.oe"; */ exports.scriptNonce = "__webpack_require__.nc"; +/** + * property to store cache storage link + */ +exports.cacheStorage = "__webpack_require__.cs"; + /** * function to load a script tag. * Arguments: (url: string, done: (event) => void), key?: string | number, chunkId?: string | number) => void diff --git a/lib/RuntimePlugin.js b/lib/RuntimePlugin.js index 624473d37b5..6441b6dc07b 100644 --- a/lib/RuntimePlugin.js +++ b/lib/RuntimePlugin.js @@ -12,6 +12,7 @@ const JavascriptModulesPlugin = require("./javascript/JavascriptModulesPlugin"); const AsyncModuleRuntimeModule = require("./runtime/AsyncModuleRuntimeModule"); const AutoPublicPathRuntimeModule = require("./runtime/AutoPublicPathRuntimeModule"); const BaseUriRuntimeModule = require("./runtime/BaseUriRuntimeModule"); +const CacheStorageRuntimeModule = require("./runtime/CacheStorageRuntimeModule"); const CompatGetDefaultExportRuntimeModule = require("./runtime/CompatGetDefaultExportRuntimeModule"); const CompatRuntimeModule = require("./runtime/CompatRuntimeModule"); const CreateFakeNamespaceObjectRuntimeModule = require("./runtime/CreateFakeNamespaceObjectRuntimeModule"); @@ -42,6 +43,7 @@ const StringXor = require("./util/StringXor"); const GLOBALS_ON_REQUIRE = [ RuntimeGlobals.chunkName, RuntimeGlobals.runtimeId, + RuntimeGlobals.cacheStorage, RuntimeGlobals.compatGetDefaultExport, RuntimeGlobals.createFakeNamespaceObject, RuntimeGlobals.createScript, @@ -438,6 +440,12 @@ class RuntimePlugin { compilation.addRuntimeModule(chunk, new NonceRuntimeModule()); return true; }); + compilation.hooks.runtimeRequirementInTree + .for(RuntimeGlobals.cacheStorage) + .tap("RuntimePlugin", chunk => { + compilation.addRuntimeModule(chunk, new CacheStorageRuntimeModule()); + return true; + }); // TODO webpack 6: remove CompatRuntimeModule compilation.hooks.additionalTreeRuntimeRequirements.tap( "RuntimePlugin", diff --git a/lib/runtime/CacheStorageRuntimeModule.js b/lib/runtime/CacheStorageRuntimeModule.js new file mode 100644 index 00000000000..df450038f1e --- /dev/null +++ b/lib/runtime/CacheStorageRuntimeModule.js @@ -0,0 +1,37 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Ivan Kopeykin @vankop +*/ + +"use strict"; + +const RuntimeModule = require("../RuntimeModule"); + +class CacheStorageRuntimeModule extends RuntimeModule { + constructor() { + super("cache storage", RuntimeModule.STAGE_ATTACH); + } + + /** + * @returns {string} runtime code + */ + generate() { + return ` + if ('caches' in window) { + caches.open('mf-cache').then((cache) => { + + // TODO: get values from module arguments or global variables + cache.addAll([ + 'http://localhost:5002/remoteEntry.js', + 'http://localhost:5002/vendors-node_modules_react_index_js.js', + 'http://localhost:5002/vendors-node_modules_react-dom_index_js.js', + 'http://localhost:5002/src_Button_tsx.js' + ]); + + // TODO: add mfCache to RuntimeGlobals.cacheStorage (__webpack_require__.cs) + mfCache = cache; + `; + } +} + +module.exports = CacheStorageRuntimeModule; diff --git a/lib/web/JsonpChunkLoadingRuntimeModule.js b/lib/web/JsonpChunkLoadingRuntimeModule.js index ea7bfb4ab4f..8dc64a77216 100644 --- a/lib/web/JsonpChunkLoadingRuntimeModule.js +++ b/lib/web/JsonpChunkLoadingRuntimeModule.js @@ -174,13 +174,28 @@ class JsonpChunkLoadingRuntimeModule extends RuntimeModule { "if(installedChunkData !== 0) installedChunks[chunkId] = undefined;", "if(installedChunkData) {", Template.indent([ - "var errorType = event && (event.type === 'load' ? 'missing' : event.type);", - "var realSrc = event && event.target && event.target.src;", - "error.message = 'Loading chunk ' + chunkId + ' failed.\\n(' + errorType + ': ' + realSrc + ')';", - "error.name = 'ChunkLoadError';", - "error.type = errorType;", - "error.request = realSrc;", - "installedChunkData[1](error);" + ` + mfCache.match(url) + .then((response) => { + var reader = response.body.getReader(); + + reader.read().then((data) => { + new Function(new TextDecoder().decode(data.value))(); + + installedChunkData[0](); + installedChunkData = 0; + }); + }) + .catch(() => { + "var errorType = event && (event.type === 'load' ? 'missing' : event.type);", + "var realSrc = event && event.target && event.target.src;", + "error.message = 'Loading chunk ' + chunkId + ' failed.\\n(' + errorType + ': ' + realSrc + ')';", + "error.name = 'ChunkLoadError';", + "error.type = errorType;", + "error.request = realSrc;", + "installedChunkData[1](error);" + }); + ` ]), "}" ]),