diff --git a/packages/react-scripts/backpack-addons/splitChunks.js b/packages/react-scripts/backpack-addons/splitChunks.js index 22abea25a04..b3d3a9a59ed 100644 --- a/packages/react-scripts/backpack-addons/splitChunks.js +++ b/packages/react-scripts/backpack-addons/splitChunks.js @@ -1,14 +1,8 @@ -'use strict'; - -const paths = require('../config/paths'); -const appPackageJson = require(paths.appPackageJson); -const bpkReactScriptsConfig = appPackageJson['backpack-react-scripts'] || {}; - /** * Defines a webpack splitChunks configuration, optionally based on consumer configuration. - * + * * For automatic configuration set enableAutomaticChunking and optionally provide a vendorsChunkRegex string, e.g: - * + * * // package.json * ... * "backpack-react-scripts": { @@ -18,9 +12,9 @@ const bpkReactScriptsConfig = appPackageJson['backpack-react-scripts'] || {}; * ... * } * ... - * + * * For custom configuration disable enableAutomaticChunking and provide a configuration object, e.g: - * + * * // package.json * ... * "backpack-react-scripts": { @@ -43,7 +37,7 @@ const bpkReactScriptsConfig = appPackageJson['backpack-react-scripts'] || {}; * ... * } * ... - * + * * References: * https://webpack.js.org/plugins/split-chunks-plugin/#optimizationsplitchunks * https://webpack.js.org/plugins/split-chunks-plugin/#splitchunkscachegroups @@ -51,9 +45,14 @@ const bpkReactScriptsConfig = appPackageJson['backpack-react-scripts'] || {}; * https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366 */ -module.exports = (isEnvDevelopment) => { +'use strict'; + +const paths = require('../config/paths'); +const appPackageJson = require(paths.appPackageJson); +const bpkReactScriptsConfig = appPackageJson['backpack-react-scripts'] || {}; - let splitChunksConfig = {} +module.exports = isEnvDevelopment => { + let splitChunksConfig = {}; // If opted in to automatic chunking, apply default configuration if (bpkReactScriptsConfig.enableAutomaticChunking) { @@ -73,16 +72,22 @@ module.exports = (isEnvDevelopment) => { } } // If not opted in to automatic chunking, use custom configuration - if defined. - else if(bpkReactScriptsConfig.splitChunksConfig) { - // - splitChunksConfig = { ...bpkReactScriptsConfig.splitChunksConfig, name: isEnvDevelopment} - // Regexes are passed as strings in package.json config, but need constructed here. - for(let cacheGroup of Object.keys(splitChunksConfig.cacheGroups)){ - splitChunksConfig.cacheGroups[cacheGroup].test = new RegExp(splitChunksConfig.cacheGroups[cacheGroup].test); + else if (bpkReactScriptsConfig.splitChunksConfig) { + splitChunksConfig = { + ...bpkReactScriptsConfig.splitChunksConfig, + name: isEnvDevelopment, + }; + if (splitChunksConfig.cacheGroups) { + // Regexes are passed as strings in package.json config, but need constructed here. + for (let cacheGroup of Object.keys(splitChunksConfig.cacheGroups)) { + splitChunksConfig.cacheGroups[cacheGroup].test = new RegExp( + splitChunksConfig.cacheGroups[cacheGroup].test + ); + } } } return { - splitChunks: splitChunksConfig + splitChunks: splitChunksConfig, }; }; diff --git a/packages/react-scripts/backpack-addons/splitChunks.test.js b/packages/react-scripts/backpack-addons/splitChunks.test.js new file mode 100644 index 00000000000..6d945e98a1a --- /dev/null +++ b/packages/react-scripts/backpack-addons/splitChunks.test.js @@ -0,0 +1,234 @@ +'use strict'; + +jest.mock('../config/paths', () => ({ + appPackageJson: './test/mockPackage.json', +})); + +describe('splitChunks', () => { + const mockData = { + name: 'test', + version: '1.0.0', + 'backpack-react-scripts': {}, + }; + + let isEnvDevelopment = true; + + beforeEach(() => { + jest.resetModules(); + }); + + test('should return default if no config defined', () => { + jest.doMock('./test/mockPackage.json', () => ({ + ...mockData, + 'backpack-react-scripts': {}, + })); + const splitChunks = require('../backpack-addons/splitChunks'); + + let res = splitChunks(isEnvDevelopment); + + expect(res).toEqual({ splitChunks: {} }); + }); + + test('should apply basic defaults if automatic chunking enabled without vendors regex', () => { + jest.doMock('./test/mockPackage.json', () => ({ + ...mockData, + 'backpack-react-scripts': { + enableAutomaticChunking: true, + }, + })); + const splitChunks = require('../backpack-addons/splitChunks'); + + let res = splitChunks(isEnvDevelopment); + + expect(res).toEqual({ + splitChunks: { chunks: 'all', name: true, cacheGroups: {} }, + }); + }); + + test('should return empty if automatic chunking false and no other config is defined', () => { + jest.doMock('./test/mockPackage.json', () => ({ + ...mockData, + 'backpack-react-scripts': { + enableAutomaticChunking: false, + }, + })); + const splitChunks = require('../backpack-addons/splitChunks'); + + let res = splitChunks(isEnvDevelopment); + + expect(res).toEqual({ splitChunks: {} }); + }); + + test('should apply basic defaults and cacheGroup with vendors RegExp when automatic chunking enabled and vendors regex provided', () => { + jest.doMock('./test/mockPackage.json', () => ({ + ...mockData, + 'backpack-react-scripts': { + enableAutomaticChunking: true, + vendorsChunkRegex: '[\\/]node_modules[\\/]', + }, + })); + const splitChunks = require('../backpack-addons/splitChunks'); + + let res = splitChunks(isEnvDevelopment); + + expect(res).toEqual({ + splitChunks: { + chunks: 'all', + name: true, + cacheGroups: { vendors: { test: expect.any(RegExp) } }, + }, + }); + }); + + test('should return empty when automatic chunking disabled and vendors regex provided', () => { + jest.doMock('./test/mockPackage.json', () => ({ + ...mockData, + 'backpack-react-scripts': { + enableAutomaticChunking: false, + vendorsChunkRegex: '[\\/]node_modules[\\/]', + }, + })); + const splitChunks = require('../backpack-addons/splitChunks'); + + let res = splitChunks(isEnvDevelopment); + + expect(res).toEqual({ splitChunks: {} }); + }); + + test('should ignore custom config when automatic chunking enabled and splitChunksConfig is also defined', () => { + jest.doMock('./test/mockPackage.json', () => ({ + ...mockData, + 'backpack-react-scripts': { + enableAutomaticChunking: true, + splitChunksConfig: { + cacheGroups: { + vendors: { + test: '[\\/]node_modules[\\/]', + }, + someCustomChunk: { + test: '[\\/]some_regex[\\/]', + priority: 100, + chunks: 'all', + name: 'someCustomChunk', + }, + }, + }, + }, + })); + const splitChunks = require('../backpack-addons/splitChunks'); + + let res = splitChunks(isEnvDevelopment); + + expect(res).toEqual({ + splitChunks: { chunks: 'all', name: true, cacheGroups: {} }, + }); + }); + + test('should not ignore custom config when automatic chunking disabled and splitChunksConfig is defined', () => { + jest.doMock('./test/mockPackage.json', () => ({ + ...mockData, + 'backpack-react-scripts': { + enableAutomaticChunking: false, + splitChunksConfig: { + chunks: 'all', + cacheGroups: { + vendors: { + test: '[\\/]node_modules[\\/]', + }, + }, + }, + }, + })); + const splitChunks = require('../backpack-addons/splitChunks'); + + let res = splitChunks(isEnvDevelopment); + + expect(res).toEqual({ + splitChunks: { + chunks: 'all', + name: true, + cacheGroups: { + vendors: { + test: expect.any(RegExp), + }, + }, + }, + }); + }); + + test('should apply only the name field when splitChunks is empty', () => { + jest.doMock('./test/mockPackage.json', () => ({ + ...mockData, + 'backpack-react-scripts': { + enableAutomaticChunking: false, + splitChunksConfig: {}, + }, + })); + const splitChunks = require('../backpack-addons/splitChunks'); + + let res = splitChunks(isEnvDevelopment); + + expect(res).toEqual({ splitChunks: { name: true } }); + }); + + test('should apply Regexes when multiple cacheGroups are applied', () => { + jest.doMock('./test/mockPackage.json', () => ({ + ...mockData, + 'backpack-react-scripts': { + enableAutomaticChunking: false, + splitChunksConfig: { + chunks: 'all', + cacheGroups: { + vendors: { + test: '[\\/]node_modules[\\/]', + }, + someCustomChunk: { + test: '[\\/]some_regex[\\/]', + priority: 100, + chunks: 'all', + name: 'someCustomChunk', + }, + }, + }, + }, + })); + const splitChunks = require('../backpack-addons/splitChunks'); + + let res = splitChunks(isEnvDevelopment); + + expect(res).toEqual({ + splitChunks: { + chunks: 'all', + name: true, + cacheGroups: { + vendors: { + test: expect.any(RegExp), + }, + someCustomChunk: { + test: expect.any(RegExp), + priority: 100, + chunks: 'all', + name: 'someCustomChunk', + }, + }, + }, + }); + }); + + test('should apply isEnvDevelopment boolean as name value', () => { + let isEnvDevelopment = false; + jest.doMock('./test/mockPackage.json', () => ({ + ...mockData, + 'backpack-react-scripts': { + enableAutomaticChunking: true, + }, + })); + const splitChunks = require('../backpack-addons/splitChunks'); + + let res = splitChunks(isEnvDevelopment); + + expect(res).toEqual({ + splitChunks: { chunks: 'all', name: false, cacheGroups: {} }, + }); + }); +}); diff --git a/packages/react-scripts/package.json b/packages/react-scripts/package.json index fb019a53ddd..931a086a6d7 100644 --- a/packages/react-scripts/package.json +++ b/packages/react-scripts/package.json @@ -21,6 +21,9 @@ "utils", "backpack-addons" ], + "scripts": { + "test:addons": "jest --testPathPattern=backpack-addons" + }, "bin": { "react-scripts": "./bin/react-scripts.js" },