@storybook/react-native
Version:
A better way to develop React Native Components for your app
171 lines (170 loc) • 7.95 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 storybook_internal_common = require("storybook/internal/common");
let storybook_internal_telemetry = require("storybook/internal/telemetry");
//#region src/metro/withStorybook.ts
var import_generate = require_env_tools.require_generate();
/**
* Configures Metro bundler to work with Storybook in React Native.
* This function wraps a Metro configuration to enable Storybook usage.
* This is intended to replace the withStorybook function in the future.
*
* @param config - The Metro bundler configuration to be modified. This should be a valid Metro config object
* that includes resolver, transformer, and other Metro-specific options.
* @param options - Options to customize the Storybook configuration.
* @param options.configPath - The path to the Storybook config folder. Defaults to './.rnstorybook'.
* This is where your main.js/ts and preview.js/ts files are located.
* @param options.websockets - WebSocket configuration for syncing storybook instances or sending events.
* When provided, creates a WebSocket server for real-time communication.
* @param options.websockets.port - The port WebSocket server will listen on. Defaults to 7007.
* @param options.websockets.host - The host WebSocket server will bind to. Defaults to 'localhost'.
* @param options.websockets.secured - Whether to use WSS/HTTPS for the channel server.
* @param options.websockets.key - TLS private key used when `secured` is true.
* @param options.websockets.cert - TLS certificate used when `secured` is true.
* @param options.useJs - Whether to use JavaScript files for Storybook configuration instead of TypeScript.
* When true, generates storybook.requires.js instead of storybook.requires.ts.
* Defaults to false.
* @param options.enabled - If false, attempts to remove storybook modules from the JavaScript
* bundle to reduce bundle size. Defaults to true.
* @param options.docTools - Whether to include doc tools in the storybook.requires file.
* Doc tools provide additional documentation features. Defaults to true.
* @param options.liteMode - Whether to use lite mode for the storybook. In lite mode, the default
* storybook UI is mocked out so you don't need to install all its dependencies
* like reanimated etc. This is useful for reducing bundle size and dependencies.
* Defaults to false.
* @returns The modified Metro configuration with Storybook support enabled.
*
* @example
* ```javascript
* const { getDefaultConfig } = require('expo/metro-config');
* const {withStorybook} = require('@storybook/react-native/metro/withStorybook');
* const path = require('path');
*
* const projectRoot = __dirname;
* const config = getDefaultConfig(projectRoot);
*
* module.exports = withStorybook(config, {
* configPath: path.resolve(projectRoot, './.rnstorybook'),
* websockets: { port: 7007, host: 'localhost' },
* useJs: false,
* docTools: true,
* liteMode: false,
* });
* ```
*
* @example
* ```javascript
* // Minimal configuration
* const { getDefaultConfig } = require('expo/metro-config');
* const {withStorybook} = require('@storybook/react-native/metro/withStorybook');
*
* const config = getDefaultConfig(__dirname);
* module.exports = withStorybook(config);
* ```
*
* @example
* ```javascript
* // Disable Storybook in production
* const { getDefaultConfig } = require('expo/metro-config');
* const {withStorybook} = require('@storybook/react-native/metro/withStorybook');
*
* const config = getDefaultConfig(__dirname);
* module.exports = withStorybook(config, {
* enabled: process.env.EXPO_PUBLIC_STORYBOOK_ENABLED === "true",
* });
* ```
*/
function withStorybook(config, options = {
useJs: false,
enabled: true,
docTools: true,
liteMode: false,
configPath: path.resolve(process.cwd(), "./.rnstorybook")
}) {
const { configPath = path.resolve(process.cwd(), "./.rnstorybook"), websockets, useJs = false, enabled = true, docTools = true, liteMode = false, experimental_mcp = false } = options;
if (!(0, storybook_internal_common.optionalEnvToBoolean)(process.env.STORYBOOK_DISABLE_TELEMETRY) && enabled) (0, storybook_internal_telemetry.telemetry)(process.env.NODE_ENV === "production" ? "build" : "dev", {}).catch((e) => {});
if (!enabled) return {
...config,
resolver: {
...config.resolver,
resolveRequest: (context, moduleName, platform) => {
const resolveFunction = config?.resolver?.resolveRequest ? config.resolver.resolveRequest : context.resolveRequest;
if (moduleName.startsWith("storybook") || moduleName.startsWith("@storybook")) return { type: "empty" };
if (platform !== "web" && (moduleName === "tty" || moduleName === "os")) return { type: "empty" };
const resolved = resolveFunction(context, moduleName, platform);
const configIndexRegex = new RegExp(`${configPath}/index\\.(tsx?|jsx?)$`);
if (resolved.filePath && configIndexRegex.test(resolved.filePath)) return {
filePath: path.resolve(__dirname, "../stub.js"),
type: "sourceFile"
};
if (resolved.filePath?.includes?.(configPath)) return { type: "empty" };
return resolved;
}
}
};
if (experimental_mcp || websockets != null || process.env.STORYBOOK_WS_HOST) {
const resolvedWs = require_env_tools.loadWebsocketEnvOverrides(websockets);
const bindHost = websockets === "auto" && !process.env.STORYBOOK_WS_HOST ? void 0 : resolvedWs.host;
const generateHost = resolvedWs.host ?? (websockets === "auto" && !process.env.STORYBOOK_WS_HOST ? "auto" : void 0);
const port = resolvedWs.port ?? 7007;
const secured = resolvedWs.secured;
require_channelServer.createChannelServer({
port,
host: bindHost,
configPath,
experimental_mcp,
websockets: Boolean(websockets) || Boolean(process.env.STORYBOOK_WS_HOST) || Boolean(resolvedWs.host),
secured,
ssl: websockets && websockets !== "auto" ? {
key: websockets.key,
cert: websockets.cert,
ca: websockets.ca,
passphrase: websockets.passphrase
} : void 0
});
if (websockets != null || process.env.STORYBOOK_WS_HOST) (0, import_generate.generate)({
configPath,
useJs,
docTools,
host: generateHost,
port,
secured
});
else (0, import_generate.generate)({
configPath,
useJs,
docTools
});
} else (0, import_generate.generate)({
configPath,
useJs,
docTools
});
return {
...config,
transformer: {
...config.transformer,
unstable_allowRequireContext: true
},
resolver: {
...config.resolver,
resolveRequest: (context, moduleName, platform) => {
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 (platform !== "web" && (moduleName === "tty" || moduleName === "os")) 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" };
return resolveResult;
}
}
};
}
//#endregion
exports.withStorybook = withStorybook;