@storybook/preset-create-react-app
Version:
Storybook for Create React App preset
445 lines (430 loc) • 23 kB
JavaScript
import CJS_COMPAT_NODE_URL_dcxejwqv6gs from 'node:url';
import CJS_COMPAT_NODE_PATH_dcxejwqv6gs from 'node:path';
import CJS_COMPAT_NODE_MODULE_dcxejwqv6gs from "node:module";
var __filename = CJS_COMPAT_NODE_URL_dcxejwqv6gs.fileURLToPath(import.meta.url);
var __dirname = CJS_COMPAT_NODE_PATH_dcxejwqv6gs.dirname(__filename);
var require = CJS_COMPAT_NODE_MODULE_dcxejwqv6gs.createRequire(import.meta.url);
// ------------------------------------------------------------
// end of CJS compatibility banner, injected by Storybook's esbuild configuration
// ------------------------------------------------------------
var __require = /* @__PURE__ */ ((x) => typeof require < "u" ? require : typeof Proxy < "u" ? new Proxy(x, {
get: (a, b) => (typeof require < "u" ? require : a)[b]
}) : x)(function(x) {
if (typeof require < "u") return require.apply(this, arguments);
throw Error('Dynamic require of "' + x + '" is not supported');
});
// src/index.ts
import module from "node:module";
import { dirname as dirname2, join as join4, relative as relative2 } from "node:path";
import { logger as logger2 } from "storybook/internal/node-logger";
import PnpWebpackPlugin from "pnp-webpack-plugin";
// src/helpers/checkPresets.ts
import { logger } from "storybook/internal/node-logger";
var incompatiblePresets = ["@storybook/preset-scss", "@storybook/preset-typescript"], checkPresets = (options) => {
let { presetsList } = options;
presetsList?.forEach((preset) => {
let presetName = typeof preset == "string" ? preset : preset.name;
incompatiblePresets.includes(presetName) && logger.warn(
`\`${presetName}\` may not be compatible with \`@storybook/preset-create-react-app\``
);
});
};
// src/helpers/getModulePath.ts
import { existsSync } from "node:fs";
import { join } from "node:path";
var JSCONFIG = "jsconfig.json", TSCONFIG = "tsconfig.json", getModulePath = (appDirectory) => {
let configName = "";
existsSync(join(appDirectory, TSCONFIG)) ? configName = TSCONFIG : existsSync(join(appDirectory, JSCONFIG)) && (configName = JSCONFIG);
try {
let { baseUrl } = __require(join(appDirectory, configName)).compilerOptions;
return baseUrl ? [baseUrl] : [];
} catch {
return [];
}
};
// src/helpers/getReactScriptsPath.ts
import { lstatSync, readFileSync, realpathSync } from "node:fs";
import { join as join3 } from "node:path";
// ../../core/src/shared/utils/module.ts
import { fileURLToPath, pathToFileURL } from "node:url";
// ../../node_modules/exsolve/dist/index.mjs
import assert from "node:assert";
import v8 from "node:v8";
import { format, inspect } from "node:util";
var own$1 = {}.hasOwnProperty, classRegExp = /^([A-Z][a-z\d]*)+$/, kTypes = /* @__PURE__ */ new Set([
"string",
"function",
"number",
"object",
"Function",
"Object",
"boolean",
"bigint",
"symbol"
]), messages = /* @__PURE__ */ new Map(), nodeInternalPrefix = "__node_internal_", userStackTraceLimit;
function formatList(array, type = "and") {
return array.length < 3 ? array.join(` ${type} `) : `${array.slice(0, -1).join(", ")}, ${type} ${array.at(-1)}`;
}
function createError(sym, value, constructor) {
return messages.set(sym, value), makeNodeErrorWithCode(constructor, sym);
}
function makeNodeErrorWithCode(Base, key) {
return function(...parameters) {
let limit = Error.stackTraceLimit;
isErrorStackTraceLimitWritable() && (Error.stackTraceLimit = 0);
let error = new Base();
isErrorStackTraceLimitWritable() && (Error.stackTraceLimit = limit);
let message = getMessage(key, parameters, error);
return Object.defineProperties(error, {
message: {
value: message,
enumerable: !1,
writable: !0,
configurable: !0
},
toString: {
value() {
return `${this.name} [${key}]: ${this.message}`;
},
enumerable: !1,
writable: !0,
configurable: !0
}
}), captureLargerStackTrace(error), error.code = key, error;
};
}
function isErrorStackTraceLimitWritable() {
try {
if (v8.startupSnapshot.isBuildingSnapshot()) return !1;
} catch {
}
let desc = Object.getOwnPropertyDescriptor(Error, "stackTraceLimit");
return desc === void 0 ? Object.isExtensible(Error) : own$1.call(desc, "writable") && desc.writable !== void 0 ? desc.writable : desc.set !== void 0;
}
function hideStackFrames(wrappedFunction) {
let hidden = nodeInternalPrefix + wrappedFunction.name;
return Object.defineProperty(wrappedFunction, "name", { value: hidden }), wrappedFunction;
}
var captureLargerStackTrace = hideStackFrames(function(error) {
let stackTraceLimitIsWritable = isErrorStackTraceLimitWritable();
return stackTraceLimitIsWritable && (userStackTraceLimit = Error.stackTraceLimit, Error.stackTraceLimit = Number.POSITIVE_INFINITY), Error.captureStackTrace(error), stackTraceLimitIsWritable && (Error.stackTraceLimit = userStackTraceLimit), error;
});
function getMessage(key, parameters, self) {
let message = messages.get(key);
if (assert.ok(message !== void 0, "expected `message` to be found"), typeof message == "function")
return assert.ok(message.length <= parameters.length, `Code: ${key}; The provided arguments length (${parameters.length}) does not match the required ones (${message.length}).`), Reflect.apply(message, self, parameters);
let regex = /%[dfijoOs]/g, expectedLength = 0;
for (; regex.exec(message) !== null; ) expectedLength++;
return assert.ok(expectedLength === parameters.length, `Code: ${key}; The provided arguments length (${parameters.length}) does not match the required ones (${expectedLength}).`), parameters.length === 0 ? message : (parameters.unshift(message), Reflect.apply(format, null, parameters));
}
function determineSpecificType(value) {
if (value == null) return String(value);
if (typeof value == "function" && value.name) return `function ${value.name}`;
if (typeof value == "object")
return value.constructor && value.constructor.name ? `an instance of ${value.constructor.name}` : `${inspect(value, { depth: -1 })}`;
let inspected = inspect(value, { colors: !1 });
return inspected.length > 28 && (inspected = `${inspected.slice(0, 25)}...`), `type ${typeof value} (${inspected})`;
}
var ERR_INVALID_ARG_TYPE = createError("ERR_INVALID_ARG_TYPE", (name, expected, actual) => {
assert.ok(typeof name == "string", "'name' must be a string"), Array.isArray(expected) || (expected = [expected]);
let message = "The ";
if (name.endsWith(" argument")) message += `${name} `;
else {
let type = name.includes(".") ? "property" : "argument";
message += `"${name}" ${type} `;
}
message += "must be ";
let types = [], instances = [], other = [];
for (let value of expected)
assert.ok(typeof value == "string", "All expected entries have to be of type string"), kTypes.has(value) ? types.push(value.toLowerCase()) : classRegExp.exec(value) === null ? (assert.ok(value !== "object", 'The value "object" should be written as "Object"'), other.push(value)) : instances.push(value);
if (instances.length > 0) {
let pos = types.indexOf("object");
pos !== -1 && (types.slice(pos, 1), instances.push("Object"));
}
return types.length > 0 && (message += `${types.length > 1 ? "one of type" : "of type"} ${formatList(types, "or")}`, (instances.length > 0 || other.length > 0) && (message += " or ")), instances.length > 0 && (message += `an instance of ${formatList(instances, "or")}`, other.length > 0 && (message += " or ")), other.length > 0 && (other.length > 1 ? message += `one of ${formatList(other, "or")}` : (other[0]?.toLowerCase() !== other[0] && (message += "an "), message += `${other[0]}`)), message += `. Received ${determineSpecificType(actual)}`, message;
}, TypeError), ERR_INVALID_MODULE_SPECIFIER = createError(
"ERR_INVALID_MODULE_SPECIFIER",
/**
* @param {string} request
* @param {string} reason
* @param {string} [base]
*/
(request, reason, base) => `Invalid module "${request}" ${reason}${base ? ` imported from ${base}` : ""}`,
TypeError
), ERR_INVALID_PACKAGE_CONFIG = createError("ERR_INVALID_PACKAGE_CONFIG", (path$1, base, message) => `Invalid package config ${path$1}${base ? ` while importing ${base}` : ""}${message ? `. ${message}` : ""}`, Error), ERR_INVALID_PACKAGE_TARGET = createError("ERR_INVALID_PACKAGE_TARGET", (packagePath, key, target, isImport = !1, base) => {
let relatedError = typeof target == "string" && !isImport && target.length > 0 && !target.startsWith("./");
return key === "." ? (assert.ok(isImport === !1), `Invalid "exports" main target ${JSON.stringify(target)} defined in the package config ${packagePath}package.json${base ? ` imported from ${base}` : ""}${relatedError ? '; targets must start with "./"' : ""}`) : `Invalid "${isImport ? "imports" : "exports"}" target ${JSON.stringify(target)} defined for '${key}' in the package config ${packagePath}package.json${base ? ` imported from ${base}` : ""}${relatedError ? '; targets must start with "./"' : ""}`;
}, Error), ERR_MODULE_NOT_FOUND = createError("ERR_MODULE_NOT_FOUND", (path$1, base, exactUrl = !1) => `Cannot find ${exactUrl ? "module" : "package"} '${path$1}' imported from ${base}`, Error), ERR_NETWORK_IMPORT_DISALLOWED = createError("ERR_NETWORK_IMPORT_DISALLOWED", "import of '%s' by %s is not supported: %s", Error), ERR_PACKAGE_IMPORT_NOT_DEFINED = createError("ERR_PACKAGE_IMPORT_NOT_DEFINED", (specifier, packagePath, base) => `Package import specifier "${specifier}" is not defined${packagePath ? ` in package ${packagePath || ""}package.json` : ""} imported from ${base}`, TypeError), ERR_PACKAGE_PATH_NOT_EXPORTED = createError(
"ERR_PACKAGE_PATH_NOT_EXPORTED",
/**
* @param {string} packagePath
* @param {string} subpath
* @param {string} [base]
*/
(packagePath, subpath, base) => subpath === "." ? `No "exports" main defined in ${packagePath}package.json${base ? ` imported from ${base}` : ""}` : `Package subpath '${subpath}' is not defined by "exports" in ${packagePath}package.json${base ? ` imported from ${base}` : ""}`,
Error
), ERR_UNSUPPORTED_DIR_IMPORT = createError("ERR_UNSUPPORTED_DIR_IMPORT", "Directory import '%s' is not supported resolving ES modules imported from %s", Error), ERR_UNSUPPORTED_RESOLVE_REQUEST = createError("ERR_UNSUPPORTED_RESOLVE_REQUEST", 'Failed to resolve module specifier "%s" from "%s": Invalid relative URL or base scheme is not hierarchical.', TypeError), ERR_UNKNOWN_FILE_EXTENSION = createError("ERR_UNKNOWN_FILE_EXTENSION", (extension, path$1) => `Unknown file extension "${extension}" for ${path$1}`, TypeError), ERR_INVALID_ARG_VALUE = createError("ERR_INVALID_ARG_VALUE", (name, value, reason = "is invalid") => {
let inspected = inspect(value);
return inspected.length > 128 && (inspected = `${inspected.slice(0, 128)}...`), `The ${name.includes(".") ? "property" : "argument"} '${name}' ${reason}. Received ${inspected}`;
}, TypeError), hasOwnProperty$1 = {}.hasOwnProperty;
var hasOwnProperty = {}.hasOwnProperty;
var RegExpPrototypeSymbolReplace = RegExp.prototype[Symbol.replace], own = {}.hasOwnProperty;
var isWindows = process.platform === "win32", globalCache = globalThis.__EXSOLVE_CACHE__ ||= /* @__PURE__ */ new Map();
// ../../node_modules/pathe/dist/shared/pathe.ff20891b.mjs
var _DRIVE_LETTER_START_RE = /^[A-Za-z]:\//;
function normalizeWindowsPath(input = "") {
return input && input.replace(/\\/g, "/").replace(_DRIVE_LETTER_START_RE, (r) => r.toUpperCase());
}
var _UNC_REGEX = /^[/\\]{2}/, _IS_ABSOLUTE_RE = /^[/\\](?![/\\])|^[/\\]{2}(?!\.)|^[A-Za-z]:[/\\]/, _DRIVE_LETTER_RE = /^[A-Za-z]:$/;
var normalize = function(path2) {
if (path2.length === 0)
return ".";
path2 = normalizeWindowsPath(path2);
let isUNCPath = path2.match(_UNC_REGEX), isPathAbsolute = isAbsolute(path2), trailingSeparator = path2[path2.length - 1] === "/";
return path2 = normalizeString(path2, !isPathAbsolute), path2.length === 0 ? isPathAbsolute ? "/" : trailingSeparator ? "./" : "." : (trailingSeparator && (path2 += "/"), _DRIVE_LETTER_RE.test(path2) && (path2 += "/"), isUNCPath ? isPathAbsolute ? `//${path2}` : `//./${path2}` : isPathAbsolute && !isAbsolute(path2) ? `/${path2}` : path2);
}, join2 = function(...arguments_) {
if (arguments_.length === 0)
return ".";
let joined;
for (let argument of arguments_)
argument && argument.length > 0 && (joined === void 0 ? joined = argument : joined += `/${argument}`);
return joined === void 0 ? "." : normalize(joined.replace(/\/\/+/g, "/"));
};
function normalizeString(path2, allowAboveRoot) {
let res = "", lastSegmentLength = 0, lastSlash = -1, dots = 0, char = null;
for (let index = 0; index <= path2.length; ++index) {
if (index < path2.length)
char = path2[index];
else {
if (char === "/")
break;
char = "/";
}
if (char === "/") {
if (!(lastSlash === index - 1 || dots === 1)) if (dots === 2) {
if (res.length < 2 || lastSegmentLength !== 2 || res[res.length - 1] !== "." || res[res.length - 2] !== ".") {
if (res.length > 2) {
let lastSlashIndex = res.lastIndexOf("/");
lastSlashIndex === -1 ? (res = "", lastSegmentLength = 0) : (res = res.slice(0, lastSlashIndex), lastSegmentLength = res.length - 1 - res.lastIndexOf("/")), lastSlash = index, dots = 0;
continue;
} else if (res.length > 0) {
res = "", lastSegmentLength = 0, lastSlash = index, dots = 0;
continue;
}
}
allowAboveRoot && (res += res.length > 0 ? "/.." : "..", lastSegmentLength = 2);
} else
res.length > 0 ? res += `/${path2.slice(lastSlash + 1, index)}` : res = path2.slice(lastSlash + 1, index), lastSegmentLength = index - lastSlash - 1;
lastSlash = index, dots = 0;
} else char === "." && dots !== -1 ? ++dots : dots = -1;
}
return res;
}
var isAbsolute = function(p) {
return _IS_ABSOLUTE_RE.test(p);
};
var dirname = function(p) {
let segments = normalizeWindowsPath(p).replace(/\/$/, "").split("/").slice(0, -1);
return segments.length === 1 && _DRIVE_LETTER_RE.test(segments[0]) && (segments[0] += "/"), segments.join("/") || (isAbsolute(p) ? "/" : ".");
};
// ../../core/src/shared/utils/module.ts
var importMetaResolve = (...args) => typeof import.meta.resolve != "function" && process.env.VITEST === "true" ? (console.warn(
"importMetaResolve from within Storybook is being used in a Vitest test, but it shouldn't be. Please report this at https://github.com/storybookjs/storybook/issues/new?template=bug_report.yml"
), pathToFileURL(args[0]).href) : import.meta.resolve(...args), resolvePackageDir = (pkg, parent) => {
try {
return dirname(fileURLToPath(importMetaResolve(join2(pkg, "package.json"), parent)));
} catch {
return dirname(fileURLToPath(importMetaResolve(join2(pkg, "package.json"))));
}
};
// src/helpers/getReactScriptsPath.ts
var getReactScriptsPath = () => {
let cwd = process.cwd(), scriptsBinPath = join3(cwd, "/node_modules/.bin/react-scripts");
if (process.platform === "win32")
try {
let packagePathMatch = readFileSync(scriptsBinPath, "utf8").match(
/"\$basedir[\\/](\S+?)[\\/]bin[\\/]react-scripts\.js"/i
);
if (packagePathMatch && packagePathMatch.length > 1)
return join3(cwd, "/node_modules/.bin/", packagePathMatch[1]);
} catch {
}
else
try {
let scriptsBinPathStat = lstatSync(scriptsBinPath);
if (scriptsBinPathStat.isSymbolicLink() === !0) {
let resolvedBinPath = realpathSync(scriptsBinPath);
return join3(resolvedBinPath, "..", "..");
}
if (scriptsBinPathStat.isFile() === !0)
return join3(cwd, "/node_modules/react-scripts");
} catch {
}
try {
return resolvePackageDir("react-scripts");
} catch {
}
return "";
};
// src/helpers/mergePlugins.ts
import ReactRefreshWebpackPlugin from "@pmmmwh/react-refresh-webpack-plugin";
var mergePlugins = (...args) => args?.reduce((plugins, plugin) => {
if (plugins?.some(
(includedPlugin) => includedPlugin?.constructor.name === plugin?.constructor.name
) || plugin?.constructor.name === "WebpackManifestPlugin")
return plugins;
let updatedPlugin = plugin;
return plugin?.constructor.name === "ReactRefreshPlugin" && (updatedPlugin = new ReactRefreshWebpackPlugin({
overlay: {
sockIntegration: "whm"
}
})), [...plugins ?? [], updatedPlugin];
}, []);
// src/helpers/processCraConfig.ts
import { resolve as resolve2 } from "node:path";
import semver from "semver";
var isRegExp = (value) => value instanceof RegExp, isString = (value) => typeof value == "string", testMatch = (rule, string) => rule.test ? Array.isArray(rule.test) ? rule.test.some((test) => isRegExp(test) && test.test(string)) : isRegExp(rule.test) && rule.test.test(string) : !1, processCraConfig = async (craWebpackConfig, options) => {
let configDir = resolve2(options.configDir), storybookVersion = semver.coerce(options.packageJson?.version) || "", isStorybook530 = semver.gte(storybookVersion, "5.3.0"), babelOptions = await options.presets.apply("babel");
return craWebpackConfig?.module?.rules ? craWebpackConfig.module.rules.reduce((rules, rule) => {
let { oneOf, include } = rule;
if (testMatch(rule, ".jsx")) {
let newRule = {
...rule,
include: [include, configDir].filter(Boolean)
};
return [...rules, newRule];
}
return oneOf ? [
...rules,
{
// @ts-expect-error (broken typings from webpack)
oneOf: oneOf.map((oneOfRule) => {
if (oneOfRule.type === "asset/resource") {
if (isStorybook530) {
let excludes = [
"ejs",
// Used within Storybook.
"md",
// Used with Storybook Notes.
"mdx",
// Used with Storybook Docs.
"cjs",
// Used for CommonJS modules.
...options.craOverrides?.fileLoaderExcludes || []
], excludeRegex = new RegExp(`\\.(${excludes.join("|")})$`);
return {
...oneOfRule,
exclude: [...oneOfRule.exclude, excludeRegex]
};
}
return {};
}
if (testMatch(oneOfRule, ".css"))
return {
...oneOfRule,
include: isStorybook530 ? void 0 : [configDir],
exclude: [oneOfRule.exclude, /@storybook/]
};
let isBabelLoader = isString(oneOfRule.loader) && /[/\\]babel-loader[/\\]/.test(oneOfRule.loader);
if (isBabelLoader && isRegExp(oneOfRule.test) && oneOfRule.test.test(".jsx")) {
let { include: _include, options: ruleOptions } = oneOfRule, {
plugins: rulePlugins,
presets: rulePresets,
overrides: ruleOverrides
} = typeof ruleOptions == "object" ? ruleOptions : {}, { extends: _extends, plugins, presets, overrides } = babelOptions;
return {
...oneOfRule,
include: [_include, configDir].filter(Boolean),
options: {
...ruleOptions,
extends: _extends,
plugins: [...plugins ?? [], ...rulePlugins ?? []],
presets: [...presets ?? [], ...rulePresets ?? []],
overrides: [...overrides ?? [], ...ruleOverrides ?? []]
}
};
}
return isBabelLoader && isRegExp(oneOfRule.test) && oneOfRule.test.test(".js") ? {
...oneOfRule,
include: [configDir]
} : oneOfRule;
})
}
] : [...rules, rule];
}, []) : [];
};
// src/index.ts
var CWD = process.cwd(), REACT_SCRIPTS_PATH = getReactScriptsPath(), OPTION_SCRIPTS_PACKAGE = "scriptsPackageName";
process.env.PUBLIC_URL || (process.env.PUBLIC_URL = ".");
var resolveLoader = {
modules: ["node_modules", join4(REACT_SCRIPTS_PATH, "node_modules")],
// TODO: Remove in SB11
plugins: [PnpWebpackPlugin.moduleLoader(module)]
}, core = (existing) => ({
...existing,
disableWebpackDefaults: !0
}), webpack = async (webpackConfig = {}, options) => {
let scriptsPath = REACT_SCRIPTS_PATH;
checkPresets(options);
let scriptsPackageName = options[OPTION_SCRIPTS_PACKAGE];
if (typeof scriptsPackageName == "string")
try {
scriptsPath = dirname2(
__require.resolve(`${scriptsPackageName}/package.json`, {
paths: [options.configDir]
})
);
} catch {
logger2.warn(`A \`${OPTION_SCRIPTS_PACKAGE}\` was provided, but couldn't be resolved.`);
}
if (!scriptsPath)
return logger2.error("Failed to resolve a `react-scripts` package."), webpackConfig;
logger2.step(`Loading Webpack configuration from \`${relative2(CWD, scriptsPath)}\``), logger2.step("Removing existing JavaScript and TypeScript rules.");
let filteredRules = webpackConfig.module?.rules?.filter((rule) => {
if (typeof rule == "string")
return !1;
let { test } = rule;
return !(test instanceof RegExp && (test?.test(".js") || test?.test(".ts")));
}), craWebpackConfigPath = join4(scriptsPath, "config", "webpack.config"), craWebpackConfig = __require(craWebpackConfigPath)(webpackConfig.mode);
logger2.step("Modifying Create React App rules.");
let craRules = await processCraConfig(craWebpackConfig, options), isProd = webpackConfig.mode !== "development", builder = (await options.presets.apply("core"))?.builder, builderOptions = typeof builder == "string" ? {} : builder?.options, cacheConfig = builderOptions?.fsCache ? { cache: { type: "filesystem" } } : {}, lazyCompilationConfig = builderOptions?.lazyCompilation && !isProd ? { experiments: { lazyCompilation: { entries: !1 } } } : {};
return {
...webpackConfig,
...cacheConfig,
...lazyCompilationConfig,
module: {
...webpackConfig.module,
rules: [...filteredRules || [], ...craRules]
},
// NOTE: this prioritizes the storybook version of a plugin
// when there are duplicates between SB and CRA
plugins: mergePlugins(
...webpackConfig.plugins ?? [],
...craWebpackConfig.plugins ?? []
),
resolve: {
...webpackConfig.resolve,
extensions: craWebpackConfig.resolve?.extensions,
modules: [
...webpackConfig.resolve && webpackConfig.resolve.modules || [],
join4(REACT_SCRIPTS_PATH, "node_modules"),
...getModulePath(CWD)
],
// TODO: Remove in SB11
plugins: [PnpWebpackPlugin],
// manual copy from builder-webpack because defaults are disabled in this CRA preset
conditionNames: [
...webpackConfig.resolve?.conditionNames ?? [],
"storybook",
"stories",
"test",
"..."
]
},
resolveLoader
};
}, exportedCore = core, exportedWebpack = webpack;
export {
exportedCore as core,
exportedWebpack as webpack
};