diff --git a/packages/holocron/__tests__/loadModule.node.spec.js b/packages/holocron/__tests__/loadModule.node.spec.js index 4597f2f..c886dec 100644 --- a/packages/holocron/__tests__/loadModule.node.spec.js +++ b/packages/holocron/__tests__/loadModule.node.spec.js @@ -92,8 +92,8 @@ describe('loadModule.node', () => { beforeAll(() => { jest.spyOn(console, 'log'); jest.spyOn(console, 'warn'); - console.log.mockImplementation(() => { }); - console.warn.mockImplementation(() => { }); + console.log.mockImplementation(() => {}); + console.warn.mockImplementation(() => {}); }); beforeEach(() => { @@ -788,14 +788,13 @@ describe('loadModule.node', () => { environmentVariables: [{ name: 'COOL_API_URL', validate: jest.fn() }], }; const moduleString = { onModuleLoadConfig }; - + // mock fetching module-config.json mockFetch.mockImplementationOnce(() => Promise.resolve({ status: 200, statusText: 'OK', - json: () => '{ "requiredExternals": [] }', + json: () => '{ "requiredExternals": {} }', ok: true, - }) - ); + })); mockFetch.mockImplementationOnce( makeFetchMock({ fetchText: moduleString }) @@ -834,7 +833,7 @@ describe('loadModule.node', () => { environmentVariables: [{ name: 'COOL_API_URL', validate: jest.fn() }], }; const moduleString = { onModuleLoadConfig }; - + // mock fetching module-config.json mockFetch.mockImplementationOnce(() => Promise.resolve({ status: 200, statusText: 'OK', @@ -843,20 +842,21 @@ describe('loadModule.node', () => { { name: 'lodash', version: '1.0.0', + browserIntegrity: '123-browser', + nodeIntegrity: '123-node', }, ], }), ok: true, - }) - ); + })); mockFetch.mockImplementationOnce(() => Promise.resolve({ status: 200, statusText: 'OK', text: () => 'external fallback code', ok: true, - }) - ); + })); + mockFetch.mockImplementationOnce( makeFetchMock({ fetchText: moduleString }) ); @@ -921,8 +921,7 @@ describe('loadModule.node', () => { }, }), ok: true, - }) - ); + })); mockFetch.mockImplementationOnce( makeFetchMock({ fetchText: moduleString }) ); @@ -972,8 +971,7 @@ describe('loadModule.node', () => { }, }), ok: true, - }) - ); + })); mockFetch.mockImplementationOnce( makeFetchMock({ fetchText: moduleString }) ); @@ -1028,8 +1026,7 @@ describe('loadModule.node', () => { }, }), ok: true, - }) - ); + })); mockFetch.mockImplementationOnce( makeFetchMock({ fetchText: moduleString }) ); @@ -1070,14 +1067,14 @@ describe('loadModule.node', () => { requiredExternals: { 'my-dep': { name: 'my-dep', - integrity: '1234', + browserIntegrity: '1234-browser', + nodeIntegrity: '1234-node', version: '1.0.1', semanticRange: '^1.0.0', }, }, }), - }) - ); + })); // load module const loadModule = load({ @@ -1108,7 +1105,8 @@ describe('loadModule.node', () => { 'my-module': { 'my-dep': { name: 'my-dep', - integrity: '1234', + browserIntegrity: '1234-browser', + nodeIntegrity: '1234-node', version: '1.0.1', semanticRange: '^1.0.0', }, @@ -1125,22 +1123,21 @@ describe('loadModule.node', () => { requiredExternals: { myDep: { name: 'my-dep', - integrity: '1234', + browserIntegrity: '1234-browser', + nodeIntegrity: '1234-node', version: '1.0.1', semanticRange: '^1.0.0', }, }, }), ok: true, - }) - ); + })); mockFetch.mockImplementation(() => Promise.resolve({ ok: true, status: 200, text: () => JSON.stringify({}), - }) - ); + })); const loadModule = load({ fetch: mockFetch, @@ -1197,7 +1194,8 @@ describe('loadModule.node', () => { semanticRange: '^1.0.0', name: 'lodash', version: '1.2.3', - integrity: '12345', + browserIntegrity: '1234-browser', + nodeIntegrity: '1234-node', }, }, }), @@ -1209,8 +1207,7 @@ describe('loadModule.node', () => { statusText: 'OK', text: () => 'external fallback code', ok: true, - }) - ); + })); // mock fetch for module code mockFetch.mockImplementationOnce( @@ -1245,8 +1242,9 @@ describe('loadModule.node', () => { Object { "awesome": Object { "lodash": Object { - "integrity": "12345", + "browserIntegrity": "1234-browser", "name": "lodash", + "nodeIntegrity": "1234-node", "semanticRange": "^1.0.0", "version": "1.2.3", }, @@ -1280,7 +1278,8 @@ describe('loadModule.node', () => { mockFetch.mockImplementationOnce( makeFetchMock({ fetchText: fakeModule, - })); + }) + ); const loadModule = load({ fetch: mockFetch, @@ -1294,7 +1293,7 @@ describe('loadModule.node', () => { }, }) ).rejects.toThrowErrorMatchingInlineSnapshot( - '"External \'example-dep\' is required by awesome, but is not provided by the root module"' + "\"External 'example-dep' is required by awesome, but is not provided by the root module\"" ); }); @@ -1305,7 +1304,8 @@ describe('loadModule.node', () => { // does not have moduleConfig file. mockFetch.mockImplementationOnce(() => Promise.resolve({ status: 404, - })); + }) + ); // mock fetch for module mockFetch.mockImplementationOnce( @@ -1343,7 +1343,8 @@ describe('loadModule.node', () => { // does not have moduleConfig file. mockFetch.mockImplementationOnce(() => Promise.resolve({ status: 404, - })); + }) + ); // mock fetch for module mockFetch.mockImplementationOnce( @@ -1388,7 +1389,8 @@ describe('loadModule.node', () => { // does not have moduleConfig file. mockFetch.mockImplementationOnce(() => Promise.resolve({ status: 404, - })); + }) + ); // mock fetch for module mockFetch.mockImplementationOnce( @@ -1435,7 +1437,8 @@ describe('loadModule.node', () => { // does not have moduleConfig file. mockFetch.mockImplementationOnce(() => Promise.resolve({ status: 404, - })); + }) + ); // mock fetch for module mockFetch.mockImplementationOnce( @@ -1476,7 +1479,8 @@ describe('loadModule.node', () => { // does not have moduleConfig file. mockFetch.mockImplementationOnce(() => Promise.resolve({ status: 404, - })); + }) + ); // mock fetch for module mockFetch.mockImplementationOnce( diff --git a/packages/holocron/src/externalRegistry.js b/packages/holocron/src/externalRegistry.js index a45f7fb..71ffa24 100644 --- a/packages/holocron/src/externalRegistry.js +++ b/packages/holocron/src/externalRegistry.js @@ -39,7 +39,8 @@ let registeredExternals = iMap(); * name: {string}[name of external], * version: {string}[version of external fallback], * semanticRange: {string}[range of expected external], - * integrity: {string}[hash value of module code] + * browserIntegrity: {string}[hash value of external fallback browser code] + * nodeIntegrity: {string}[hash value of external fallback server code] * } * } * } @@ -47,7 +48,10 @@ let registeredExternals = iMap(); * @param {string} registry.[moduleName].[externalName].name external name * @param {string} registry.[moduleName].[externalName].version external version * @param {string} registry.[moduleName].[externalName].semanticRange accepted semantic range - * @param {string} registry.[moduleName].[externalName].integrity hash value of fallback external + * @param {string} registry.[moduleName].[externalName].browserIntegrity hash value of + * fallback external browser code + * @param {string} registry.[moduleName].[externalName].nodeIntegrity hash value of + * fallback external server code */ let requiredModuleExternals = iMap(); @@ -115,8 +119,11 @@ function clearModulesRequiredExternals(moduleName) { * @param {string} externals.[externalName].name external name * @param {string} externals.[externalName].version external version * @param {string} externals.[externalName].semanticRange semantic range module will accept - * @param {string} externals.[externalName].integrity hash value of fallback external - */ + * @param {string} externals.[externalName].nodeIntegrity hash value of + * fallback external browser code + * @param {string} externals.[externalName].browserIntegrity hash value of + * fallback external server code +*/ function setModulesRequiredExternals({ moduleName, externals }) { if (externals) { requiredModuleExternals = requiredModuleExternals.set(moduleName, fromJS(externals)); diff --git a/packages/holocron/src/loadModule.node.js b/packages/holocron/src/loadModule.node.js index 285858f..b0c59f4 100644 --- a/packages/holocron/src/loadModule.node.js +++ b/packages/holocron/src/loadModule.node.js @@ -98,7 +98,7 @@ const fetchNodeModule = async (url, integrity, context) => { try { const moduleString = await fetchAsset(url); - if (process.env.NODE_ENV === 'production') { + if (process.env.NODE_ENV !== 'development') { const actualSRI = ssri.fromData( moduleString, { algorithms: ['sha256', 'sha384'] } @@ -125,7 +125,7 @@ const fetchNodeModule = async (url, integrity, context) => { }; /** - * Loads Fallback Externals for a module + * Loads Fallback Externals server bundle for a module * @param {string} baseUrl path to the assets * @param {string} moduleName module name */ @@ -133,8 +133,8 @@ const loadModuleFallbackExternals = async (baseUrl, moduleName) => { const fallbacks = getUnregisteredRequiredExternals(moduleName); await Promise.all( - fallbacks.map(async ({ name, version, integrity }) => { - const fallbackDependency = await fetchNodeModule(`${baseUrl}${name}.node.js`, integrity, { + fallbacks.map(async ({ name, version, nodeIntegrity }) => { + const fallbackDependency = await fetchNodeModule(`${baseUrl}${name}.node.js`, nodeIntegrity, { type: 'External Fallback', name, }); @@ -212,9 +212,9 @@ const validateRequiredExternals = ({ const providedExternal = providedExternals[externalName]; const requiredExternal = requiredExternals[externalName]; const { - version, name, integrity, semanticRange, + version, name, nodeIntegrity, browserIntegrity, semanticRange, } = requiredExternal; - const fallbackExternalAvailable = !!name && !!version; + const fallbackExternalAvailable = !!name && !!version && !!nodeIntegrity && !!browserIntegrity; const fallbackBlockedByRootModule = !!providedExternal && !providedExternal.fallbackEnabled; if (!providedExternal) { @@ -242,7 +242,8 @@ const validateRequiredExternals = ({ name, version, semanticRange, - integrity, + nodeIntegrity, + browserIntegrity, }; } }); @@ -296,7 +297,7 @@ const loadModule = async ( // root modules can be built without getTenantRootModule const rootModule = global.getTenantRootModule ? global.getTenantRootModule() : null; - // if no root module, module being loaded should be root. + // if no root module, module being loaded should be rootModule if (rootModule) { const { providedExternals: rootProvidedExternals, diff --git a/packages/holocron/src/loadModule.web.js b/packages/holocron/src/loadModule.web.js index c0bc2ed..072698f 100644 --- a/packages/holocron/src/loadModule.web.js +++ b/packages/holocron/src/loadModule.web.js @@ -57,9 +57,9 @@ function loadModuleFallbackExternals(moduleName) { const fallbacks = getUnregisteredRequiredExternals(moduleName); const baseUrl = getModuleMap().getIn(['modules', moduleName, 'baseUrl']); - return Promise.all(fallbacks.map(({ name, integrity }) => createScript({ + return Promise.all(fallbacks.map(({ name, browserIntegrity }) => createScript({ url: `${baseUrl}${name}.browser.js`, - integrity, + integrity: browserIntegrity, }))); }