@storybook/angular
Version:
Storybook for Angular: Develop, document, and test UI components in isolation
317 lines (306 loc) • 13.4 kB
JavaScript
import CJS_COMPAT_NODE_URL_hrrnwz31pm from 'node:url';
import CJS_COMPAT_NODE_PATH_hrrnwz31pm from 'node:path';
import CJS_COMPAT_NODE_MODULE_hrrnwz31pm from "node:module";
var __filename = CJS_COMPAT_NODE_URL_hrrnwz31pm.fileURLToPath(import.meta.url);
var __dirname = CJS_COMPAT_NODE_PATH_hrrnwz31pm.dirname(__filename);
var require = CJS_COMPAT_NODE_MODULE_hrrnwz31pm.createRequire(import.meta.url);
// ------------------------------------------------------------
// end of CJS compatibility banner, injected by Storybook's esbuild configuration
// ------------------------------------------------------------
import {
up
} from "../_node-chunks/chunk-R6QRREVY.js";
// src/server/framework-preset-angular-cli.ts
import { logger } from "storybook/internal/node-logger";
import { AngularLegacyBuildOptionsError } from "storybook/internal/server-errors";
import { WebpackDefinePlugin, WebpackIgnorePlugin } from "@storybook/builder-webpack5";
import { targetFromTargetString } from "@angular-devkit/architect";
import { logging } from "@angular-devkit/core";
// src/server/angular-cli-webpack.js
import { createRequire } from "node:module";
// src/server/plugins/storybook-normalize-angular-entry-plugin.js
var PLUGIN_NAME = "storybook-normalize-angular-entry-plugin", StorybookNormalizeAngularEntryPlugin = class {
constructor(options) {
this.options = options;
}
apply(compiler) {
compiler.hooks.environment.tap(PLUGIN_NAME, () => {
let originalEntry = compiler.options.entry;
compiler.options.entry = async () => {
let entryResult;
if (typeof originalEntry == "function")
try {
entryResult = await originalEntry();
} catch (error) {
throw console.error("Failed to execute the entry function:", error), error;
}
else
entryResult = originalEntry;
return entryResult && entryResult.main && entryResult.styles ? {
main: {
import: Array.from(
/* @__PURE__ */ new Set([...entryResult.main.import, ...entryResult.styles.import])
)
}
} : entryResult;
};
}), compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation) => {
this.compilation = compilation;
});
}
};
// src/server/utils/filter-out-styling-rules.ts
var isStylingRule = (rule) => {
let { test } = rule;
return !test || !(test instanceof RegExp) ? !1 : test.test(".css") || test.test(".scss") || test.test(".sass");
}, filterOutStylingRules = (config) => config.module.rules.filter((rule) => !isStylingRule(rule));
// src/server/angular-cli-webpack.js
var require2 = createRequire(import.meta.url), {
generateI18nBrowserWebpackConfigFromContext
} = require2("@angular-devkit/build-angular/src/utils/webpack-browser-config"), TsconfigPathsPlugin = require2("tsconfig-paths-webpack-plugin"), {
getCommonConfig,
getStylesConfig,
getDevServerConfig,
getTypeScriptConfig
} = require2("@angular-devkit/build-angular/src/tools/webpack/configs"), getWebpackConfig = async (baseConfig, { builderOptions, builderContext }) => {
async function getCustomStylesConfig(wco) {
let { root } = wco;
if ((() => {
try {
let output = import.meta.resolve("@tailwindcss/postcss", root);
return isAbsolute(output);
} catch {
return !1;
}
})()) {
let fs = require2("node:fs/promises"), originalReaddir = fs.readdir;
fs.readdir = async function(path2, options) {
let results = await originalReaddir.call(this, path2, options), tailwindFiles = [
"tailwind.config.js",
"tailwind.config.cjs",
"tailwind.config.mjs",
"tailwind.config.ts"
];
return results.filter((file) => !tailwindFiles.includes(file));
};
let styleConfig = await getStylesConfig(wco);
fs.readdir = originalReaddir;
let tailwindPackage = await import(import.meta.resolve("@tailwindcss/postcss", root)), extraPostcssPlugins = [
typeof tailwindPackage == "function" ? tailwindPackage() : tailwindPackage.default()
];
return styleConfig.module.rules.map((rule) => rule.rules).forEach((rule) => {
rule.forEach((r) => {
r.oneOf?.forEach?.((oneOfRule) => oneOfRule.use.forEach((use) => {
if (use.loader.includes("postcss-loader") && use.options.postcssOptions) {
let originalOptionsFn = use.options.postcssOptions;
use.options.postcssOptions = (loaderOptions) => {
let originalOptions = originalOptionsFn(loaderOptions);
return {
...originalOptions,
plugins: [...originalOptions.plugins, ...extraPostcssPlugins]
};
};
}
}));
});
}), styleConfig;
} else
return getStylesConfig(wco);
}
let { config: cliConfig } = await generateI18nBrowserWebpackConfigFromContext(
{
// Default options
index: "noop-index",
main: "noop-main",
// Options provided by user
...builderOptions,
styles: builderOptions.styles?.map((style) => typeof style == "string" ? style : style.input).filter((style) => typeof style == "string" || style.inject !== !1),
outputPath: typeof builderOptions.outputPath == "string" ? builderOptions.outputPath : builderOptions.outputPath?.base ?? "noop-out",
// Fixed options
optimization: !1,
namedChunks: !1,
progress: !1,
buildOptimizer: !1,
aot: !1
},
builderContext,
(wco) => [
getCommonConfig(wco),
getCustomStylesConfig(wco),
getTypeScriptConfig ? getTypeScriptConfig(wco) : getDevServerConfig(wco)
]
);
!builderOptions.experimentalZoneless && !cliConfig.entry.polyfills?.includes("zone.js") && (cliConfig.entry.polyfills ??= [], cliConfig.entry.polyfills.push("zone.js"));
let entry = [
...cliConfig.entry.polyfills ?? [],
...baseConfig.entry,
...cliConfig.entry.styles ?? []
], rulesExcludingStyles = filterOutStylingRules(baseConfig), module = {
...baseConfig.module,
rules: [...cliConfig.module.rules, ...rulesExcludingStyles]
}, plugins = [
...cliConfig.plugins ?? [],
...baseConfig.plugins,
new StorybookNormalizeAngularEntryPlugin()
], resolve2 = {
...baseConfig.resolve,
modules: Array.from(/* @__PURE__ */ new Set([...baseConfig.resolve.modules, ...cliConfig.resolve.modules])),
plugins: [
new TsconfigPathsPlugin({
configFile: builderOptions.tsConfig,
mainFields: ["browser", "module", "main"]
})
]
};
return {
...baseConfig,
entry,
module,
plugins,
resolve: resolve2,
resolveLoader: cliConfig.resolveLoader
};
};
// src/server/framework-preset-angular-cli.ts
import { getProjectRoot, resolvePackageDir } from "storybook/internal/common";
// ../../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 _IS_ABSOLUTE_RE = /^[/\\](?![/\\])|^[/\\]{2}(?!\.)|^[A-Za-z]:[/\\]/;
var _ROOT_FOLDER_RE = /^\/([A-Za-z]:)?$/;
function cwd() {
return typeof process < "u" && typeof process.cwd == "function" ? process.cwd().replace(/\\/g, "/") : "/";
}
var resolve = function(...arguments_) {
arguments_ = arguments_.map((argument) => normalizeWindowsPath(argument));
let resolvedPath = "", resolvedAbsolute = !1;
for (let index = arguments_.length - 1; index >= -1 && !resolvedAbsolute; index--) {
let path2 = index >= 0 ? arguments_[index] : cwd();
!path2 || path2.length === 0 || (resolvedPath = `${path2}/${resolvedPath}`, resolvedAbsolute = isAbsolute2(path2));
}
return resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute), resolvedAbsolute && !isAbsolute2(resolvedPath) ? `/${resolvedPath}` : resolvedPath.length > 0 ? resolvedPath : ".";
};
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 isAbsolute2 = function(p) {
return _IS_ABSOLUTE_RE.test(p);
};
var relative = function(from, to) {
let _from = resolve(from).replace(_ROOT_FOLDER_RE, "$1").split("/"), _to = resolve(to).replace(_ROOT_FOLDER_RE, "$1").split("/");
if (_to[0][1] === ":" && _from[0][1] === ":" && _from[0] !== _to[0])
return _to.join("/");
let _fromCopy = [..._from];
for (let segment of _fromCopy) {
if (_to[0] !== segment)
break;
_from.shift(), _to.shift();
}
return [..._from.map(() => ".."), ..._to].join("/");
};
// src/server/framework-preset-angular-cli.ts
async function webpackFinal(baseConfig, options) {
if (!resolvePackageDir("@angular-devkit/build-angular"))
return logger.info('Using base config because "@angular-devkit/build-angular" is not installed'), baseConfig;
checkForLegacyBuildOptions(options);
let builderContext = getBuilderContext(options), builderOptions = await getBuilderOptions(options, builderContext), webpackConfig = await getWebpackConfig(baseConfig, {
builderOptions: {
watch: options.configType === "DEVELOPMENT",
...builderOptions
},
builderContext
});
webpackConfig.plugins = webpackConfig.plugins ?? [];
let miniCssPlugin = webpackConfig?.plugins?.find(
(plugin) => plugin?.constructor?.name === "MiniCssExtractPlugin"
);
miniCssPlugin && "options" in miniCssPlugin && (miniCssPlugin.options.filename = "[name].[contenthash].css", miniCssPlugin.options.chunkFilename = "[name].iframe.[contenthash].css"), webpackConfig.plugins.push(
new WebpackDefinePlugin({
STORYBOOK_ANGULAR_OPTIONS: JSON.stringify({
experimentalZoneless: builderOptions.experimentalZoneless
})
})
);
try {
resolvePackageDir("@angular/animations");
} catch {
webpackConfig.plugins.push(
new WebpackIgnorePlugin({
resourceRegExp: /@angular\/platform-browser\/animations$/
})
), webpackConfig.plugins.push(
new WebpackIgnorePlugin({
resourceRegExp: /@angular\/animations\/browser$/
})
);
}
return webpackConfig;
}
function getBuilderContext(options) {
return options.angularBuilderContext ?? {
target: { project: "noop-project", builder: "", options: {} },
workspaceRoot: process.cwd(),
getProjectMetadata: () => ({}),
getTargetOptions: () => ({}),
logger: new logging.Logger("Storybook")
};
}
function deepMerge(target, source) {
let result = { ...target };
for (let key in source)
source[key] !== void 0 && source[key] !== null && (typeof source[key] == "object" && !Array.isArray(source[key]) && typeof target[key] == "object" && !Array.isArray(target[key]) && target[key] !== null ? result[key] = deepMerge(target[key], source[key]) : result[key] = source[key]);
return result;
}
async function getBuilderOptions(options, builderContext) {
let browserTargetOptions = {};
if (options.angularBrowserTarget) {
let browserTarget = targetFromTargetString(options.angularBrowserTarget);
logger.info(
`Using angular browser target options from "${browserTarget.project}:${browserTarget.target}${browserTarget.configuration ? `:${browserTarget.configuration}` : ""}"`
), browserTargetOptions = await builderContext.getTargetOptions(browserTarget);
}
let explicitAngularBuilderOptions = await builderContext.getTargetOptions(
builderContext.target
), builderOptions = deepMerge(browserTargetOptions, explicitAngularBuilderOptions || {});
return builderOptions.tsConfig = options.tsConfig ?? up("tsconfig.json", { cwd: options.configDir, last: getProjectRoot() }) ?? browserTargetOptions.tsConfig, logger.info(
`Using angular project with "tsConfig:${relative(getProjectRoot(), builderOptions.tsConfig)}"`
), builderOptions.experimentalZoneless = options.angularBuilderOptions?.experimentalZoneless, builderOptions;
}
function checkForLegacyBuildOptions(options) {
if (options.angularBrowserTarget === void 0)
throw new AngularLegacyBuildOptionsError();
}
export {
deepMerge,
getBuilderOptions,
webpackFinal
};