@storybook/react-native
Version:
A better way to develop React Native Components for your app
173 lines (172 loc) • 6.68 kB
JavaScript
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const require_chunk = require("./chunk-Ble4zEEl.js");
const require_env_tools = require("./env-tools-HukDb0eg.js");
const require_channelServer = require("./channelServer-MfmENTPk.js");
let path = require("path");
path = require_chunk.__toESM(path);
let fs = require("fs");
fs = require_chunk.__toESM(fs);
//#region src/enhanceMetroConfig.ts
function enhanceMetroConfig(config, options = {}) {
const { swap, liteMode = false } = options;
return {
...config,
transformer: {
...config.transformer,
unstable_allowRequireContext: true
},
resolver: {
...config.resolver,
resolveRequest: (context, moduleName, platform) => {
if (platform !== "web" && (moduleName === "tty" || moduleName === "os")) return { type: "empty" };
const resolveResult = (config?.resolver?.resolveRequest ? config.resolver.resolveRequest : context.resolveRequest)(moduleName.startsWith("storybook") || moduleName.startsWith("@storybook") || moduleName.startsWith("uuid") ? {
...context,
unstable_enablePackageExports: true,
unstable_conditionNames: ["import"]
} : context, moduleName, platform);
if (resolveResult?.filePath?.includes?.("@storybook/react/template/cli")) return { type: "empty" };
if (liteMode && resolveResult?.filePath?.includes?.("@storybook/react-native-ui") && !resolveResult?.filePath?.includes?.("@storybook/react-native-ui-lite") && !resolveResult?.filePath?.includes?.("@storybook/react-native-ui-common")) return { type: "empty" };
if (swap && resolveResult?.filePath && path.resolve(resolveResult.filePath) === swap.appEntryPoint) return {
filePath: swap.storybookEntryPoint,
type: "sourceFile"
};
return resolveResult;
}
}
};
}
//#endregion
//#region src/enhanceRepackConfig.ts
function enhanceRepackConfig(config, options = {}) {
const { swap, liteMode = false } = options;
if (!swap && !liteMode) return config;
const result = { ...config };
if (swap) result.entry = swap.storybookEntryPoint;
if (liteMode) {
const resolve = { ...result.resolve ?? {} };
resolve.alias = {
...resolve.alias ?? {},
"@storybook/react-native-ui$": false
};
result.resolve = resolve;
}
return result;
}
//#endregion
//#region src/metro/utils.ts
const ENTRY_EXTENSIONS = [
"js",
"jsx",
"ts",
"tsx"
];
/**
* Resolves the application entry point for entry-point swapping.
*
* Detection order:
* 1. Expo Router: checks for `expo-router/entry` as the main field in package.json
* and resolves it from node_modules.
* 2. Expo / RN CLI: reads `package.json#main` and resolves it relative to the project root.
* 3. Fallback: defaults to `index.js` in the project root.
*/
function resolveEntryPoint(projectRoot = process.cwd()) {
const pkgJsonPath = path.resolve(projectRoot, "package.json");
let mainField;
try {
mainField = JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8")).main;
if (mainField === "expo-router/entry") {
const expoRouterEntry = require.resolve("expo-router/entry");
if (expoRouterEntry) return expoRouterEntry;
}
} catch {}
if (mainField && mainField !== "expo-router/entry") {
const resolved = resolveFileWithExtensions(path.resolve(projectRoot, mainField), ENTRY_EXTENSIONS);
if (resolved) return resolved;
}
return resolveFileWithExtensions(path.resolve(projectRoot, "index"), ENTRY_EXTENSIONS);
}
/**
* Resolves a file path by trying the given path as-is first, then appending each
* of the provided extensions. Returns the first path that exists on disk, or undefined.
*/
function resolveFileWithExtensions(basePath, extensions) {
try {
if (fs.statSync(basePath).isFile()) return basePath;
} catch {}
for (const ext of extensions) {
const candidate = `${basePath}.${ext}`;
if (fs.existsSync(candidate)) return candidate;
}
}
/**
* Resolves the Storybook config entry point (the file that will replace the app entry).
* Looks for index.(ts|tsx|js|jsx) in the config folder.
*/
function resolveStorybookEntry(configPath) {
return resolveFileWithExtensions(path.resolve(configPath, "index"), ENTRY_EXTENSIONS);
}
//#endregion
//#region src/withStorybook.ts
var import_generate = require_env_tools.require_generate();
function isMetroConfig(config) {
return config != null && typeof config === "object" && "transformer" in config;
}
function withStorybook(config, options = {}) {
if (!require_env_tools.envVariableToBoolean(process.env.STORYBOOK_ENABLED, options.enabled ?? false)) return config;
const server = require_env_tools.envVariableToBoolean(process.env.STORYBOOK_SERVER, true);
const disableUI = require_env_tools.envVariableToBoolean(process.env.STORYBOOK_DISABLE_UI, options.disableUI ?? false);
const settings = { ...options };
if (!server) settings.experimental_mcp = false;
if (disableUI) settings.docTools = false;
const defaultConfigPath = path.resolve(process.cwd(), "./.rnstorybook");
const configPath = options.configPath || defaultConfigPath;
const websocketsOption = options.websockets;
const resolvedWs = require_env_tools.loadWebsocketEnvOverrides(websocketsOption);
const appEntryPoint = resolveEntryPoint();
const storybookEntryPoint = resolveStorybookEntry(configPath);
const swap = appEntryPoint && storybookEntryPoint ? {
appEntryPoint,
storybookEntryPoint
} : void 0;
const { useJs = false, docTools = true, experimental_mcp = false, liteMode = false } = settings;
const bindHost = websocketsOption === "auto" && !process.env.STORYBOOK_WS_HOST ? void 0 : resolvedWs.host;
const generateHost = resolvedWs.host ?? (websocketsOption === "auto" && !process.env.STORYBOOK_WS_HOST ? "auto" : void 0);
const port = resolvedWs.port ?? 7007;
const secured = resolvedWs.secured;
const channelWebsocketsEnabled = Boolean(websocketsOption) || Boolean(process.env.STORYBOOK_WS_HOST) || Boolean(resolvedWs.host);
if (server || experimental_mcp) require_channelServer.createChannelServer({
port,
host: bindHost,
configPath,
experimental_mcp,
websockets: channelWebsocketsEnabled,
secured,
ssl: websocketsOption && websocketsOption !== "auto" && secured ? {
key: websocketsOption.key,
cert: websocketsOption.cert,
ca: websocketsOption.ca,
passphrase: websocketsOption.passphrase
} : void 0
});
(0, import_generate.generate)({
configPath,
useJs,
docTools,
disableUI,
...websocketsOption != null || process.env.STORYBOOK_WS_HOST ? {
host: generateHost,
port,
secured
} : {}
});
if (isMetroConfig(config)) return enhanceMetroConfig(config, {
swap,
liteMode
});
return enhanceRepackConfig(config, {
swap,
liteMode
});
}
//#endregion
exports.withStorybook = withStorybook;