diff --git a/__tests__/server/utils/watchLocalModules.spec.js b/__tests__/server/utils/watchLocalModules.spec.js index f34bcd0de..2a3656cf8 100644 --- a/__tests__/server/utils/watchLocalModules.spec.js +++ b/__tests__/server/utils/watchLocalModules.spec.js @@ -66,6 +66,7 @@ jest.mock('fs', () => { readFileSync: jest.fn(actual.readFileSync), }; }); +jest.spyOn(console, 'error').mockImplementation(() => {}); describe('watchLocalModules', () => { beforeEach(() => jest.clearAllMocks()); @@ -123,6 +124,49 @@ describe('watchLocalModules', () => { expect(getModules().get(moduleName)).toBe(updatedModule); }); + it('handles a rejection properly', async () => { + const moduleName = 'some-module'; + const moduleVersion = '1.0.1'; + const moduleMapSample = { + modules: { + [moduleName]: { + node: { + integrity: '133', + url: `https://example.com/cdn/${moduleName}/${moduleVersion}/${moduleName}-node.js`, + }, + browser: { + integrity: '234', + url: `https://example.com/cdn/${moduleName}/${moduleVersion}/${moduleName}-browser.js`, + }, + legacyBrowser: { + integrity: '134633', + url: `https://example.com/cdn/${moduleName}/${moduleVersion}/${moduleName}-legacy.browser.js`, + }, + }, + }, + }; + fs.readFileSync.mockImplementationOnce(() => JSON.stringify(moduleMapSample)); + const modulePath = path.resolve(__dirname, `../../../static/modules/${moduleName}/${moduleVersion}/${moduleName}.node.js`); + const originalModule = () => null; + const updatedModule = () => null; + const modules = fromJS({ [moduleName]: originalModule }); + const moduleMap = fromJS(moduleMapSample); + resetModuleRegistry(modules, moduleMap); + watchLocalModules(); + const changeListener = chokidar.getListeners().change; + expect(getModules().get(moduleName)).toBe(originalModule); + loadModule.mockReturnValueOnce(Promise.reject(updatedModule)); + await changeListener(modulePath); + expect(loadModule).toHaveBeenCalledWith( + moduleName, + moduleMapSample.modules[moduleName], + require('../../../src/server/utils/onModuleLoad').default + ); + expect(getModules().get(moduleName)).toBe(originalModule); + expect(console.error).toHaveBeenCalledTimes(1); + expect(console.error).toHaveBeenCalledWith(updatedModule); + }); + it('should ignore when the regex doesn\'t match', async () => { const changedPath = path.resolve(__dirname, '../../../static/modules/dont-match-me-bro.node.js'); watchLocalModules(); diff --git a/package-lock.json b/package-lock.json index 56a14d132..5e8c5f74b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7112,9 +7112,9 @@ "integrity": "sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ=" }, "bl": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.2.tgz", - "integrity": "sha512-j4OH8f6Qg2bGuWfRiltT2HYGx0e1QcBTrK9KAHNMwMZdQnDZFk0ZSYIpADjYCB3U12nicC5tVJwSIhwOWjb4RQ==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.3.tgz", + "integrity": "sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg==", "dev": true, "requires": { "buffer": "^5.5.0", @@ -10135,11 +10135,11 @@ } }, "cross-fetch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.0.5.tgz", - "integrity": "sha512-FFLcLtraisj5eteosnX1gf01qYDCOc4fDy0+euOt8Kn9YBY2NtXL/pCoYPavw24NIQkQqm5ZOLsGD5Zzj0gyew==", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.0.6.tgz", + "integrity": "sha512-KBPUbqgFjzWlVcURG+Svp9TlhA5uliYtiNx/0r8nv0pdypeQCRJ9IaSIc3q/x3q8t3F75cHuwxVql1HFGHCNJQ==", "requires": { - "node-fetch": "2.6.0" + "node-fetch": "2.6.1" } }, "cross-spawn": { @@ -13830,9 +13830,9 @@ } }, "holocron": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/holocron/-/holocron-1.1.0.tgz", - "integrity": "sha512-BZntRbr7kZ8TTQLMdumlZMCP+BRiL+8mDVl6p53mfYh00IoLRXrI9jYgoeLmvYGCpZxLSL13+xUoVcp4ACk8CQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/holocron/-/holocron-1.1.1.tgz", + "integrity": "sha512-7jZRoHrCjHjsu5GMIDvgfW2qaU8C/6Cey6WSIhwQvh3taAbMbXThiA/i4GAQ6LIrxRnWShM+C2u7nWgBub0nYg==", "requires": { "@americanexpress/vitruvius": "^2.0.0", "hoist-non-react-statics": "^3.3.0", @@ -19794,9 +19794,9 @@ } }, "node-fetch": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", - "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" }, "node-int64": { "version": "0.4.0", diff --git a/package.json b/package.json index 222705ea1..beeedf02d 100644 --- a/package.json +++ b/package.json @@ -91,10 +91,10 @@ "core-js": "^3.6.5", "cors": "^2.8.5", "create-shared-react-context": "^1.0.3", - "cross-fetch": "^3.0.5", + "cross-fetch": "^3.0.6", "express": "^4.17.1", "helmet": "^3.22.0", - "holocron": "^1.1.0", + "holocron": "^1.1.1", "holocron-module-route": "^1.1.0", "if-env": "^1.0.4", "immutable": "^4.0.0-rc.12", diff --git a/src/server/utils/watchLocalModules.js b/src/server/utils/watchLocalModules.js index 64eb9ce32..2ec79b63a 100644 --- a/src/server/utils/watchLocalModules.js +++ b/src/server/utils/watchLocalModules.js @@ -39,28 +39,32 @@ export default function watchLocalModules() { const watcher = chokidar.watch(moduleDirectory, { awaitWriteFinish: true }); watcher.on('change', async (changedPath) => { - if (!changedPath.endsWith('.node.js')) return; + try { + if (!changedPath.endsWith('.node.js')) return; - const match = changedPath.substring(moduleDirectory.length).match(/\/([^/]+)\/([^/]+)/); - if (!match) return; - const [, moduleNameChangeDetectedIn] = match; + const match = changedPath.substring(moduleDirectory.length).match(/\/([^/]+)\/([^/]+)/); + if (!match) return; + const [, moduleNameChangeDetectedIn] = match; - const moduleMap = JSON.parse(fs.readFileSync(moduleMapPath, 'utf8')); + const moduleMap = JSON.parse(fs.readFileSync(moduleMapPath, 'utf8')); - const moduleData = moduleMap.modules[moduleNameChangeDetectedIn]; - const oneAppDevCdnAddress = `http://${ip}:${process.env.HTTP_ONE_APP_DEV_CDN_PORT || 3001}`; + const moduleData = moduleMap.modules[moduleNameChangeDetectedIn]; + const oneAppDevCdnAddress = `http://${ip}:${process.env.HTTP_ONE_APP_DEV_CDN_PORT || 3001}`; - moduleData.browser.url = moduleData.browser.url.replace('[one-app-dev-cdn-url]', oneAppDevCdnAddress); - moduleData.legacyBrowser.url = moduleData.legacyBrowser.url.replace('[one-app-dev-cdn-url]', oneAppDevCdnAddress); - moduleData.node.url = moduleData.node.url.replace('[one-app-dev-cdn-url]', oneAppDevCdnAddress); + moduleData.browser.url = moduleData.browser.url.replace('[one-app-dev-cdn-url]', oneAppDevCdnAddress); + moduleData.legacyBrowser.url = moduleData.legacyBrowser.url.replace('[one-app-dev-cdn-url]', oneAppDevCdnAddress); + moduleData.node.url = moduleData.node.url.replace('[one-app-dev-cdn-url]', oneAppDevCdnAddress); - const module = addHigherOrderComponent(await loadModule( - moduleNameChangeDetectedIn, - moduleData, - onModuleLoad - )); + const module = addHigherOrderComponent(await loadModule( + moduleNameChangeDetectedIn, + moduleData, + onModuleLoad + )); - const modules = getModules().set(moduleNameChangeDetectedIn, module); - resetModuleRegistry(modules, getModuleMap()); + const modules = getModules().set(moduleNameChangeDetectedIn, module); + resetModuleRegistry(modules, getModuleMap()); + } catch (error) { + console.error(error); + } }); }