Skip to content

Commit

Permalink
Merge pull request #196 from spautz/issue/190
Browse files Browse the repository at this point in the history
Support async configs for scripts (fix #190)
  • Loading branch information
patricklafrance authored Sep 27, 2020
2 parents b1cfb67 + 1a5fade commit e4ac761
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 66 deletions.
14 changes: 14 additions & 0 deletions packages/craco/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,20 @@ module.exports = function({ env }) {
}
```

or a **promise** or **async function**:

```javascript
/* craco.config.js */

module.exports = async function({ env }) {
await ...

return {
...
};
}
```

Update the existing calls to `react-scripts` in the `scripts` section of your `package.json` file to use the `craco` CLI:

```diff
Expand Down
27 changes: 25 additions & 2 deletions packages/craco/lib/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,43 @@ function processCracoConfig(cracoConfig, context) {
return applyCracoConfigPlugins(resultingCracoConfig, context);
}

function loadCracoConfig(context) {
function getConfigAsObject(context) {
log("Found craco config file at: ", configFilePath);

const config = require(configFilePath);
const configAsObject = isFunction(config) ? config(context) : config;

if (!configAsObject) {
throw new Error("craco: Config function didn't returned a config object.");
throw new Error("craco: Config function didn't return a config object.");
}
return configAsObject;
}

function loadCracoConfig(context) {
const configAsObject = getConfigAsObject(context);

if (configAsObject instanceof Promise) {
throw new Error(
"craco: Config function returned a promise. Use `loadCracoConfigAsync` instead of `loadCracoConfig`."
);
}

return processCracoConfig(configAsObject, context);
}

// The "build", "start", and "test" scripts use this to wait for any promises to resolve before they run.
async function loadCracoConfigAsync(context) {
const configAsObject = await getConfigAsObject(context);

if (!configAsObject) {
throw new Error("craco: Async config didn't return a config object.");
}

return processCracoConfig(configAsObject, context);
}

module.exports = {
loadCracoConfig,
loadCracoConfigAsync,
processCracoConfig
};
38 changes: 38 additions & 0 deletions packages/craco/lib/features/test/create-jest-babel-transform.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const babelJest = require("babel-jest");

const { isArray } = require("../../utils");

function createJestBabelTransform(cracoConfig) {
const craBabelTransformer = {
presets: ["babel-preset-react-app"],
babelrc: false,
configFile: false
};

if (cracoConfig) {
const { addPresets, addPlugins } = cracoConfig.jest.babel;

if (cracoConfig.babel) {
if (addPresets) {
const { presets } = cracoConfig.babel;

if (isArray(presets)) {
craBabelTransformer.presets = craBabelTransformer.presets.concat(presets);
}
}

if (addPlugins) {
const { plugins } = cracoConfig.babel;

if (isArray(plugins)) {
craBabelTransformer.plugins = plugins;
}
}
}
}
return babelJest.createTransformer(craBabelTransformer);
}

module.exports = {
createJestBabelTransform
};
49 changes: 14 additions & 35 deletions packages/craco/lib/features/test/jest-babel-transform.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,17 @@
const babelJest = require("babel-jest");

const { loadCracoConfig } = require("../../config");
const { isArray } = require("../../utils");

const craBabelTransformer = {
presets: ["babel-preset-react-app"],
babelrc: false,
configFile: false
};

const context = {
env: process.env.NODE_ENV
};

const cracoConfig = loadCracoConfig(context);

const { addPresets, addPlugins } = cracoConfig.jest.babel;

if (cracoConfig.babel) {
if (addPresets) {
const { presets } = cracoConfig.babel;

if (isArray(presets)) {
craBabelTransformer.presets = craBabelTransformer.presets.concat(presets);
const { createJestBabelTransform } = require("./create-jest-babel-transform");

let jestBabelTransform;

// cracoConfig is only available inside the transform, but the transform needs to include whatever options cracoConfig
// specifies. So, the first time this transform is run, it generates a new transform -- using cracoConfig -- and
// uses that to process files.
module.exports = {
...createJestBabelTransform(),
process(src, filename, config, transformOptions) {
if (!jestBabelTransform) {
jestBabelTransform = createJestBabelTransform(config.globals._cracoConfig);
}
}

if (addPlugins) {
const { plugins } = cracoConfig.babel;

if (isArray(plugins)) {
craBabelTransformer.plugins = plugins;
}
return jestBabelTransform.process(src, filename, config, transformOptions);
}
}

module.exports = babelJest.createTransformer(craBabelTransformer);
};
22 changes: 9 additions & 13 deletions packages/craco/lib/features/test/merge-jest-config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
const path = require("path");

const { getArgs } = require("../../args");
const { isFunction, isArray, deepMergeWithArray } = require("../../utils");
const { log } = require("../../logger");
const { applyJestConfigPlugins } = require("../plugins");
Expand All @@ -9,8 +8,13 @@ const { projectRoot } = require("../../paths");
const BABEL_TRANSFORM_ENTRY_KEY_BEFORE_2_1_0 = "^.+\\.(js|jsx)$";
const BABEL_TRANSFORM_ENTRY_KEY = "^.+\\.(js|jsx|ts|tsx)$";

function overrideBabelTransform(jestConfig, transformKey) {
jestConfig.transform[transformKey] = require.resolve("./jest-babel-transform.js");
function overrideBabelTransform(jestConfig, cracoConfig, transformKey) {
// The cracoConfig needs to be available within the jest-babel-transform in order to honor its settings.
// This approach is based on https://github.com/facebook/jest/issues/1468#issuecomment-384825178
jestConfig.globals = jestConfig.globals || {};
jestConfig.globals._cracoConfig = cracoConfig;

jestConfig.transform[transformKey] = require.resolve("./jest-babel-transform");

log("Overrided Jest Babel transformer.");
}
Expand All @@ -23,18 +27,10 @@ function configureBabel(jestConfig, cracoConfig) {
const { presets, plugins } = cracoConfig.babel;

if (isArray(presets) || isArray(plugins)) {
const { config } = getArgs();

if (config.isProvided) {
throw new Error(
"craco: Jest + Babel doesn't support --config. Provide a custom location for the craco.config.js file from your package.json file by specifing a value for 'cracoConfig'."
);
}

if (jestConfig.transform[BABEL_TRANSFORM_ENTRY_KEY]) {
overrideBabelTransform(jestConfig, BABEL_TRANSFORM_ENTRY_KEY);
overrideBabelTransform(jestConfig, cracoConfig, BABEL_TRANSFORM_ENTRY_KEY);
} else if (jestConfig.transform[BABEL_TRANSFORM_ENTRY_KEY_BEFORE_2_1_0]) {
overrideBabelTransform(jestConfig, BABEL_TRANSFORM_ENTRY_KEY_BEFORE_2_1_0);
overrideBabelTransform(jestConfig, cracoConfig, BABEL_TRANSFORM_ENTRY_KEY_BEFORE_2_1_0);
} else {
throw new Error(
`craco: Cannot find Jest transform entry for Babel ${BABEL_TRANSFORM_ENTRY_KEY} or ${BABEL_TRANSFORM_ENTRY_KEY_BEFORE_2_1_0}.`
Expand Down
11 changes: 6 additions & 5 deletions packages/craco/scripts/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ findArgsFromCli();

const { log } = require("../lib/logger");
const { getCraPaths, build } = require("../lib/cra");
const { loadCracoConfig } = require("../lib/config");
const { loadCracoConfigAsync } = require("../lib/config");
const { overrideWebpackProd } = require("../lib/features/webpack/override");

log("Override started with arguments: ", process.argv);
Expand All @@ -17,8 +17,9 @@ const context = {
env: process.env.NODE_ENV
};

const cracoConfig = loadCracoConfig(context);
context.paths = getCraPaths(cracoConfig);
loadCracoConfigAsync(context).then(cracoConfig => {
context.paths = getCraPaths(cracoConfig);

overrideWebpackProd(cracoConfig, context);
build(cracoConfig);
overrideWebpackProd(cracoConfig, context);
build(cracoConfig);
});
13 changes: 7 additions & 6 deletions packages/craco/scripts/start.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ findArgsFromCli();

const { log } = require("../lib/logger");
const { getCraPaths, start } = require("../lib/cra");
const { loadCracoConfig } = require("../lib/config");
const { loadCracoConfigAsync } = require("../lib/config");
const { overrideWebpackDev } = require("../lib/features/webpack/override");
const { overrideDevServer } = require("../lib/features/dev-server/override");

Expand All @@ -18,10 +18,11 @@ const context = {
env: process.env.NODE_ENV
};

const cracoConfig = loadCracoConfig(context);
context.paths = getCraPaths(cracoConfig);
loadCracoConfigAsync(context).then(cracoConfig => {
context.paths = getCraPaths(cracoConfig);

overrideWebpackDev(cracoConfig, context);
overrideDevServer(cracoConfig, context);
overrideWebpackDev(cracoConfig, context);
overrideDevServer(cracoConfig, context);

start(cracoConfig);
start(cracoConfig);
});
11 changes: 6 additions & 5 deletions packages/craco/scripts/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ findArgsFromCli();
const { log } = require("../lib/logger");
const { getCraPaths, test } = require("../lib/cra");
const { overrideJest } = require("../lib/features/test/override");
const { loadCracoConfig } = require("../lib/config");
const { loadCracoConfigAsync } = require("../lib/config");

log("Override started with arguments: ", process.argv);
log("For environment: ", process.env.NODE_ENV);
Expand All @@ -17,8 +17,9 @@ const context = {
env: process.env.NODE_ENV
};

const cracoConfig = loadCracoConfig(context);
context.paths = getCraPaths(cracoConfig);
loadCracoConfigAsync(context).then(cracoConfig => {
context.paths = getCraPaths(cracoConfig);

overrideJest(cracoConfig, context);
test(cracoConfig);
overrideJest(cracoConfig, context);
test(cracoConfig);
});

0 comments on commit e4ac761

Please sign in to comment.