152 lines
6.8 KiB
Plaintext
152 lines
6.8 KiB
Plaintext
import chalk from "next/dist/compiled/chalk";
|
|
import { findConfig } from "../../../../../lib/find-config";
|
|
const genericErrorText = "Malformed PostCSS Configuration";
|
|
function getError_NullConfig(pluginName) {
|
|
return `${chalk.red.bold("Error")}: Your PostCSS configuration for '${pluginName}' cannot have ${chalk.bold("null")} configuration.\nTo disable '${pluginName}', pass ${chalk.bold("false")}, otherwise, pass ${chalk.bold("true")} or a configuration object.`;
|
|
}
|
|
function isIgnoredPlugin(pluginPath) {
|
|
const ignoredRegex = /(?:^|[\\/])(postcss-modules-values|postcss-modules-scope|postcss-modules-extract-imports|postcss-modules-local-by-default|postcss-modules)(?:[\\/]|$)/i;
|
|
const match = ignoredRegex.exec(pluginPath);
|
|
if (match == null) {
|
|
return false;
|
|
}
|
|
const plugin = match.pop();
|
|
console.warn(`${chalk.yellow.bold("Warning")}: Please remove the ${chalk.underline(plugin)} plugin from your PostCSS configuration. ` + `This plugin is automatically configured by Next.js.\n` + "Read more: https://nextjs.org/docs/messages/postcss-ignored-plugin");
|
|
return true;
|
|
}
|
|
const createLazyPostCssPlugin = (fn)=>{
|
|
let result = undefined;
|
|
const plugin = (...args)=>{
|
|
if (result === undefined) result = fn();
|
|
if (result.postcss === true) {
|
|
return result(...args);
|
|
} else if (result.postcss) {
|
|
return result.postcss;
|
|
}
|
|
return result;
|
|
};
|
|
plugin.postcss = true;
|
|
return plugin;
|
|
};
|
|
async function loadPlugin(dir, pluginName, options) {
|
|
if (options === false || isIgnoredPlugin(pluginName)) {
|
|
return false;
|
|
}
|
|
if (options == null) {
|
|
console.error(getError_NullConfig(pluginName));
|
|
throw new Error(genericErrorText);
|
|
}
|
|
const pluginPath = require.resolve(pluginName, {
|
|
paths: [
|
|
dir
|
|
]
|
|
});
|
|
if (isIgnoredPlugin(pluginPath)) {
|
|
return false;
|
|
} else if (options === true) {
|
|
return createLazyPostCssPlugin(()=>require(pluginPath));
|
|
} else {
|
|
if (typeof options === "object" && Object.keys(options).length === 0) {
|
|
return createLazyPostCssPlugin(()=>require(pluginPath));
|
|
}
|
|
return createLazyPostCssPlugin(()=>require(pluginPath)(options));
|
|
}
|
|
}
|
|
function getDefaultPlugins(supportedBrowsers, disablePostcssPresetEnv) {
|
|
return [
|
|
require.resolve("next/dist/compiled/postcss-flexbugs-fixes"),
|
|
disablePostcssPresetEnv ? false : [
|
|
require.resolve("next/dist/compiled/postcss-preset-env"),
|
|
{
|
|
browsers: supportedBrowsers ?? [
|
|
"defaults"
|
|
],
|
|
autoprefixer: {
|
|
// Disable legacy flexbox support
|
|
flexbox: "no-2009"
|
|
},
|
|
// Enable CSS features that have shipped to the
|
|
// web platform, i.e. in 2+ browsers unflagged.
|
|
stage: 3,
|
|
features: {
|
|
"custom-properties": false
|
|
}
|
|
}
|
|
]
|
|
].filter(Boolean);
|
|
}
|
|
export async function getPostCssPlugins(dir, supportedBrowsers, disablePostcssPresetEnv = false) {
|
|
let config = await findConfig(dir, "postcss");
|
|
if (config == null) {
|
|
config = {
|
|
plugins: getDefaultPlugins(supportedBrowsers, disablePostcssPresetEnv)
|
|
};
|
|
}
|
|
if (typeof config === "function") {
|
|
throw new Error(`Your custom PostCSS configuration may not export a function. Please export a plain object instead.\n` + "Read more: https://nextjs.org/docs/messages/postcss-function");
|
|
}
|
|
// Warn user about configuration keys which are not respected
|
|
const invalidKey = Object.keys(config).find((key)=>key !== "plugins");
|
|
if (invalidKey) {
|
|
console.warn(`${chalk.yellow.bold("Warning")}: Your PostCSS configuration defines a field which is not supported (\`${invalidKey}\`). ` + `Please remove this configuration value.`);
|
|
}
|
|
// Enforce the user provided plugins if the configuration file is present
|
|
let plugins = config.plugins;
|
|
if (plugins == null || typeof plugins !== "object") {
|
|
throw new Error(`Your custom PostCSS configuration must export a \`plugins\` key.`);
|
|
}
|
|
if (!Array.isArray(plugins)) {
|
|
// Capture variable so TypeScript is happy
|
|
const pc = plugins;
|
|
plugins = Object.keys(plugins).reduce((acc, curr)=>{
|
|
const p = pc[curr];
|
|
if (typeof p === "undefined") {
|
|
console.error(getError_NullConfig(curr));
|
|
throw new Error(genericErrorText);
|
|
}
|
|
acc.push([
|
|
curr,
|
|
p
|
|
]);
|
|
return acc;
|
|
}, []);
|
|
}
|
|
const parsed = [];
|
|
plugins.forEach((plugin)=>{
|
|
if (plugin == null) {
|
|
console.warn(`${chalk.yellow.bold("Warning")}: A ${chalk.bold("null")} PostCSS plugin was provided. This entry will be ignored.`);
|
|
} else if (typeof plugin === "string") {
|
|
parsed.push([
|
|
plugin,
|
|
true
|
|
]);
|
|
} else if (Array.isArray(plugin)) {
|
|
const pluginName = plugin[0];
|
|
const pluginConfig = plugin[1];
|
|
if (typeof pluginName === "string" && (typeof pluginConfig === "boolean" || typeof pluginConfig === "object" || typeof pluginConfig === "string")) {
|
|
parsed.push([
|
|
pluginName,
|
|
pluginConfig
|
|
]);
|
|
} else {
|
|
if (typeof pluginName !== "string") {
|
|
console.error(`${chalk.red.bold("Error")}: A PostCSS Plugin must be provided as a ${chalk.bold("string")}. Instead, we got: '${pluginName}'.\n` + "Read more: https://nextjs.org/docs/messages/postcss-shape");
|
|
} else {
|
|
console.error(`${chalk.red.bold("Error")}: A PostCSS Plugin was passed as an array but did not provide its configuration ('${pluginName}').\n` + "Read more: https://nextjs.org/docs/messages/postcss-shape");
|
|
}
|
|
throw new Error(genericErrorText);
|
|
}
|
|
} else if (typeof plugin === "function") {
|
|
console.error(`${chalk.red.bold("Error")}: A PostCSS Plugin was passed as a function using require(), but it must be provided as a ${chalk.bold("string")}.\nRead more: https://nextjs.org/docs/messages/postcss-shape`);
|
|
throw new Error(genericErrorText);
|
|
} else {
|
|
console.error(`${chalk.red.bold("Error")}: An unknown PostCSS plugin was provided (${plugin}).\n` + "Read more: https://nextjs.org/docs/messages/postcss-shape");
|
|
throw new Error(genericErrorText);
|
|
}
|
|
});
|
|
const resolved = await Promise.all(parsed.map((p)=>loadPlugin(dir, p[0], p[1])));
|
|
const filtered = resolved.filter(Boolean);
|
|
return filtered;
|
|
}
|
|
|
|
//# sourceMappingURL=plugins.js.map |