Merge CRA plugins

This commit is contained in:
Igor Muchychka 2018-12-31 14:21:01 +01:00
parent 4f410d2d60
commit b65ecfc52e
3 changed files with 89 additions and 73 deletions

View File

@ -1,6 +1,56 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`cra-config when used with TypeScript should apply Babel and styling webpack rules 1`] = ` exports[`cra-config when used with react-scripts < 2.1.0 should apply styling webpack rules 1`] = `
Object {
"devtool": "cheap-eval-source-map",
"module": Object {
"noParse": /jquery/,
"rules": Array [
Object {
"include": "app/baseSrc",
"loader": "babel-loader",
"options": Object {},
"test": /\\\\\\.js\\$/,
},
Object {
"exclude": /\\\\\\.module\\\\\\.css\\$/,
"sideEffects": true,
"test": /\\\\\\.css\\$/,
"use": "style-loader",
},
Object {
"test": /\\\\\\.module\\\\\\.css\\$/,
"use": "style-loader",
},
Object {
"exclude": /\\\\\\.module\\\\\\.\\(scss\\|sass\\)\\$/,
"sideEffects": true,
"test": /\\\\\\.\\(scss\\|sass\\)\\$/,
"use": "sass-loader",
},
Object {
"test": /\\\\\\.module\\\\\\.\\(scss\\|sass\\)\\$/,
"use": "sass-loader",
},
],
},
"plugins": Array [
BaseTestPlugin1 {},
BaseTestPlugin2 {},
],
"resolve": Object {
"alias": Object {
"baseAlias": "base-alias",
},
"extensions": Array [
".js",
".jsx",
],
},
}
`;
exports[`cra-config when used with react-scripts >= 2.1.0 should apply Babel, styling rules and merge plugins 1`] = `
Object { Object {
"devtool": "cheap-eval-source-map", "devtool": "cheap-eval-source-map",
"module": Object { "module": Object {
@ -46,6 +96,8 @@ Object {
"plugins": Array [ "plugins": Array [
BaseTestPlugin1 {}, BaseTestPlugin1 {},
BaseTestPlugin2 {}, BaseTestPlugin2 {},
CRATestPlugin1 {},
CRATestPlugin2 {},
], ],
"resolve": Object { "resolve": Object {
"alias": Object { "alias": Object {
@ -60,53 +112,3 @@ Object {
}, },
} }
`; `;
exports[`cra-config when used without TypeScript should apply styling webpack rules 1`] = `
Object {
"devtool": "cheap-eval-source-map",
"module": Object {
"noParse": /jquery/,
"rules": Array [
Object {
"include": "app/baseSrc",
"loader": "babel-loader",
"options": Object {},
"test": /\\\\\\.js\\$/,
},
Object {
"exclude": /\\\\\\.module\\\\\\.css\\$/,
"sideEffects": true,
"test": /\\\\\\.css\\$/,
"use": "style-loader",
},
Object {
"test": /\\\\\\.module\\\\\\.css\\$/,
"use": "style-loader",
},
Object {
"exclude": /\\\\\\.module\\\\\\.\\(scss\\|sass\\)\\$/,
"sideEffects": true,
"test": /\\\\\\.\\(scss\\|sass\\)\\$/,
"use": "sass-loader",
},
Object {
"test": /\\\\\\.module\\\\\\.\\(scss\\|sass\\)\\$/,
"use": "sass-loader",
},
],
},
"plugins": Array [
BaseTestPlugin1 {},
BaseTestPlugin2 {},
],
"resolve": Object {
"alias": Object {
"baseAlias": "base-alias",
},
"extensions": Array [
".js",
".jsx",
],
},
}
`;

View File

@ -78,6 +78,17 @@ export const getTypeScriptRules = (webpackConfigRules, configDir) => {
]; ];
}; };
function mergePlugins(basePlugins, additionalPlugins) {
return [...basePlugins, ...additionalPlugins].reduce((plugins, plugin) => {
if (
plugins.some(includedPlugin => includedPlugin.constructor.name === plugin.constructor.name)
) {
return plugins;
}
return [...plugins, plugin];
}, []);
}
export function getCraWebpackConfig(mode) { export function getCraWebpackConfig(mode) {
const pathToReactScripts = getReactScriptsPath(); const pathToReactScripts = getReactScriptsPath();
@ -132,7 +143,7 @@ export function applyCRAWebpackConfig(baseConfig, configDir) {
...baseConfig.module, ...baseConfig.module,
rules: [...filteredBaseRules, ...craStyleRules, ...craTypeScriptRules], rules: [...filteredBaseRules, ...craStyleRules, ...craTypeScriptRules],
}, },
plugins, plugins: mergePlugins(baseConfig.plugins, hasTsSupport ? craWebpackConfig.plugins : []),
resolve: { resolve: {
...baseConfig.resolve, ...baseConfig.resolve,
extensions: [...baseConfig.resolve.extensions, ...tsExtensions], extensions: [...baseConfig.resolve.extensions, ...tsExtensions],

View File

@ -14,6 +14,7 @@ const SCRIPT_PATH = '.bin/react-scripts';
describe('cra-config', () => { describe('cra-config', () => {
beforeEach(() => { beforeEach(() => {
fs.realpathSync.mockReset();
fs.realpathSync.mockImplementationOnce(() => '/test-project'); fs.realpathSync.mockImplementationOnce(() => '/test-project');
}); });
@ -45,27 +46,7 @@ describe('cra-config', () => {
}); });
}); });
describe('when used without TypeScript', () => {
beforeEach(() => {
fs.realpathSync.mockImplementationOnce(() =>
path.join(__dirname, '__mocks__/react-scripts-2-0-0/sub1/sub2')
);
getReactScriptsPath({ noCache: true });
});
it('should apply styling webpack rules', () => {
expect(applyCRAWebpackConfig(mockConfig, '/test-project')).toMatchSnapshot();
});
});
describe('when used with TypeScript', () => { describe('when used with TypeScript', () => {
beforeEach(() => {
fs.realpathSync.mockImplementationOnce(() =>
path.join(__dirname, '__mocks__/react-scripts-2-1-0/sub1/sub2')
);
getReactScriptsPath({ noCache: true });
});
it('should return the correct config', () => { it('should return the correct config', () => {
// Normalise the return, as we know our new rules object will be an array, whereas a string is expected. // Normalise the return, as we know our new rules object will be an array, whereas a string is expected.
const rules = getTypeScriptRules(mockRules, './.storybook'); const rules = getTypeScriptRules(mockRules, './.storybook');
@ -78,8 +59,30 @@ describe('cra-config', () => {
const rules = getTypeScriptRules(mockRules, './.storybook'); const rules = getTypeScriptRules(mockRules, './.storybook');
expect(rules[0].include.findIndex(string => string.includes('.storybook'))).toEqual(1); expect(rules[0].include.findIndex(string => string.includes('.storybook'))).toEqual(1);
}); });
});
it('should apply Babel and styling webpack rules', () => { describe('when used with react-scripts < 2.1.0', () => {
beforeEach(() => {
fs.realpathSync.mockImplementationOnce(() =>
path.join(__dirname, '__mocks__/react-scripts-2-0-0/sub1/sub2')
);
getReactScriptsPath({ noCache: true });
});
it('should apply styling webpack rules', () => {
expect(applyCRAWebpackConfig(mockConfig, '/test-project')).toMatchSnapshot();
});
});
describe('when used with react-scripts >= 2.1.0', () => {
beforeEach(() => {
fs.realpathSync.mockImplementationOnce(() =>
path.join(__dirname, '__mocks__/react-scripts-2-1-0/sub1/sub2')
);
getReactScriptsPath({ noCache: true });
});
it('should apply Babel, styling rules and merge plugins', () => {
expect(applyCRAWebpackConfig(mockConfig, '/test-project')).toMatchSnapshot(); expect(applyCRAWebpackConfig(mockConfig, '/test-project')).toMatchSnapshot();
}); });
}); });