Skip to content

Commit

Permalink
feat: react-scripts. allow parametrise webpack config path
Browse files Browse the repository at this point in the history
  • Loading branch information
pashidlos committed May 25, 2021
1 parent 63a9bf9 commit 1fd4e1c
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 83 deletions.
84 changes: 4 additions & 80 deletions npm/react/plugins/react-scripts/findReactScriptsWebpackConfig.js
Original file line number Diff line number Diff line change
@@ -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.')
Expand Down
16 changes: 14 additions & 2 deletions npm/react/plugins/react-scripts/index.js
Original file line number Diff line number Diff line change
@@ -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
Expand Down
43 changes: 43 additions & 0 deletions npm/react/plugins/utils/eslint-helpers.js
Original file line number Diff line number Diff line change
@@ -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 }
Original file line number Diff line number Diff line change
Expand Up @@ -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 }

0 comments on commit 1fd4e1c

Please sign in to comment.