feat(angular): add getWebpackConfig for angular 12.2.x & 13.x.x

only work with angular storybook builder
This commit is contained in:
Thibaud Av 2021-11-09 12:24:47 +01:00
parent 48d7d6089b
commit b9eaf4ba04
No known key found for this signature in database
GPG Key ID: 3F0FA53A70B49E78
14 changed files with 245 additions and 25 deletions

View File

@ -52,10 +52,12 @@
"@storybook/core-events": "6.4.0-beta.31",
"@storybook/csf": "0.0.2--canary.87bc651.0",
"@storybook/node-logger": "6.4.0-beta.31",
"@storybook/semver": "^7.3.2",
"@storybook/store": "6.4.0-beta.31",
"@types/webpack-env": "^1.16.0",
"autoprefixer": "^9.8.6",
"core-js": "^3.8.2",
"find-up": "^5.0.0",
"fork-ts-checker-webpack-plugin": "^4.1.6",
"global": "^4.4.0",
"postcss": "^7.0.36",

View File

@ -59,11 +59,14 @@ function commandBuilder(
map(({ tsConfig }) => {
const { browserTarget, ...otherOptions } = options;
return {
const standaloneOptions: StandaloneOptions = {
...otherOptions,
angularBrowserTarget: browserTarget,
angularBuilderContext: context,
tsConfig,
};
return standaloneOptions;
}),
switchMap((standaloneOptions) => runInstance(standaloneOptions)),
map(() => {
@ -88,8 +91,8 @@ async function setup(options: StorybookBuilderOptions, context: BuilderContext)
tsConfig: options.tsConfig ?? browserOptions.tsConfig ?? undefined,
};
}
function runInstance(options: StandaloneOptions) {
// FIXME : staticDir is deprecated and cause bug if i put it here. need to find a solution with core team
function runInstance({ staticDir, ...options }: StandaloneOptions) {
return new Observable<void>((observer) => {
// This Observable intentionally never complete, leaving the process running ;)
buildStandalone(options).then(

View File

@ -87,13 +87,5 @@
}
}
},
"additionalProperties": false,
"oneOf": [
{
"required": ["browserTarget"]
},
{
"required": ["tsConfig"]
}
]
"additionalProperties": false
}

View File

@ -0,0 +1 @@
export declare function getWebpackConfig(baseConfig: any, options: any): any;

View File

@ -0,0 +1,83 @@
const { targetFromTargetString } = require('@angular-devkit/architect');
// Private angular devkit stuff
const {
generateI18nBrowserWebpackConfigFromContext,
} = require('@angular-devkit/build-angular/src/utils/webpack-browser-config');
const {
getCommonConfig,
getStylesConfig,
getTypescriptWorkerPlugin,
} = require('@angular-devkit/build-angular/src/webpack/configs');
const { filterOutStylingRules } = require('./utils/filter-out-styling-rules');
/**
* Extract wepack config from angular-cli 12.2.x
* This file is in JavaScript to not use TypeScript. Because current storybook TypeScript version is not compatible with Angular CLI.
* FIXME: Try another way with TypeScript on future storybook version (7 maybe 🤞)
*
* @param {*} baseConfig Previous webpack config from storybook
* @param {*} options PresetOptions
*/
exports.getWebpackConfig = async (baseConfig, options) => {
const builderContext = options.angularBuilderContext;
const target = options.angularBrowserTarget;
let targetOptions = {};
if (target) {
targetOptions = await builderContext.getTargetOptions(targetFromTargetString(target));
}
const tsConfig = options.tsConfig ?? targetOptions.tsConfig;
const { config: cliConfig } = await generateI18nBrowserWebpackConfigFromContext(
{
// Default required options
index: 'noop-index',
main: 'noop-main',
outputPath: 'noop-out',
// Target options to override
...targetOptions,
// Fixed options
optimization: false,
namedChunks: false,
progress: false,
tsConfig,
buildOptimizer: false,
aot: false,
},
builderContext,
(wco) => [getCommonConfig(wco), getStylesConfig(wco), getTypescriptWorkerPlugin(wco)]
);
const entry = [
...baseConfig.entry,
...(cliConfig.entry.styles ?? []),
...(cliConfig.entry.polyfills ?? []),
];
// Don't use storybooks styling rules because we have to use rules created by @angular-devkit/build-angular
// because @angular-devkit/build-angular created rules have include/exclude for global style files.
const rulesExcludingStyles = filterOutStylingRules(baseConfig);
const resolve = {
...baseConfig.resolve,
modules: Array.from(new Set([...baseConfig.resolve.modules, ...cliConfig.resolve.modules])),
};
return {
...baseConfig,
entry,
module: {
...baseConfig.module,
rules: [...cliConfig.module.rules, ...rulesExcludingStyles],
},
plugins: [...(cliConfig.plugins ?? []), ...baseConfig.plugins],
resolve,
resolveLoader: cliConfig.resolveLoader,
};
};

View File

@ -0,0 +1 @@
export declare function getWebpackConfig(baseConfig: any, options: any): any;

View File

@ -0,0 +1,83 @@
const { targetFromTargetString } = require('@angular-devkit/architect');
// Private angular devkit stuff
const {
generateI18nBrowserWebpackConfigFromContext,
} = require('@angular-devkit/build-angular/src/utils/webpack-browser-config');
const {
getCommonConfig,
getStylesConfig,
getTypescriptWorkerPlugin,
} = require('@angular-devkit/build-angular/src/webpack/configs');
const { filterOutStylingRules } = require('./utils/filter-out-styling-rules');
/**
* Extract wepack config from angular-cli 12.2.x
* This file is in JavaScript to not use TypeScript. Because current storybook TypeScript version is not compatible with Angular CLI.
* FIXME: Try another way with TypeScript on future storybook version (7 maybe 🤞)
*
* @param {*} baseConfig Previous webpack config from storybook
* @param {*} options PresetOptions
*/
exports.getWebpackConfig = async (baseConfig, options) => {
const builderContext = options.angularBuilderContext;
const target = options.angularBrowserTarget;
let targetOptions = {};
if (target) {
targetOptions = await builderContext.getTargetOptions(targetFromTargetString(target));
}
const tsConfig = options.tsConfig ?? targetOptions.tsConfig;
const { config: cliConfig } = await generateI18nBrowserWebpackConfigFromContext(
{
// Default required options
index: 'noop-index',
main: 'noop-main',
outputPath: 'noop-out',
// Target options to override
...targetOptions,
// Fixed options
optimization: false,
namedChunks: false,
progress: false,
tsConfig,
buildOptimizer: false,
aot: false,
},
builderContext,
(wco) => [getCommonConfig(wco), getStylesConfig(wco), getTypescriptWorkerPlugin(wco)]
);
const entry = [
...baseConfig.entry,
...(cliConfig.entry.styles ?? []),
...(cliConfig.entry.polyfills ?? []),
];
// Don't use storybooks styling rules because we have to use rules created by @angular-devkit/build-angular
// because @angular-devkit/build-angular created rules have include/exclude for global style files.
const rulesExcludingStyles = filterOutStylingRules(baseConfig);
const resolve = {
...baseConfig.resolve,
modules: Array.from(new Set([...baseConfig.resolve.modules, ...cliConfig.resolve.modules])),
};
return {
...baseConfig,
entry,
module: {
...baseConfig.module,
rules: [...cliConfig.module.rules, ...rulesExcludingStyles],
},
plugins: [...(cliConfig.plugins ?? []), ...baseConfig.plugins],
resolve,
resolveLoader: cliConfig.resolveLoader,
};
};

View File

@ -2,8 +2,9 @@ import webpack from 'webpack';
import { logger } from '@storybook/node-logger';
import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin';
import { targetFromTargetString, Target } from '@angular-devkit/architect';
import { sync as findUpSync } from 'find-up';
import semver from '@storybook/semver';
import { Options as CoreOptions } from '@storybook/core-common';
import { workspaces } from '@angular-devkit/core';
import {
findAngularProjectTarget,
@ -16,13 +17,32 @@ import {
} from './angular-devkit-build-webpack';
import { moduleIsAvailable } from './utils/module-is-available';
import { filterOutStylingRules } from './utils/filter-out-styling-rules';
import { getWebpackConfig as getWebpackConfig12_2_x } from './angular-cli-webpack-12.2.x';
import { getWebpackConfig as getWebpackConfig13_x_x } from './angular-cli-webpack-13.x.x';
import { PresetOptions } from './options';
export type Options = CoreOptions & {
angularBrowserTarget?: string;
tsConfig?: string;
};
export async function webpackFinal(baseConfig: webpack.Configuration, options: PresetOptions) {
/**
* Find angular version and use right getWebpackConfig
*
* Only work with angular storybook builder
*/
const packageJson = await import(findUpSync('package.json', { cwd: options.configDir }));
const angularCliVersion = semver.coerce(packageJson.devDependencies['@angular/cli'])?.version;
export async function webpackFinal(baseConfig: webpack.Configuration, options: Options) {
const isNg12_2_x = semver.satisfies(angularCliVersion, '12.2.x');
if (isNg12_2_x && options.angularBuilderContext) {
return getWebpackConfig12_2_x(baseConfig, options);
}
const isNg13_x_x = semver.satisfies(angularCliVersion, '13.x.x');
if (isNg13_x_x && options.angularBuilderContext) {
return getWebpackConfig13_x_x(baseConfig, options);
}
/**
* Classic way currently support version lower than 12.2.x
*/
const dirToSearch = process.cwd();
if (!moduleIsAvailable('@angular-devkit/build-angular')) {

View File

@ -1,7 +1,25 @@
import { Configuration } from 'webpack';
import { process as ngccProcess } from '@angular/compiler-cli/ngcc';
import * as path from 'path';
import { Options } from './framework-preset-angular-cli';
import { PresetOptions } from './options';
/**
* Source : https://github.com/angular/angular-cli/blob/ebccb5de4a455af813c5e82483db6af20666bdbd/packages/angular_devkit/build_angular/src/utils/load-esm.ts#L23
* This uses a dynamic import to load a module which may be ESM.
* CommonJS code can load ESM code via a dynamic import. Unfortunately, TypeScript
* will currently, unconditionally downlevel dynamic import into a require call.
* require calls cannot load ESM code and will result in a runtime error. To workaround
* this, a Function constructor is used to prevent TypeScript from changing the dynamic import.
* Once TypeScript provides support for keeping the dynamic import this workaround can
* be dropped.
*
* @param modulePath The path of the module to load.
* @returns A Promise that resolves to the dynamically imported module.
*/
function loadEsmModule<T>(modulePath: string): Promise<T> {
// eslint-disable-next-line no-new-func
return new Function('modulePath', `return import(modulePath);`)(modulePath) as Promise<T>;
}
/**
* Run ngcc for converting modules to ivy format before starting storybook
@ -9,8 +27,11 @@ import { Options } from './framework-preset-angular-cli';
*
* Information about Ivy can be found here https://angular.io/guide/ivy
*/
export const runNgcc = () => {
ngccProcess({
export const runNgcc = async () => {
const ngcc = await loadEsmModule<typeof import('@angular/compiler-cli/ngcc')>(
'@angular/compiler-cli/ngcc'
);
ngcc.process({
// should be async: true but does not work due to
// https://github.com/storybookjs/storybook/pull/11157/files#r615413803
async: false,
@ -20,7 +41,7 @@ export const runNgcc = () => {
});
};
export const webpack = async (webpackConfig: Configuration, options: Options) => {
export const webpack = async (webpackConfig: Configuration, options: PresetOptions) => {
const angularOptions = await options.presets.apply(
'angularOptions',
{} as {

View File

@ -1,5 +1,13 @@
import { sync } from 'read-pkg-up';
import { LoadOptions } from '@storybook/core-common';
import { LoadOptions, Options as CoreOptions } from '@storybook/core-common';
import { BuilderContext } from '@angular-devkit/architect';
export type PresetOptions = CoreOptions & {
angularBrowserTarget?: string;
angularBuilderContext?: BuilderContext | null;
tsConfig?: string;
};
export default {
packageJson: sync({ cwd: __dirname }).packageJson,

View File

@ -1,4 +1,5 @@
declare module 'global';
declare module '@storybook/semver';
// will be provided by the webpack define plugin
declare var NODE_ENV: string | undefined;

View File

@ -1,4 +1,5 @@
import { CLIOptions, LoadOptions, BuilderOptions } from '@storybook/core-common';
import { BuilderContext } from '@angular-devkit/architect';
export type StandaloneOptions = Partial<
CLIOptions &
@ -6,6 +7,7 @@ export type StandaloneOptions = Partial<
BuilderOptions & {
mode?: 'static' | 'dev';
angularBrowserTarget?: string | null;
angularBuilderContext?: BuilderContext | null;
tsConfig?: string;
}
>;

View File

@ -5,7 +5,8 @@
"outDir": "dist",
"types": ["webpack-env", "node"],
"rootDir": "./src",
"resolveJsonModule": true
"resolveJsonModule": true,
"allowJs": true
},
"include": ["src/**/*", "src/**/*.json"]
}

View File

@ -7513,6 +7513,7 @@ __metadata:
"@storybook/core-events": 6.4.0-beta.31
"@storybook/csf": 0.0.2--canary.87bc651.0
"@storybook/node-logger": 6.4.0-beta.31
"@storybook/semver": ^7.3.2
"@storybook/store": 6.4.0-beta.31
"@types/autoprefixer": ^9.7.2
"@types/jest": ^26.0.16
@ -7520,6 +7521,7 @@ __metadata:
"@webcomponents/custom-elements": ^1.4.3
autoprefixer: ^9.8.6
core-js: ^3.8.2
find-up: ^5.0.0
fork-ts-checker-webpack-plugin: ^4.1.6
global: ^4.4.0
jest: ^26.6.3