@craco/craco
Version:
Create React App Configuration Override, an easy and comprehensible configuration layer for create-react-app.
129 lines (101 loc) • 3.44 kB
JavaScript
const { getLoaders, loaderByName } = require("../../../loaders");
const { log, logError } = require("../../../logger");
const { isArray, isFunction, deepMergeWithArray } = require("../../../utils");
const { projectRoot } = require("../../../paths");
const POSTCSS_MODES = {
extends: "extends",
file: "file"
};
const CRA_PLUGINS = presetEnv => {
// prettier-ignore
return [
require("postcss-flexbugs-fixes"),
require("postcss-preset-env")(presetEnv),
require(require.resolve("postcss-normalize", { paths: [projectRoot] }))
];
};
const CRA_PRESET_ENV = {
autoprefixer: {
flexbox: "no-2009"
},
stage: 3
};
function usePostcssConfigFile(match) {
if (match.loader.options) {
const ident = match.loader.options.ident;
const sourceMap = match.loader.options.sourceMap;
match.loader.options = {
ident: ident,
sourceMap: sourceMap
};
log("Overwrited PostCSS config to use a config file.");
}
}
function extendsPostcss(match, { plugins, env }) {
if (isArray(plugins) || env) {
let postcssPlugins;
if (env) {
const mergedPreset = deepMergeWithArray({}, CRA_PRESET_ENV, env);
postcssPlugins = CRA_PLUGINS(mergedPreset);
log("Merged PostCSS env preset.");
} else {
let craPlugins = [];
if (match.loader.options) {
craPlugins = match.loader.options.plugins();
}
postcssPlugins = craPlugins || [];
}
if (plugins) {
postcssPlugins = postcssPlugins.concat(plugins);
log("Added PostCSS plugins.");
}
if (match.loader.options) {
match.loader.options.plugins = () => postcssPlugins;
} else {
match.loader.options = {
plugins: () => postcssPlugins
};
}
}
}
function applyLoaderOptions(match, loaderOptions, context) {
if (isFunction(loaderOptions)) {
match.loader.options = loaderOptions(match.loader.options || {}, context);
if (!match.loader.options) {
throw new Error("craco: 'style.postcss.loaderOptions' function didn't return a loader config object.");
}
} else {
// TODO: ensure is otherwise a plain object, if not, log an error.
match.loader.options = deepMergeWithArray({}, match.loader.options || {}, loaderOptions);
}
log("Applied PostCSS loaders options.");
}
function overrideLoader(match, postcssConfig, context) {
const { mode, loaderOptions } = postcssConfig;
if (mode === POSTCSS_MODES.file) {
usePostcssConfigFile(match);
} else {
extendsPostcss(match, postcssConfig);
}
if (loaderOptions) {
applyLoaderOptions(match, loaderOptions, context);
}
log("Overrided PostCSS loader.");
}
function overridePostcss(cracoConfig, webpackConfig, context) {
if (cracoConfig.postcss) {
const { hasFoundAny, matches } = getLoaders(webpackConfig, loaderByName("postcss-loader"));
if (!hasFoundAny) {
logError("Cannot find any PostCSS loaders.");
return webpackConfig;
}
matches.forEach(x => {
overrideLoader(x, cracoConfig.postcss, context);
});
}
return webpackConfig;
}
module.exports = {
overridePostcss,
POSTCSS_MODES
};