mirror of
https://github.com/storybookjs/storybook.git
synced 2025-04-07 07:21:17 +08:00
216 lines
7.2 KiB
TypeScript
216 lines
7.2 KiB
TypeScript
/**
|
|
* This file is to be watched !
|
|
* The code must be compatible from @angular-devkit version 6.1.0 to the latest supported
|
|
*
|
|
* It uses code block of angular cli to extract parts of webpack configuration
|
|
*/
|
|
|
|
import path from 'path';
|
|
import webpack, { Configuration } from 'webpack';
|
|
import { normalize, resolve, workspaces, getSystemPath } from '@angular-devkit/core';
|
|
import { createConsoleLogger } from '@angular-devkit/core/node';
|
|
|
|
// Only type, so not dependent on the client version
|
|
import {
|
|
WebpackConfigOptions,
|
|
BuildOptions,
|
|
} from '@angular-devkit/build-angular/src/utils/build-options';
|
|
|
|
import { moduleIsAvailable } from './utils/module-is-available';
|
|
import { normalizeAssetPatterns } from './utils/normalize-asset-patterns';
|
|
import { normalizeOptimization } from './utils/normalize-optimization';
|
|
|
|
const importAngularCliWebpackConfigGenerator = (): {
|
|
getCommonConfig: (config: unknown) => webpack.Configuration;
|
|
getStylesConfig: (config: unknown) => webpack.Configuration;
|
|
} => {
|
|
let angularWebpackConfig;
|
|
|
|
// First we look for webpack config according to directory structure of Angular 11
|
|
if (moduleIsAvailable('@angular-devkit/build-angular/src/webpack/configs')) {
|
|
// eslint-disable-next-line global-require
|
|
angularWebpackConfig = require('@angular-devkit/build-angular/src/webpack/configs');
|
|
}
|
|
// We fallback on directory structure of Angular 10 (and below)
|
|
else if (
|
|
moduleIsAvailable('@angular-devkit/build-angular/src/angular-cli-files/models/webpack-configs')
|
|
) {
|
|
// eslint-disable-next-line global-require
|
|
angularWebpackConfig = require('@angular-devkit/build-angular/src/angular-cli-files/models/webpack-configs');
|
|
} else {
|
|
throw new Error('Webpack config not found in "@angular-devkit/build-angular"');
|
|
}
|
|
|
|
return {
|
|
getCommonConfig: angularWebpackConfig.getCommonConfig,
|
|
getStylesConfig: angularWebpackConfig.getStylesConfig,
|
|
};
|
|
};
|
|
|
|
const importAngularCliReadTsconfigUtil =
|
|
(): typeof import('@angular-devkit/build-angular/src/utils/read-tsconfig') => {
|
|
// First we look for webpack config according to directory structure of Angular 11
|
|
if (moduleIsAvailable('@angular-devkit/build-angular/src/utils/read-tsconfig')) {
|
|
// eslint-disable-next-line global-require
|
|
return require('@angular-devkit/build-angular/src/utils/read-tsconfig');
|
|
}
|
|
// We fallback on directory structure of Angular 10 (and below)
|
|
if (
|
|
moduleIsAvailable(
|
|
'@angular-devkit/build-angular/src/angular-cli-files/utilities/read-tsconfig'
|
|
)
|
|
) {
|
|
// eslint-disable-next-line global-require
|
|
return require('@angular-devkit/build-angular/src/angular-cli-files/utilities/read-tsconfig');
|
|
}
|
|
throw new Error('ReadTsconfig not found in "@angular-devkit/build-angular"');
|
|
};
|
|
|
|
const buildWebpackConfigOptions = async (
|
|
dirToSearch: string,
|
|
project: workspaces.ProjectDefinition,
|
|
target: workspaces.TargetDefinition,
|
|
confName?: string
|
|
): Promise<WebpackConfigOptions> => {
|
|
let conf: Record<string, unknown> = {};
|
|
|
|
if (confName) {
|
|
if (!target.configurations) {
|
|
throw new Error('Missing "configurations" section in project target');
|
|
}
|
|
if (!target.configurations[confName]) {
|
|
throw new Error(`Missing required configuration in project target. Check "${confName}"`);
|
|
}
|
|
conf = target.configurations[confName];
|
|
}
|
|
|
|
const projectBuildOptions = { ...target.options, ...conf };
|
|
|
|
const requiredOptions = ['tsConfig'];
|
|
if (!requiredOptions.every((key) => !!projectBuildOptions[key])) {
|
|
throw new Error(
|
|
`Missing required options in project target. Check "${requiredOptions.join(', ')}"`
|
|
);
|
|
}
|
|
|
|
const workspaceRootNormalized = normalize(dirToSearch);
|
|
const projectRootNormalized = resolve(
|
|
workspaceRootNormalized,
|
|
normalize((project.root as string) || '')
|
|
);
|
|
const sourceRootNormalized = project.sourceRoot
|
|
? resolve(workspaceRootNormalized, normalize(project.sourceRoot))
|
|
: undefined;
|
|
|
|
const tsConfigPath = path.resolve(
|
|
getSystemPath(workspaceRootNormalized),
|
|
projectBuildOptions.tsConfig as string
|
|
);
|
|
const tsConfig = await importAngularCliReadTsconfigUtil().readTsconfig(tsConfigPath);
|
|
|
|
const ts = await import('typescript');
|
|
const scriptTarget = tsConfig.options.target || ts.ScriptTarget.ES5;
|
|
|
|
const buildOptions: BuildOptions = {
|
|
// Default options
|
|
budgets: [],
|
|
fileReplacements: [],
|
|
main: '',
|
|
outputPath: 'dist/storybook-angular',
|
|
scripts: [],
|
|
sourceMap: {},
|
|
styles: [],
|
|
// Deleted in angular 12. Keep for compatibility with versions lower than angular 12
|
|
lazyModules: [],
|
|
|
|
// Project Options
|
|
...projectBuildOptions,
|
|
assets: normalizeAssetPatterns(
|
|
(projectBuildOptions.assets as any[]) || [],
|
|
workspaceRootNormalized,
|
|
projectRootNormalized,
|
|
sourceRootNormalized
|
|
),
|
|
optimization: normalizeOptimization(projectBuildOptions.optimization as any),
|
|
|
|
// Forced options
|
|
statsJson: false,
|
|
|
|
// Deleted in angular 12. Keep for compatibility with versions lower than angular 12
|
|
// @ts-expect-error (Converted from ts-ignore)
|
|
forkTypeChecker: false,
|
|
};
|
|
|
|
return {
|
|
projectName: 'this-is-just-a-fake-name-for-getting-rid-of-the-error',
|
|
root: getSystemPath(workspaceRootNormalized),
|
|
// The dependency of `@angular-devkit/build-angular` to `@angular-devkit/core` is not exactly the same version as the one for storybook (node modules of node modules ^^)
|
|
logger: createConsoleLogger() as unknown as WebpackConfigOptions['logger'],
|
|
projectRoot: getSystemPath(projectRootNormalized),
|
|
sourceRoot: sourceRootNormalized ? getSystemPath(sourceRootNormalized) : undefined,
|
|
buildOptions,
|
|
tsConfig,
|
|
tsConfigPath,
|
|
scriptTarget,
|
|
};
|
|
};
|
|
|
|
export type AngularCliWebpackConfig = {
|
|
cliCommonWebpackConfig: {
|
|
plugins: Configuration['plugins'];
|
|
resolve: {
|
|
modules: string[];
|
|
};
|
|
resolveLoader: Configuration['resolveLoader'];
|
|
};
|
|
cliStyleWebpackConfig: {
|
|
entry: Configuration['entry'];
|
|
module: {
|
|
rules: Configuration['module']['rules'];
|
|
};
|
|
plugins: Configuration['plugins'];
|
|
};
|
|
tsConfigPath: string;
|
|
};
|
|
|
|
/**
|
|
* Uses angular cli to extract webpack configuration.
|
|
* The `AngularCliWebpackConfig` type lists the parts used by storybook
|
|
*/
|
|
export async function extractAngularCliWebpackConfig(
|
|
dirToSearch: string,
|
|
project: workspaces.ProjectDefinition,
|
|
target: workspaces.TargetDefinition,
|
|
confName?: string
|
|
): Promise<AngularCliWebpackConfig> {
|
|
const { getCommonConfig, getStylesConfig } = importAngularCliWebpackConfigGenerator();
|
|
|
|
const webpackConfigOptions = await buildWebpackConfigOptions(
|
|
dirToSearch,
|
|
project,
|
|
target,
|
|
confName
|
|
);
|
|
|
|
const cliCommonConfig = getCommonConfig(webpackConfigOptions);
|
|
const cliStyleConfig = getStylesConfig(webpackConfigOptions);
|
|
|
|
return {
|
|
cliCommonWebpackConfig: {
|
|
plugins: cliCommonConfig.plugins,
|
|
resolve: {
|
|
modules: cliCommonConfig.resolve?.modules,
|
|
},
|
|
resolveLoader: cliCommonConfig.resolveLoader,
|
|
},
|
|
cliStyleWebpackConfig: {
|
|
entry: cliStyleConfig.entry,
|
|
module: {
|
|
rules: [...cliStyleConfig.module.rules],
|
|
},
|
|
plugins: cliStyleConfig.plugins,
|
|
},
|
|
tsConfigPath: webpackConfigOptions.tsConfigPath,
|
|
};
|
|
}
|