From 1fd4e1c38efd50fd287dc6686e9511e952f0112a Mon Sep 17 00:00:00 2001 From: Pavel Strunkin Date: Mon, 24 May 2021 11:00:43 +0300 Subject: [PATCH] feat: react-scripts. allow parametrise webpack config path --- .../findReactScriptsWebpackConfig.js | 84 +------------------ npm/react/plugins/react-scripts/index.js | 16 +++- npm/react/plugins/utils/eslint-helpers.js | 43 ++++++++++ ...d-image-redirect.js => webpack-helpers.js} | 40 ++++++++- 4 files changed, 100 insertions(+), 83 deletions(-) create mode 100644 npm/react/plugins/utils/eslint-helpers.js rename npm/react/plugins/utils/{add-image-redirect.js => webpack-helpers.js} (62%) diff --git a/npm/react/plugins/react-scripts/findReactScriptsWebpackConfig.js b/npm/react/plugins/react-scripts/findReactScriptsWebpackConfig.js index 3dacde36e10a..dc41049ea4da 100644 --- a/npm/react/plugins/react-scripts/findReactScriptsWebpackConfig.js +++ b/npm/react/plugins/react-scripts/findReactScriptsWebpackConfig.js @@ -1,93 +1,17 @@ // @ts-check const debug = require('debug')('@cypress/react') const tryLoadWebpackConfig = require('../utils/tryLoadWebpackConfig') +const { allowModuleSourceInPlace } = require('../utils/webpack-helpers') +const { addCypressToWebpackEslintRulesInPlace } = require('../utils/eslint-helpers') const { getTranspileFolders } = require('../utils/get-transpile-folders') const { addFolderToBabelLoaderTranspileInPlace } = require('../utils/babel-helpers') -/** - * Finds the ModuleScopePlugin plugin and adds given folder - * to that list. This allows react-scripts to import folders - * outside of the default "/src" folder. - * WARNING modifies the input webpack options argument. - * @see https://github.com/bahmutov/cypress-react-unit-test/issues/289 - * @param {string} folderName Folder to add, should be absolute - */ -function allowModuleSourceInPlace (folderName, webpackOptions) { - if (!folderName) { - return - } - - if (!webpackOptions.resolve) { - return - } - - if (!Array.isArray(webpackOptions.resolve.plugins)) { - return - } - - const moduleSourcePlugin = webpackOptions.resolve.plugins.find((plugin) => { - return Array.isArray(plugin.appSrcs) - }) - - if (!moduleSourcePlugin) { - debug('cannot find module source plugin') - - return - } - - debug('found module source plugin %o', moduleSourcePlugin) - if (!moduleSourcePlugin.appSrcs.includes(folderName)) { - moduleSourcePlugin.appSrcs.push(folderName) - debug('added folder %s to allowed sources', folderName) - } -} - -const addCypressToWebpackEslintRulesInPlace = (webpackOptions) => { - const globalsToAdd = ['cy', 'Cypress', 'before', 'after', 'context'] - - if (webpackOptions.module && Array.isArray(webpackOptions.module.rules)) { - const modulePre = webpackOptions.module.rules.find( - (rule) => rule.enforce === 'pre', - ) - - if (modulePre && Array.isArray(modulePre.use)) { - debug('found Pre block %o', modulePre) - - const useEslintLoader = modulePre.use.find( - (use) => use.loader && use.loader.includes('eslint-loader'), - ) - - if (useEslintLoader) { - debug('found useEslintLoader %o', useEslintLoader) - - if (useEslintLoader.options) { - if (Array.isArray(useEslintLoader.options.globals)) { - debug( - 'adding cy to existing globals %o', - useEslintLoader.options.globals, - ) - - useEslintLoader.options.globals.push(...globalsToAdd) - } else { - debug('setting new list of globals with cy and Cypress') - useEslintLoader.options.globals = globalsToAdd - } - - debug('updated globals %o', useEslintLoader.options.globals) - } else { - debug('eslint loader does not have options ⚠️') - } - } - } - } -} - -module.exports = function findReactScriptsWebpackConfig (config) { +module.exports = function findReactScriptsWebpackConfig (config, { webpackConfigPath }) { // this is required because // 1) we use our own HMR and we don't need react-refresh transpiling overhead // 2) it doesn't work with process.env=test @see https://github.com/cypress-io/cypress-realworld-app/pull/832 process.env.FAST_REFRESH = 'false' - const webpackConfig = tryLoadWebpackConfig('react-scripts/config/webpack.config') + const webpackConfig = tryLoadWebpackConfig(webpackConfigPath) if (!webpackConfig) { throw new Error('⚠️ Could not find Webpack options for react-scripts. Make sure that you have react-scripts module available.') diff --git a/npm/react/plugins/react-scripts/index.js b/npm/react/plugins/react-scripts/index.js index 0e6974e21943..f986ebff9ad7 100644 --- a/npm/react/plugins/react-scripts/index.js +++ b/npm/react/plugins/react-scripts/index.js @@ -1,9 +1,21 @@ const { startDevServer } = require('@cypress/webpack-dev-server') const findReactScriptsWebpackConfig = require('./findReactScriptsWebpackConfig') -module.exports = (on, config) => { +module.exports = ( + on, + config, { + webpackConfigPath, + } = { + webpackConfigPath: 'react-scripts/config/webpack.config', + }, +) => { on('dev-server:start', async (options) => { - return startDevServer({ options, webpackConfig: findReactScriptsWebpackConfig(config) }) + return startDevServer({ + options, + webpackConfig: findReactScriptsWebpackConfig(config, { + webpackConfigPath, + }), + }) }) config.env.reactDevtools = true diff --git a/npm/react/plugins/utils/eslint-helpers.js b/npm/react/plugins/utils/eslint-helpers.js new file mode 100644 index 000000000000..1eda1f95502b --- /dev/null +++ b/npm/react/plugins/utils/eslint-helpers.js @@ -0,0 +1,43 @@ +const debug = require('debug')('@cypress/react') + +const addCypressToWebpackEslintRulesInPlace = (webpackOptions) => { + const globalsToAdd = ['cy', 'Cypress', 'before', 'after', 'context'] + + if (webpackOptions.module && Array.isArray(webpackOptions.module.rules)) { + const modulePre = webpackOptions.module.rules.find( + (rule) => rule.enforce === 'pre', + ) + + if (modulePre && Array.isArray(modulePre.use)) { + debug('found Pre block %o', modulePre) + + const useEslintLoader = modulePre.use.find( + (use) => use.loader && use.loader.includes('eslint-loader'), + ) + + if (useEslintLoader) { + debug('found useEslintLoader %o', useEslintLoader) + + if (useEslintLoader.options) { + if (Array.isArray(useEslintLoader.options.globals)) { + debug( + 'adding cy to existing globals %o', + useEslintLoader.options.globals, + ) + + useEslintLoader.options.globals.push(...globalsToAdd) + } else { + debug('setting new list of globals with cy and Cypress') + useEslintLoader.options.globals = globalsToAdd + } + + debug('updated globals %o', useEslintLoader.options.globals) + } else { + debug('eslint loader does not have options ⚠️') + } + } + } + } +} + +module.exports = { addCypressToWebpackEslintRulesInPlace } diff --git a/npm/react/plugins/utils/add-image-redirect.js b/npm/react/plugins/utils/webpack-helpers.js similarity index 62% rename from npm/react/plugins/utils/add-image-redirect.js rename to npm/react/plugins/utils/webpack-helpers.js index 4c4ba13d3b4e..2b1ba4430c38 100644 --- a/npm/react/plugins/utils/add-image-redirect.js +++ b/npm/react/plugins/utils/webpack-helpers.js @@ -59,4 +59,42 @@ function addImageRedirect (webpackOptions) { } } -module.exports = { addImageRedirect } +/** + * Finds the ModuleScopePlugin plugin and adds given folder + * to that list. This allows react-scripts to import folders + * outside of the default "/src" folder. + * WARNING modifies the input webpack options argument. + * @see https://github.com/bahmutov/cypress-react-unit-test/issues/289 + * @param {string} folderName Folder to add, should be absolute + */ +function allowModuleSourceInPlace (folderName, webpackOptions) { + if (!folderName) { + return + } + + if (!webpackOptions.resolve) { + return + } + + if (!Array.isArray(webpackOptions.resolve.plugins)) { + return + } + + const moduleSourcePlugin = webpackOptions.resolve.plugins.find((plugin) => { + return Array.isArray(plugin.appSrcs) + }) + + if (!moduleSourcePlugin) { + debug('cannot find module source plugin') + + return + } + + debug('found module source plugin %o', moduleSourcePlugin) + if (!moduleSourcePlugin.appSrcs.includes(folderName)) { + moduleSourcePlugin.appSrcs.push(folderName) + debug('added folder %s to allowed sources', folderName) + } +} + +module.exports = { addImageRedirect, allowModuleSourceInPlace }