diff --git a/MIGRATION.md b/MIGRATION.md index 74a25caa45a7..1f4a4b5e997e 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -38,6 +38,8 @@ - [Addon-a11y: Removed deprecated withA11y decorator](#addon-a11y-removed-deprecated-witha11y-decorator) - [Stories glob matches MDX files](#stories-glob-matches-mdx-files) - [Add strict mode](#add-strict-mode) + - [Angular: Drop support for Angular \< 14](#angular-drop-support-for-angular--14) + - [Angular: Drop support for calling storybook directly](#angular-drop-support-for-calling-storybook-directly) - [Docs Changes](#docs-changes) - [Standalone docs files](#standalone-docs-files) - [Referencing stories in docs files](#referencing-stories-in-docs-files) @@ -306,8 +308,8 @@ To opt-out of the old behavior you can set the `storyStoreV7` feature flag to `f module.exports = { features: { storyStoreV7: false, - } -} + }, +}; ``` #### Removed global client APIs @@ -740,6 +742,15 @@ Starting in 7.0, Storybook's build tools add [`"use strict"`](https://developer. If user code in `.storybook/preview.js` or stories relies on "sloppy" mode behavior, it will need to be updated. As a workaround, it is sometimes possible to move the sloppy mode code inside a script tag in `.storybook/preview-head.html`. +#### Angular: Drop support for Angular < 14 + +Starting in 7.0, we drop support for Angular < 14 + +#### Angular: Drop support for calling storybook directly + +In Storybook 6.4 we have deprecated calling Storybook directly (`npm run storybook`) and removed support for it in Storybook 7.0 entirely. Instead you have to set up +the Storybook builder in your `angular.json` and execute `ng run :storybook` to start Storybook. Please visit https://github.com/storybookjs/storybook/tree/next/code/frameworks/angular to set up Storybook for Angular correctly. + ### Docs Changes The information hierarchy of docs in Storybook has changed in 7.0. The main difference is that each docs is listed in the sidebar as a separate entry, rather than attached to individual stories. @@ -3812,4 +3823,3 @@ If you **are** using these addons, it takes two steps to migrate: ``` - diff --git a/code/frameworks/angular/README.md b/code/frameworks/angular/README.md index ceb998025f85..8ef91c279af6 100644 --- a/code/frameworks/angular/README.md +++ b/code/frameworks/angular/README.md @@ -1,5 +1,11 @@ # Storybook for Angular +- [Storybook for Angular](#storybook-for-angular) + - [Getting Started](#getting-started) + - [Setup Compodoc](#setup-compodoc) + - [Support for multi-project workspace](#support-for-multi-project-workspace) + - [Run Storybook](#run-storybook) + Storybook for Angular is a UI development environment for your Angular components. With it, you can visualize different states of your UI components and develop them interactively. @@ -15,6 +21,66 @@ cd my-angular-app npx storybook init ``` +### Setup Compodoc + +When installing, you will be given the option to set up Compodoc, which is a tool for creating documentation for Angular projects. + +You can include JSDoc comments above components, directives, and other parts of your Angular code to include documentation for those elements. Compodoc uses these comments to generate documentation for your application. In Storybook, it is useful to add explanatory comments above @Inputs and @Outputs, since these are the main elements that Storybook displays in its user interface. The @Inputs and @Outputs are the elements that you can interact with in Storybook, such as controls. + +## Support for multi-project workspace + +Storybook supports Angular multi-project workspace. You can setup Storybook for each project in the workspace. When running `npx storybook init` you will be asked for which project Storybook should be set up. Essentially, during initialization, the `angular.json` will be edited to add the Storybook configuration for the selected project. The configuration looks approximately like this: + +```json +// angular.json +{ + ... + "projects": { + ... + "your-project": { + ... + "architect": { + ... + "storybook": { + "builder": "@storybook/angular:start-storybook", + "options": { + "configDir": ".storybook", + "browserTarget": "your-project:build", + "compodoc": false, + "port": 6006 + } + }, + "build-storybook": { + "builder": "@storybook/angular:build-storybook", + "options": { + "configDir": ".storybook", + "browserTarget": "your-project:build", + "compodoc": false, + "outputDir": "dist/storybook/your-project" + } + } + } + } + } +} +``` + +## Run Storybook + +To run Storybook for a particular project, please run: + +```sh +ng run your-project:storybook +``` + +To build Storybook, run: + +```sh +ng run your-project:build-storybook +``` + +You will find the output in `dist/storybook/your-project`. + For more information visit: [storybook.js.org](https://storybook.js.org) --- diff --git a/code/frameworks/angular/src/builders/start-storybook/index.ts b/code/frameworks/angular/src/builders/start-storybook/index.ts index 381176740a87..7374481c4c2b 100644 --- a/code/frameworks/angular/src/builders/start-storybook/index.ts +++ b/code/frameworks/angular/src/builders/start-storybook/index.ts @@ -103,8 +103,8 @@ function commandBuilder( return standaloneOptions; }), switchMap((standaloneOptions) => runInstance(standaloneOptions)), - map(() => { - return { success: true }; + map(({ port }) => { + return { success: true, info: { port } }; }) ); } @@ -129,10 +129,10 @@ async function setup(options: StorybookBuilderOptions, context: BuilderContext) }; } function runInstance(options: StandaloneOptions) { - return new Observable((observer) => { + return new Observable<{ port: number }>((observer) => { // This Observable intentionally never complete, leaving the process running ;) buildDevStandalone(options as any).then( - () => observer.next(), + ({ port }) => observer.next({ port }), (error) => observer.error(buildStandaloneErrorHandler(error)) ); }); diff --git a/code/frameworks/angular/src/builders/utils/run-compodoc.ts b/code/frameworks/angular/src/builders/utils/run-compodoc.ts index 2d9c99279910..ba509bd05abe 100644 --- a/code/frameworks/angular/src/builders/utils/run-compodoc.ts +++ b/code/frameworks/angular/src/builders/utils/run-compodoc.ts @@ -1,7 +1,7 @@ import { BuilderContext } from '@angular-devkit/architect'; -import { spawn } from 'child_process'; import { Observable } from 'rxjs'; import * as path from 'path'; +import { JsPackageManagerFactory } from '@storybook/cli'; const hasTsConfigArg = (args: string[]) => args.indexOf('-p') !== -1; const hasOutputArg = (args: string[]) => @@ -20,37 +20,22 @@ export const runCompodoc = ( return new Observable((observer) => { const tsConfigPath = toRelativePath(tsconfig); const finalCompodocArgs = [ - 'compodoc', - // Default options ...(hasTsConfigArg(compodocArgs) ? [] : ['-p', tsConfigPath]), - ...(hasOutputArg(compodocArgs) ? [] : ['-d', `${context.workspaceRoot}`]), + ...(hasOutputArg(compodocArgs) ? [] : ['-d', `${context.workspaceRoot || '.'}`]), ...compodocArgs, ]; - try { - context.logger.info(finalCompodocArgs.join(' ')); - const child = spawn('npx', finalCompodocArgs, { - cwd: context.workspaceRoot, - shell: true, - }); + const packageManager = JsPackageManagerFactory.getPackageManager(); - child.stdout.on('data', (data) => { - context.logger.info(data.toString()); - }); - child.stderr.on('data', (data) => { - context.logger.error(data.toString()); - }); + try { + const stdout = packageManager.runScript('compodoc', finalCompodocArgs, context.workspaceRoot); - child.on('close', (code) => { - if (code === 0) { - observer.next(); - observer.complete(); - } else { - observer.error(); - } - }); - } catch (error) { - observer.error(error); + context.logger.info(stdout); + observer.next(); + observer.complete(); + } catch (e) { + context.logger.error(e); + observer.error(); } }); }; diff --git a/code/frameworks/angular/src/client/decorateStory.ts b/code/frameworks/angular/src/client/decorateStory.ts index 532b4353f7fb..83620080a625 100644 --- a/code/frameworks/angular/src/client/decorateStory.ts +++ b/code/frameworks/angular/src/client/decorateStory.ts @@ -34,7 +34,7 @@ const prepareMain = ( ): AngularRenderer['storyResult'] => { let { template } = story; - const component = story.component ?? context.component; + const { component } = context; const userDefinedTemplate = !hasNoTemplate(template); if (!userDefinedTemplate && component) { diff --git a/code/lib/cli/package.json b/code/lib/cli/package.json index fc9dd6ea695e..8835f238e306 100644 --- a/code/lib/cli/package.json +++ b/code/lib/cli/package.json @@ -22,6 +22,18 @@ }, "license": "MIT", "author": "Storybook Team", + "exports": { + ".": { + "node": "./dist/index.js", + "require": "./dist/index.js", + "import": "./dist/index.mjs", + "types": "./dist/index.d.ts" + }, + "./package.json": "./package.json" + }, + "main": "dist/index.js", + "module": "dist/index.mjs", + "types": "dist/index.d.ts", "bin": { "getstorybook": "./bin/index.js", "sb": "./bin/index.js" @@ -93,7 +105,8 @@ }, "bundler": { "entries": [ - "./src/generate.ts" + "./src/generate.ts", + "./src/index.ts" ], "platform": "node" }, diff --git a/code/lib/cli/src/detect.test.ts b/code/lib/cli/src/detect.test.ts index 597e2fc7818d..aba138e6a3c3 100644 --- a/code/lib/cli/src/detect.test.ts +++ b/code/lib/cli/src/detect.test.ts @@ -344,14 +344,6 @@ describe('Detect', () => { ) ).toBe(false); }); - - it('ALREADY_HAS_STORYBOOK if lib is present', () => { - expect( - isStorybookInstalled({ - devDependencies: { '@storybook/react': '4.0.0-alpha.21' }, - }) - ).toBe(ProjectType.ALREADY_HAS_STORYBOOK); - }); }); describe('detectFrameworkPreset should return', () => { diff --git a/code/lib/cli/src/detect.ts b/code/lib/cli/src/detect.ts index bf5e9efb38ec..87f8dbefa6fb 100644 --- a/code/lib/cli/src/detect.ts +++ b/code/lib/cli/src/detect.ts @@ -142,7 +142,7 @@ export function isStorybookInstalled( false ) ) { - return ProjectType.ALREADY_HAS_STORYBOOK; + return true; } } return false; @@ -194,9 +194,8 @@ export function detect( return ProjectType.UNDETECTED; } - const storyBookInstalled = isStorybookInstalled(packageJson, options.force); - if (storyBookInstalled) { - return storyBookInstalled; + if (isNxProject(packageJson)) { + return ProjectType.NX; } if (options.html) { @@ -205,3 +204,7 @@ export function detect( return detectFrameworkPreset(packageJson || bowerJson); } + +function isNxProject(packageJSON: PackageJson) { + return !!packageJSON.devDependencies?.nx || fs.existsSync('nx.json'); +} diff --git a/code/lib/cli/src/generators/ANGULAR/helpers.ts b/code/lib/cli/src/generators/ANGULAR/helpers.ts new file mode 100644 index 000000000000..32382f3f6e70 --- /dev/null +++ b/code/lib/cli/src/generators/ANGULAR/helpers.ts @@ -0,0 +1,116 @@ +import fs from 'fs'; +import prompts from 'prompts'; +import dedent from 'ts-dedent'; + +import { commandLog } from '../../helpers'; + +export const ANGULAR_JSON_PATH = 'angular.json'; + +export const compoDocPreviewPrefix = dedent` + import { setCompodocJson } from "@storybook/addon-docs/angular"; + import docJson from "../documentation.json"; + setCompodocJson(docJson); +`.trimStart(); + +export const promptForCompoDocs = async (): Promise => { + const { useCompoDoc } = await prompts({ + type: 'confirm', + name: 'useCompoDoc', + message: 'Do you want to use Compodoc for documentation?', + }); + + return useCompoDoc; +}; + +export class AngularJSON { + json: { + projects: Record }>; + }; + + constructor() { + if (!fs.existsSync(ANGULAR_JSON_PATH)) { + commandLog( + 'An angular.json file was not found in the current directory. Storybook needs it to work properly.' + ); + + throw new Error('No angular.json file found'); + } + + const jsonContent = fs.readFileSync(ANGULAR_JSON_PATH, 'utf8'); + this.json = JSON.parse(jsonContent); + } + + get projects() { + return this.json.projects; + } + + getProjectSettingsByName(projectName: string) { + return this.projects[projectName]; + } + + async getProjectName() { + const projectKeys = Object.keys(this.projects); + + if (projectKeys.length > 1) { + const { projectName } = await prompts({ + type: 'select', + name: 'projectName', + message: 'For which project do you want to generate Storybook configuration?', + choices: projectKeys.map((name) => ({ + title: name, + value: name, + })), + }); + + return projectName; + } + + return Object.keys(this.projects)[0]; + } + + addStorybookEntries({ + angularProjectName, + storybookFolder, + useCompodoc, + root, + }: { + angularProjectName: string; + storybookFolder: string; + useCompodoc: boolean; + root: string; + }) { + // add an entry to the angular.json file to setup the storybook builders + const { architect } = this.projects[angularProjectName]; + + const baseOptions = { + configDir: storybookFolder, + browserTarget: `${angularProjectName}:build`, + compodoc: useCompodoc, + ...(useCompodoc && { compodocArgs: ['-e', 'json', '-d', root || '.'] }), + }; + + if (!architect.storybook) { + architect.storybook = { + builder: '@storybook/angular:start-storybook', + options: { + ...baseOptions, + port: 6006, + }, + }; + } + + if (!architect['build-storybook']) { + architect['build-storybook'] = { + builder: '@storybook/angular:build-storybook', + options: { + ...baseOptions, + outputDir: `dist/storybook/${angularProjectName}`, + }, + }; + } + } + + write() { + fs.writeFileSync(ANGULAR_JSON_PATH, JSON.stringify(this.json, null, 2)); + } +} diff --git a/code/lib/cli/src/generators/ANGULAR/index.ts b/code/lib/cli/src/generators/ANGULAR/index.ts index becad6514b2d..404e094eb5c9 100644 --- a/code/lib/cli/src/generators/ANGULAR/index.ts +++ b/code/lib/cli/src/generators/ANGULAR/index.ts @@ -1,97 +1,108 @@ -import path, { join } from 'path'; +import { join } from 'path'; import semver from 'semver'; -import { - checkForProjects, - editStorybookTsConfig, - getAngularAppTsConfigJson, - getAngularAppTsConfigPath, - getBaseTsConfigName, -} from './angular-helpers'; -import { writeFileAsJson, copyTemplate } from '../../helpers'; -import { getCliDir } from '../../dirs'; +import fs from 'fs'; +import dedent from 'ts-dedent'; import { baseGenerator } from '../baseGenerator'; import type { Generator } from '../types'; import { CoreBuilder } from '../../project_types'; +import { AngularJSON, compoDocPreviewPrefix, promptForCompoDocs } from './helpers'; +import { getCliDir } from '../../dirs'; +import { copyTemplate } from '../../helpers'; +import { isStorybookInstalled } from '../../detect'; -function editAngularAppTsConfig() { - const tsConfigJson = getAngularAppTsConfigJson(); - const glob = '**/*.stories.*'; - if (!tsConfigJson) { - return; - } +const generator: Generator<{ projectName: string }> = async ( + packageManager, + npmOptions, + options, + commandOptions +) => { + const packageJson = packageManager.retrievePackageJson(); + const angularVersion = semver.coerce(packageJson.dependencies['@angular/core'])?.version; + const isWebpack5 = semver.gte(angularVersion, '12.0.0'); + const updatedOptions = isWebpack5 ? { ...options, builder: CoreBuilder.Webpack5 } : options; - const { exclude = [] } = tsConfigJson; - if (exclude.includes(glob)) { - return; - } + const angularJSON = new AngularJSON(); + const angularProjectName = await angularJSON.getProjectName(); + const { root } = angularJSON.getProjectSettingsByName(angularProjectName); + const { projects } = angularJSON; + const useCompodoc = commandOptions.yes ? true : await promptForCompoDocs(); + const storybookFolder = root ? `${root}/.storybook` : '.storybook'; - tsConfigJson.exclude = [...exclude, glob]; - writeFileAsJson(getAngularAppTsConfigPath(), tsConfigJson); -} + if (root !== '') { + // create a .storybook folder in the root of the Angular project + fs.mkdirSync(storybookFolder, { recursive: true }); + const rootReferencePathFromStorybookFolder = root + .split('/') + .map(() => '../') + .join(''); -const generator: Generator = async (packageManager, npmOptions, options) => { - checkForProjects(); + fs.writeFileSync( + `${storybookFolder}/main.js`, + dedent(` + const mainRoot = require('${rootReferencePathFromStorybookFolder}../.storybook/main.js'); + module.exports = { + ...mainRoot + }; + `) + ); - const angularVersion = semver.coerce( - packageManager.retrievePackageJson().dependencies['@angular/core'] - )?.version; - const isWebpack5 = semver.gte(angularVersion, '12.0.0'); - const updatedOptions = isWebpack5 ? { ...options, builder: CoreBuilder.Webpack5 } : options; + fs.writeFileSync( + `${storybookFolder}/tsconfig.json`, + dedent(` + { + "extends": "${rootReferencePathFromStorybookFolder}../.storybook/tsconfig.json", + "exclude": ["../src/test.ts", "../src/**/*.spec.ts"], + "include": ["../src/**/*"] + } + `) + ); + } + + angularJSON.addStorybookEntries({ + angularProjectName, + storybookFolder, + useCompodoc, + root, + }); + angularJSON.write(); + + const isSbInstalled = isStorybookInstalled(packageJson, commandOptions.force); await baseGenerator( packageManager, npmOptions, - updatedOptions, + { + ...updatedOptions, + ...(useCompodoc && { + frameworkPreviewParts: { + prefix: compoDocPreviewPrefix, + }, + }), + }, 'angular', { - extraPackages: ['@compodoc/compodoc'], + ...(useCompodoc && { extraPackages: ['@compodoc/compodoc'] }), addScripts: false, + addComponents: !isSbInstalled, + addMainFile: !isSbInstalled, + storybookConfigFolder: storybookFolder, }, 'angular' ); - const templateDir = join(getCliDir(), 'templates', 'angular'); - copyTemplate(templateDir); - - editAngularAppTsConfig(); - - // TODO: we need to add the following: - - /* - "storybook": { - "builder": "@storybook/angular:start-storybook", - "options": { - "browserTarget": "angular-cli:build", - "port": 4400 - } - }, - "build-storybook": { - "builder": "@storybook/angular:build-storybook", - "options": { - "browserTarget": "angular-cli:build" - } + if (Object.keys(projects).length === 1) { + packageManager.addScripts({ + storybook: `ng run ${angularProjectName}:storybook`, + 'build-storybook': `ng run ${angularProjectName}:build-storybook`, + }); } - */ - // to the user's angular.json file. - - // then we want to add these scripts to package.json - // packageManager.addScripts({ - // storybook: 'ng storybook', - // 'build-storybook': 'ng build-storybook', - // }); - - editStorybookTsConfig(path.resolve('./.storybook/tsconfig.json')); + const templateDir = join(getCliDir(), 'templates', 'angular'); + copyTemplate(templateDir); - // edit scripts to generate docs - const tsConfigFile = await getBaseTsConfigName(); - packageManager.addScripts({ - 'docs:json': `compodoc -p ./${tsConfigFile} -e json -d .`, - }); - packageManager.addStorybookCommandInScripts({ - port: 6006, - preCommand: 'docs:json', - }); + return { + projectName: angularProjectName, + }; }; export default generator; diff --git a/code/lib/cli/src/generators/baseGenerator.ts b/code/lib/cli/src/generators/baseGenerator.ts index bfd1ab8ac3e3..0fb1e0b4185e 100644 --- a/code/lib/cli/src/generators/baseGenerator.ts +++ b/code/lib/cli/src/generators/baseGenerator.ts @@ -17,6 +17,7 @@ const defaultOptions: FrameworkOptions = { extraAddons: [], staticDir: undefined, addScripts: true, + addMainFile: true, addComponents: true, addBabel: false, addESLint: false, @@ -24,6 +25,7 @@ const defaultOptions: FrameworkOptions = { framework: undefined, extensions: undefined, commonJs: false, + storybookConfigFolder: '.storybook', }; const getBuilderDetails = (builder: string) => { @@ -106,7 +108,13 @@ const hasFrameworkTemplates = (framework?: SupportedFrameworks) => export async function baseGenerator( packageManager: JsPackageManager, npmOptions: NpmOptions, - { language, builder = CoreBuilder.Webpack5, pnp, commonJs }: GeneratorOptions, + { + language, + builder = CoreBuilder.Webpack5, + pnp, + commonJs, + frameworkPreviewParts, + }: GeneratorOptions, renderer: SupportedRenderers, options: FrameworkOptions = defaultOptions, framework?: SupportedFrameworks @@ -116,11 +124,13 @@ export async function baseGenerator( extraPackages, staticDir, addScripts, + addMainFile, addComponents, addBabel, addESLint, extraMain, extensions, + storybookConfigFolder, } = { ...defaultOptions, ...options, @@ -194,26 +204,29 @@ export async function baseGenerator( const versionedPackages = await packageManager.getVersionedPackages(packages); - await fse.ensureDir('./.storybook'); + await fse.ensureDir(`./${storybookConfigFolder}`); + + if (addMainFile) { + await configureMain({ + framework: { name: frameworkInclude, options: options.framework || {} }, + storybookConfigFolder, + docs: { autodocs: 'tag' }, + addons: pnp ? addons.map(wrapForPnp) : addons, + extensions, + commonJs, + ...(staticDir ? { staticDirs: [path.join('..', staticDir)] } : null), + ...extraMain, + ...(type !== 'framework' + ? { + core: { + builder: builderInclude, + }, + } + : {}), + }); + } - await configureMain({ - framework: { name: frameworkInclude, options: options.framework || {} }, - docs: { autodocs: 'tag' }, - addons: pnp ? addons.map(wrapForPnp) : addons, - extensions, - commonJs, - ...(staticDir ? { staticDirs: [path.join('..', staticDir)] } : null), - ...extraMain, - ...(type !== 'framework' - ? { - core: { - builder: builderInclude, - }, - } - : {}), - }); - - await configurePreview(rendererId); + await configurePreview({ frameworkPreviewParts, storybookConfigFolder }); // FIXME: temporary workaround for https://github.com/storybookjs/storybook/issues/17516 if ( @@ -226,7 +239,9 @@ export async function baseGenerator( window.global = window; `; - await fse.writeFile(`.storybook/preview-head.html`, previewHead, { encoding: 'utf8' }); + await fse.writeFile(`${storybookConfigFolder}/preview-head.html`, previewHead, { + encoding: 'utf8', + }); } const babelDependencies = diff --git a/code/lib/cli/src/generators/configure.ts b/code/lib/cli/src/generators/configure.ts index fd5a1c40b498..b1f26922f47b 100644 --- a/code/lib/cli/src/generators/configure.ts +++ b/code/lib/cli/src/generators/configure.ts @@ -1,12 +1,12 @@ import fse from 'fs-extra'; import { dedent } from 'ts-dedent'; -import type { SupportedRenderers, SupportedFrameworks } from '../project_types'; interface ConfigureMainOptions { addons: string[]; extensions?: string[]; commonJs?: boolean; staticDirs?: string[]; + storybookConfigFolder: string; /** * Extra values for main.js * @@ -19,10 +19,20 @@ interface ConfigureMainOptions { [key: string]: any; } +export interface FrameworkPreviewParts { + prefix: string; +} + +interface ConfigurePreviewOptions { + frameworkPreviewParts?: FrameworkPreviewParts; + storybookConfigFolder: string; +} + export async function configureMain({ addons, extensions = ['js', 'jsx', 'ts', 'tsx'], commonJs = false, + storybookConfigFolder, ...custom }: ConfigureMainOptions) { const prefix = (await fse.pathExists('./src')) ? '../src' : '../stories'; @@ -44,7 +54,7 @@ export async function configureMain({ // .replaceAll(/"(path\.dirname\(require\.resolve\(path\.join\('.*\))"/g, (_, a) => a)}`; await fse.writeFile( - `./.storybook/main.${commonJs ? 'cjs' : 'js'}`, + `./${storybookConfigFolder}/main.${commonJs ? 'cjs' : 'js'}`, dedent` const path = require('path'); ${stringified} @@ -53,20 +63,9 @@ export async function configureMain({ ); } -const frameworkToPreviewParts: Partial> = { - angular: { - prefix: dedent` - import { setCompodocJson } from "@storybook/addon-docs/angular"; - import docJson from "../documentation.json"; - setCompodocJson(docJson); - - `.trimStart(), - }, -}; - -export async function configurePreview(framework: SupportedFrameworks | SupportedRenderers) { - const { prefix = '', extraParameters = '' } = frameworkToPreviewParts[framework] || {}; - const previewPath = `./.storybook/preview.js`; +export async function configurePreview(options: ConfigurePreviewOptions) { + const { prefix = '' } = options?.frameworkPreviewParts || {}; + const previewPath = `./${options.storybookConfigFolder}/preview.js`; // If the framework template included a preview then we have nothing to do if (await fse.pathExists(previewPath)) { @@ -83,7 +82,6 @@ export async function configurePreview(framework: SupportedFrameworks | Supporte date: /Date$/, }, }, - ${extraParameters} }` .replace(' \n', '') .trim(); diff --git a/code/lib/cli/src/generators/types.ts b/code/lib/cli/src/generators/types.ts index a4685145f75a..4796212e741c 100644 --- a/code/lib/cli/src/generators/types.ts +++ b/code/lib/cli/src/generators/types.ts @@ -2,6 +2,7 @@ import type { NpmOptions } from '../NpmOptions'; import type { SupportedLanguage, Builder, ProjectType } from '../project_types'; import type { JsPackageManager } from '../js-package-manager/JsPackageManager'; import { type PackageManagerName } from '../js-package-manager/JsPackageManager'; +import type { FrameworkPreviewParts } from './configure'; export type GeneratorOptions = { language: SupportedLanguage; @@ -9,6 +10,8 @@ export type GeneratorOptions = { linkable: boolean; pnp: boolean; commonJs: boolean; + storiesRoots: string[]; + frameworkPreviewParts?: FrameworkPreviewParts; }; export interface FrameworkOptions { @@ -16,6 +19,7 @@ export interface FrameworkOptions { extraAddons?: string[]; staticDir?: string; addScripts?: boolean; + addMainFile?: boolean; addComponents?: boolean; addBabel?: boolean; addESLint?: boolean; @@ -23,13 +27,15 @@ export interface FrameworkOptions { extensions?: string[]; framework?: Record; commonJs?: boolean; + storybookConfigFolder?: string; } -export type Generator = ( +export type Generator = ( packageManagerInstance: JsPackageManager, npmOptions: NpmOptions, - generatorOptions: GeneratorOptions -) => Promise; + generatorOptions: GeneratorOptions, + commandOptions?: CommandOptions +) => Promise; export type CommandOptions = { packageManager: PackageManagerName; @@ -40,6 +46,7 @@ export type CommandOptions = { html?: boolean; skipInstall?: boolean; parser?: string; + // Automatically answer yes to prompts yes?: boolean; builder?: Builder; linkable?: boolean; diff --git a/code/lib/cli/src/index.ts b/code/lib/cli/src/index.ts new file mode 100644 index 000000000000..f3dd9e41afa9 --- /dev/null +++ b/code/lib/cli/src/index.ts @@ -0,0 +1 @@ +export * from './js-package-manager'; diff --git a/code/lib/cli/src/initiate.ts b/code/lib/cli/src/initiate.ts index a9741facc52f..cab89c24e3ea 100644 --- a/code/lib/cli/src/initiate.ts +++ b/code/lib/cli/src/initiate.ts @@ -37,11 +37,11 @@ import type { CommandOptions } from './generators/types'; const logger = console; -const installStorybook = ( - projectType: ProjectType, +const installStorybook = ( + projectType: Project, packageManager: JsPackageManager, options: CommandOptions -): Promise => { +): Promise => { const npmOptions: NpmOptions = { installAsDevDependencies: true, skipInstall: options.skipInstall, @@ -64,18 +64,8 @@ const installStorybook = ( pnp: options.usePnp, }; - const runGenerator: () => Promise = async () => { + const runGenerator: () => Promise = async () => { switch (projectType) { - case ProjectType.ALREADY_HAS_STORYBOOK: - logger.log(); - paddedLog('There seems to be a Storybook already available in this project.'); - paddedLog('Apply following command to force:\n'); - codeLog(['sb init [options] -f']); - - // Add a new line for the clear visibility. - logger.log(); - return Promise.resolve(); - case ProjectType.REACT_SCRIPTS: return reactScriptsGenerator(packageManager, npmOptions, generatorOptions).then( commandLog('Adding Storybook support to your "Create React App" based project') @@ -135,9 +125,8 @@ const installStorybook = ( ); case ProjectType.ANGULAR: - return angularGenerator(packageManager, npmOptions, generatorOptions).then( - commandLog('Adding Storybook support to your "Angular" app\n') - ); + commandLog('Adding Storybook support to your "Angular" app\n'); + return angularGenerator(packageManager, npmOptions, generatorOptions, options); case ProjectType.EMBER: return emberGenerator(packageManager, npmOptions, generatorOptions).then( @@ -204,6 +193,13 @@ const installStorybook = ( commandLog('Adding Storybook support to your "Server" app\n') ); + case ProjectType.NX /* NX */: + paddedLog( + 'We have detected Nx in your project. Please use `nx g @nrwl/storybook:configuration` to add Storybook to your project.' + ); + paddedLog('For more information, please see https://nx.dev/packages/storybook'); + return Promise.reject(); + case ProjectType.UNSUPPORTED: paddedLog(`We detected a project type that we don't support yet.`); paddedLog( @@ -296,10 +292,7 @@ async function doInitiate(options: CommandOptions, pkg: PackageJson): Promise { + process.exit(); }); - if (!options.skipInstall) { + if (!options.skipInstall && !storybookInstalled) { packageManager.installDependencies(); } @@ -332,7 +340,13 @@ async function doInitiate(options: CommandOptions, pkg: PackageJson): Promise; - public executeCommand(command: string, args: string[], stdio?: 'pipe' | 'inherit'): string { + public abstract runScript(script: string, args: string[], cwd?: string): string; + + public executeCommand( + command: string, + args: string[], + stdio?: 'pipe' | 'inherit', + cwd?: string + ): string { const commandResult = spawnSync(command, args, { - cwd: this.cwd, + cwd: cwd ?? this.cwd, stdio: stdio ?? 'pipe', encoding: 'utf-8', shell: true, diff --git a/code/lib/cli/src/js-package-manager/NPMProxy.test.ts b/code/lib/cli/src/js-package-manager/NPMProxy.test.ts index 4de3a35fed6d..21a97fdc4d88 100644 --- a/code/lib/cli/src/js-package-manager/NPMProxy.test.ts +++ b/code/lib/cli/src/js-package-manager/NPMProxy.test.ts @@ -57,6 +57,37 @@ describe('NPM Proxy', () => { }); }); + describe('runScript', () => { + describe('npm6', () => { + it('should execute script `npm run compodoc -- -e json -d .`', () => { + const executeCommandSpy = jest.spyOn(npmProxy, 'executeCommand').mockReturnValue('6.0.0'); + + npmProxy.runScript('compodoc', ['-e', 'json', '-d', '.']); + + expect(executeCommandSpy).toHaveBeenLastCalledWith( + 'npm', + ['run', 'compodoc', '--', '-e', 'json', '-d', '.'], + undefined, + undefined + ); + }); + }); + describe('npm7', () => { + it('should execute script `npm run compodoc -- -e json -d .`', () => { + const executeCommandSpy = jest.spyOn(npmProxy, 'executeCommand').mockReturnValue('7.1.0'); + + npmProxy.runScript('compodoc', ['-e', 'json', '-d', '.']); + + expect(executeCommandSpy).toHaveBeenLastCalledWith( + 'npm', + ['run', 'compodoc', '--', '-e', 'json', '-d', '.'], + undefined, + undefined + ); + }); + }); + }); + describe('addDependencies', () => { describe('npm6', () => { it('with devDep it should run `npm install -D @storybook/preview-api`', () => { diff --git a/code/lib/cli/src/js-package-manager/NPMProxy.ts b/code/lib/cli/src/js-package-manager/NPMProxy.ts index 515e254a2ad6..5fb543a1e325 100644 --- a/code/lib/cli/src/js-package-manager/NPMProxy.ts +++ b/code/lib/cli/src/js-package-manager/NPMProxy.ts @@ -38,6 +38,10 @@ export class NPMProxy extends JsPackageManager { return this.uninstallArgs; } + public runScript(command: string, args: string[], cwd?: string): string { + return this.executeCommand(`npm`, ['run', command, '--', ...args], undefined, cwd); + } + protected getResolutions(packageJson: PackageJson, versions: Record) { return { overrides: { diff --git a/code/lib/cli/src/js-package-manager/PNPMProxy.test.ts b/code/lib/cli/src/js-package-manager/PNPMProxy.test.ts index 7d4a03a7b8bc..8336839eb632 100644 --- a/code/lib/cli/src/js-package-manager/PNPMProxy.test.ts +++ b/code/lib/cli/src/js-package-manager/PNPMProxy.test.ts @@ -46,6 +46,21 @@ describe('NPM Proxy', () => { }); }); + describe('runScript', () => { + it('should execute script `yarn compodoc -- -e json -d .`', () => { + const executeCommandSpy = jest.spyOn(pnpmProxy, 'executeCommand').mockReturnValue('7.1.0'); + + pnpmProxy.runScript('compodoc', ['-e', 'json', '-d', '.']); + + expect(executeCommandSpy).toHaveBeenLastCalledWith( + 'pnpm', + ['run', 'compodoc', '-e', 'json', '-d', '.'], + undefined, + undefined + ); + }); + }); + describe('addDependencies', () => { it('with devDep it should run `pnpm add -D @storybook/preview-api`', () => { const executeCommandSpy = jest.spyOn(pnpmProxy, 'executeCommand').mockReturnValue('6.0.0'); diff --git a/code/lib/cli/src/js-package-manager/PNPMProxy.ts b/code/lib/cli/src/js-package-manager/PNPMProxy.ts index cd305b16e673..a288e4f42db7 100644 --- a/code/lib/cli/src/js-package-manager/PNPMProxy.ts +++ b/code/lib/cli/src/js-package-manager/PNPMProxy.ts @@ -24,6 +24,10 @@ export class PNPMProxy extends JsPackageManager { return this.executeCommand('pnpm', ['--version']); } + runScript(command: string, args: string[], cwd?: string): string { + return this.executeCommand(`pnpm`, ['run', command, ...args], undefined, cwd); + } + protected getResolutions(packageJson: PackageJson, versions: Record) { return { overrides: { diff --git a/code/lib/cli/src/js-package-manager/Yarn1Proxy.test.ts b/code/lib/cli/src/js-package-manager/Yarn1Proxy.test.ts index 7d8fd5ad11e6..26674f0aac59 100644 --- a/code/lib/cli/src/js-package-manager/Yarn1Proxy.test.ts +++ b/code/lib/cli/src/js-package-manager/Yarn1Proxy.test.ts @@ -46,6 +46,21 @@ describe('Yarn 1 Proxy', () => { }); }); + describe('runScript', () => { + it('should execute script `yarn compodoc -- -e json -d .`', () => { + const executeCommandSpy = jest.spyOn(yarn1Proxy, 'executeCommand').mockReturnValue('7.1.0'); + + yarn1Proxy.runScript('compodoc', ['-e', 'json', '-d', '.']); + + expect(executeCommandSpy).toHaveBeenLastCalledWith( + 'yarn', + ['compodoc', '-e', 'json', '-d', '.'], + undefined, + undefined + ); + }); + }); + describe('addDependencies', () => { it('with devDep it should run `yarn install -D --ignore-workspace-root-check @storybook/preview-api`', () => { const executeCommandSpy = jest.spyOn(yarn1Proxy, 'executeCommand').mockReturnValue(''); diff --git a/code/lib/cli/src/js-package-manager/Yarn1Proxy.ts b/code/lib/cli/src/js-package-manager/Yarn1Proxy.ts index 789499084c85..75d980675d3f 100644 --- a/code/lib/cli/src/js-package-manager/Yarn1Proxy.ts +++ b/code/lib/cli/src/js-package-manager/Yarn1Proxy.ts @@ -16,6 +16,10 @@ export class Yarn1Proxy extends JsPackageManager { return `yarn ${command}`; } + runScript(command: string, args: string[], cwd?: string): string { + return this.executeCommand(`yarn`, [command, ...args], undefined, cwd); + } + protected getResolutions(packageJson: PackageJson, versions: Record) { return { resolutions: { diff --git a/code/lib/cli/src/js-package-manager/Yarn2Proxy.test.ts b/code/lib/cli/src/js-package-manager/Yarn2Proxy.test.ts index 8c7cb184f431..badeddd2cfcb 100644 --- a/code/lib/cli/src/js-package-manager/Yarn2Proxy.test.ts +++ b/code/lib/cli/src/js-package-manager/Yarn2Proxy.test.ts @@ -31,6 +31,21 @@ describe('Yarn 2 Proxy', () => { }); }); + describe('runScript', () => { + it('should execute script `yarn compodoc -- -e json -d .`', () => { + const executeCommandSpy = jest.spyOn(yarn2Proxy, 'executeCommand').mockReturnValue('7.1.0'); + + yarn2Proxy.runScript('compodoc', ['-e', 'json', '-d', '.']); + + expect(executeCommandSpy).toHaveBeenLastCalledWith( + 'yarn', + ['compodoc', '-e', 'json', '-d', '.'], + undefined, + undefined + ); + }); + }); + describe('setRegistryUrl', () => { it('should run `yarn config set npmRegistryServer https://foo.bar`', () => { const executeCommandSpy = jest.spyOn(yarn2Proxy, 'executeCommand').mockReturnValue(''); diff --git a/code/lib/cli/src/js-package-manager/Yarn2Proxy.ts b/code/lib/cli/src/js-package-manager/Yarn2Proxy.ts index 63c1bf07c87a..e77868600c88 100644 --- a/code/lib/cli/src/js-package-manager/Yarn2Proxy.ts +++ b/code/lib/cli/src/js-package-manager/Yarn2Proxy.ts @@ -17,6 +17,10 @@ export class Yarn2Proxy extends JsPackageManager { return `yarn ${command}`; } + runScript(command: string, args: string[], cwd?: string): string { + return this.executeCommand(`yarn`, [command, ...args], undefined, cwd); + } + protected getResolutions(packageJson: PackageJson, versions: Record) { return { resolutions: { diff --git a/code/lib/cli/src/project_types.ts b/code/lib/cli/src/project_types.ts index 5de0f9c3812d..47f1d99e6102 100644 --- a/code/lib/cli/src/project_types.ts +++ b/code/lib/cli/src/project_types.ts @@ -69,7 +69,6 @@ export enum ProjectType { SFC_VUE = 'SFC_VUE', ANGULAR = 'ANGULAR', EMBER = 'EMBER', - ALREADY_HAS_STORYBOOK = 'ALREADY_HAS_STORYBOOK', WEB_COMPONENTS = 'WEB_COMPONENTS', MITHRIL = 'MITHRIL', MARIONETTE = 'MARIONETTE', @@ -82,6 +81,7 @@ export enum ProjectType { RAX = 'RAX', AURELIA = 'AURELIA', SERVER = 'SERVER', + NX = 'NX', } export enum CoreBuilder { @@ -192,20 +192,6 @@ export const supportedTemplates: TemplateConfiguration[] = [ return dependencies.every(Boolean) || files.every(Boolean); }, }, - { - preset: ProjectType.WEBPACK_REACT, - dependencies: ['react', 'webpack'], - matcherFunction: ({ dependencies }) => { - return dependencies.every(Boolean); - }, - }, - { - preset: ProjectType.REACT, - dependencies: ['react'], - matcherFunction: ({ dependencies }) => { - return dependencies.every(Boolean); - }, - }, { preset: ProjectType.ANGULAR, dependencies: ['@angular/core'], @@ -284,6 +270,22 @@ export const supportedTemplates: TemplateConfiguration[] = [ return dependencies.every(Boolean); }, }, + // DO NOT MOVE ANY TEMPLATES BELOW THIS LINE + // React is part of every Template, after Storybook is initialized once + { + preset: ProjectType.WEBPACK_REACT, + dependencies: ['react', 'webpack'], + matcherFunction: ({ dependencies }) => { + return dependencies.every(Boolean); + }, + }, + { + preset: ProjectType.REACT, + dependencies: ['react'], + matcherFunction: ({ dependencies }) => { + return dependencies.every(Boolean); + }, + }, ]; // A TemplateConfiguration that matches unsupported frameworks @@ -300,11 +302,7 @@ export const unsupportedTemplate: TemplateConfiguration = { }, }; -const notInstallableProjectTypes: ProjectType[] = [ - ProjectType.UNDETECTED, - ProjectType.UNSUPPORTED, - ProjectType.ALREADY_HAS_STORYBOOK, -]; +const notInstallableProjectTypes: ProjectType[] = [ProjectType.UNDETECTED, ProjectType.UNSUPPORTED]; export const installableProjectTypes = Object.values(ProjectType) .filter((type) => !notInstallableProjectTypes.includes(type)) diff --git a/code/lib/cli/templates/angular/template-csf/.storybook/tsconfig.json b/code/lib/cli/templates/angular/template-csf/.storybook/tsconfig.json index b1e810022ba0..2243e0894a86 100644 --- a/code/lib/cli/templates/angular/template-csf/.storybook/tsconfig.json +++ b/code/lib/cli/templates/angular/template-csf/.storybook/tsconfig.json @@ -1,10 +1,10 @@ { - "extends": "%SET_DURING_SB_INIT%", + "extends": "../tsconfig.app.json", "compilerOptions": { "types": ["node"], "allowSyntheticDefaultImports": true }, - "exclude": ["../src/test.ts", "../src/**/*.spec.ts", "../projects/**/*.spec.ts"], - "include": ["../src/**/*", "../projects/**/*"], + "exclude": ["../src/test.ts", "../src/**/*.spec.ts"], + "include": ["../src/**/*"], "files": ["./typings.d.ts"] } diff --git a/code/lib/core-server/src/build-dev.ts b/code/lib/core-server/src/build-dev.ts index 616433dae110..c1a4e4693be7 100644 --- a/code/lib/core-server/src/build-dev.ts +++ b/code/lib/core-server/src/build-dev.ts @@ -156,21 +156,24 @@ export async function buildDevStandalone(options: CLIOptions & LoadOptions & Bui // eslint-disable-next-line no-console console.log(problems.map((p) => p.stack)); process.exit(problems.length > 0 ? 1 : 0); - return; + } else { + const name = + frameworkName.split('@storybook/').length > 1 + ? frameworkName.split('@storybook/')[1] + : frameworkName; + + outputStartupInformation({ + updateInfo: versionCheck, + version, + name, + address, + networkAddress, + managerTotalTime, + previewTotalTime, + }); } - const name = - frameworkName.split('@storybook/').length > 1 - ? frameworkName.split('@storybook/')[1] - : frameworkName; - - outputStartupInformation({ - updateInfo: versionCheck, - version, - name, - address, - networkAddress, - managerTotalTime, - previewTotalTime, - }); + return { + port, + }; } diff --git a/code/yarn.lock b/code/yarn.lock index 8a0620167095..9211e650ebc8 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -29,7 +29,17 @@ __metadata: languageName: node linkType: hard -"@angular-devkit/architect@npm:0.1500.5, @angular-devkit/architect@npm:^0.1500.4": +"@angular-devkit/architect@npm:0.1500.4": + version: 0.1500.4 + resolution: "@angular-devkit/architect@npm:0.1500.4" + dependencies: + "@angular-devkit/core": 15.0.4 + rxjs: 6.6.7 + checksum: b6be2ddc3b656cdb86e147238501e6cc00254d9ee711f0dd9c3ae384c1faea84774dcc0b1c11dea489828307e04e081beb0045f12d4d0a879aecabb39d492584 + languageName: node + linkType: hard + +"@angular-devkit/architect@npm:^0.1500.4": version: 0.1500.5 resolution: "@angular-devkit/architect@npm:0.1500.5" dependencies: @@ -40,13 +50,13 @@ __metadata: linkType: hard "@angular-devkit/build-angular@npm:^15.0.4": - version: 15.0.5 - resolution: "@angular-devkit/build-angular@npm:15.0.5" + version: 15.0.4 + resolution: "@angular-devkit/build-angular@npm:15.0.4" dependencies: "@ampproject/remapping": 2.2.0 - "@angular-devkit/architect": 0.1500.5 - "@angular-devkit/build-webpack": 0.1500.5 - "@angular-devkit/core": 15.0.5 + "@angular-devkit/architect": 0.1500.4 + "@angular-devkit/build-webpack": 0.1500.4 + "@angular-devkit/core": 15.0.4 "@babel/core": 7.20.2 "@babel/generator": 7.20.4 "@babel/helper-annotate-as-pure": 7.18.6 @@ -57,7 +67,7 @@ __metadata: "@babel/runtime": 7.20.1 "@babel/template": 7.18.10 "@discoveryjs/json-ext": 0.5.7 - "@ngtools/webpack": 15.0.5 + "@ngtools/webpack": 15.0.4 ansi-colors: 4.1.3 autoprefixer: 10.4.13 babel-loader: 9.1.0 @@ -131,20 +141,20 @@ __metadata: optional: true tailwindcss: optional: true - checksum: 067685257b42f89ba6407846b3cac2ed28aad91541cb6cefdd55e29e6d0bc844321013bb2b47cbfe0b06495cd54e568f355ebf56ef7635301a8379be5bd68771 + checksum: 2c3e835bbac7715d1cf1cb1e27af6f09ad1e8eeb389e18282e0991751e4902c05d017c9d5d836ef2e0f38cfc6540a7ef72d8ed12962d1138c8ebc7f7fee8ac20 languageName: node linkType: hard -"@angular-devkit/build-webpack@npm:0.1500.5": - version: 0.1500.5 - resolution: "@angular-devkit/build-webpack@npm:0.1500.5" +"@angular-devkit/build-webpack@npm:0.1500.4": + version: 0.1500.4 + resolution: "@angular-devkit/build-webpack@npm:0.1500.4" dependencies: - "@angular-devkit/architect": 0.1500.5 + "@angular-devkit/architect": 0.1500.4 rxjs: 6.6.7 peerDependencies: webpack: ^5.30.0 webpack-dev-server: ^4.0.0 - checksum: 06438ae79c1fcebbb170a5ec27c3946dfa4f4cd8ed80588deeefc54ab4550b2d779119eb7949e1477c44c3e29e8ca85369cb430c2833295b4823495a4c725052 + checksum: 5aeb788acbed900c9fa2985d178ba1248e842fd175a5f1e2f4ef5a833e812e7cb0ddc7344fe2b208e0f58ad15c9db4fc8ff6fc9408973df992478cbd84df2250 languageName: node linkType: hard @@ -167,6 +177,24 @@ __metadata: languageName: node linkType: hard +"@angular-devkit/core@npm:15.0.4": + version: 15.0.4 + resolution: "@angular-devkit/core@npm:15.0.4" + dependencies: + ajv: 8.11.0 + ajv-formats: 2.1.1 + jsonc-parser: 3.2.0 + rxjs: 6.6.7 + source-map: 0.7.4 + peerDependencies: + chokidar: ^3.5.2 + peerDependenciesMeta: + chokidar: + optional: true + checksum: 428a20d96e237d24a62ae3d5284e3140f906e212883e094cc64ec622a5065234f001bd21f9608ad2478088c1cc40aadf48bd53c399ad02be0c98b61d27d3ba11 + languageName: node + linkType: hard + "@angular-devkit/core@npm:15.0.5, @angular-devkit/core@npm:^15.0.4": version: 15.0.5 resolution: "@angular-devkit/core@npm:15.0.5" @@ -185,16 +213,16 @@ __metadata: languageName: node linkType: hard -"@angular-devkit/schematics@npm:15.0.5": - version: 15.0.5 - resolution: "@angular-devkit/schematics@npm:15.0.5" +"@angular-devkit/schematics@npm:15.0.4": + version: 15.0.4 + resolution: "@angular-devkit/schematics@npm:15.0.4" dependencies: - "@angular-devkit/core": 15.0.5 + "@angular-devkit/core": 15.0.4 jsonc-parser: 3.2.0 magic-string: 0.26.7 ora: 5.4.1 rxjs: 6.6.7 - checksum: c008f7dcb0c722b7a7f7a2a4b69c45cf75ac0a7c0c8fbdb44453bd930ddca9692965a7d6de276201d78d10c5e1c6a04fe494f7cdfbdcd51b13186543e159e8c0 + checksum: b53397b5770987bc98f697bcde56cef23b0958e4ebcdf7713c7ba8c56295869a069259fdbb480495e9ee79dae342ce88b27b64f518eeb974a38c981c4602f726 languageName: node linkType: hard @@ -212,13 +240,13 @@ __metadata: linkType: hard "@angular/cli@npm:^15.0.4": - version: 15.0.5 - resolution: "@angular/cli@npm:15.0.5" + version: 15.0.4 + resolution: "@angular/cli@npm:15.0.4" dependencies: - "@angular-devkit/architect": 0.1500.5 - "@angular-devkit/core": 15.0.5 - "@angular-devkit/schematics": 15.0.5 - "@schematics/angular": 15.0.5 + "@angular-devkit/architect": 0.1500.4 + "@angular-devkit/core": 15.0.4 + "@angular-devkit/schematics": 15.0.4 + "@schematics/angular": 15.0.4 "@yarnpkg/lockfile": 1.1.0 ansi-colors: 4.1.3 ini: 3.0.1 @@ -235,7 +263,7 @@ __metadata: yargs: 17.6.2 bin: ng: bin/ng.js - checksum: 7cb92b2f0ed2f1dea4b3c44e6cefe4ebb6e04cfb98c622daf4815888645c00bdd0d5acf1e4a12ee9a122ccc2b55864aedeabe88aeedcd83d2a33d39a27be86a2 + checksum: 1443a089fd99b47ddfe53a9ebcbd10a56357a43bdb25597f0dd6e540508bea9fd74e3b640969b2c5d1eba346fd189426bc355109e2a1fedffa76702f4b8aabb5 languageName: node linkType: hard @@ -1314,13 +1342,13 @@ __metadata: linkType: hard "@babel/plugin-transform-block-scoping@npm:^7.20.2, @babel/plugin-transform-block-scoping@npm:^7.8.3": - version: 7.20.11 - resolution: "@babel/plugin-transform-block-scoping@npm:7.20.11" + version: 7.20.8 + resolution: "@babel/plugin-transform-block-scoping@npm:7.20.8" dependencies: "@babel/helper-plugin-utils": ^7.20.2 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 3840c342c5ef6c53c750bf3801c30b3770b016516b4589d164e227688ed2dd0aa86496ac340b0735b9fa0cee30ff5338f1e291b2a91df5cce17e585298674e8b + checksum: 6c324f45b889e1de02f1f60b748d2de3b71dc90b9b2075e38f008e7363825fad1a4894bda8bd2eb632f68e351e11451ed86b5e97b081ed90a30390585675b27f languageName: node linkType: hard @@ -1460,33 +1488,33 @@ __metadata: linkType: hard "@babel/plugin-transform-modules-amd@npm:^7.13.0, @babel/plugin-transform-modules-amd@npm:^7.19.6": - version: 7.20.11 - resolution: "@babel/plugin-transform-modules-amd@npm:7.20.11" + version: 7.20.7 + resolution: "@babel/plugin-transform-modules-amd@npm:7.20.7" dependencies: "@babel/helper-module-transforms": ^7.20.11 "@babel/helper-plugin-utils": ^7.20.2 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 327077cc746d2ef14d0792a970058d9b7170ff480c1d1d7acf874ef7cfeae0c680e86a45896ea27066e9ebdd82dc2be09d321385eef1e0b4255659d75ea2e008 + checksum: 85973356d2183711ebe3338899d726070ea4f06c9fccdd2808d80337a791935b409605e4c610660a159bb4d495332d2e33b387c0384c165f898fe0107c1ddb88 languageName: node linkType: hard "@babel/plugin-transform-modules-commonjs@npm:^7.13.8, @babel/plugin-transform-modules-commonjs@npm:^7.19.6, @babel/plugin-transform-modules-commonjs@npm:^7.2.0": - version: 7.20.11 - resolution: "@babel/plugin-transform-modules-commonjs@npm:7.20.11" + version: 7.20.7 + resolution: "@babel/plugin-transform-modules-commonjs@npm:7.20.7" dependencies: "@babel/helper-module-transforms": ^7.20.11 "@babel/helper-plugin-utils": ^7.20.2 "@babel/helper-simple-access": ^7.20.2 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: f3a3281c252a978255076ff7274e4ac1ec252e0db4b3d73122c278ce9fd8318179fc804638ce726870146fa0845e2559711453ce7a391dc2a792d96dc0f6b04c + checksum: 57024919a30796a4b087e78a9ac14d31a6ba43c6fdd38f55e1fce25a932e660f4b898037480f9b4dc73faae2f2846b0faa73697a0819e0382f58759ff6b3f732 languageName: node linkType: hard "@babel/plugin-transform-modules-systemjs@npm:^7.19.6": - version: 7.20.11 - resolution: "@babel/plugin-transform-modules-systemjs@npm:7.20.11" + version: 7.19.6 + resolution: "@babel/plugin-transform-modules-systemjs@npm:7.19.6" dependencies: "@babel/helper-hoist-variables": ^7.18.6 "@babel/helper-module-transforms": ^7.20.11 @@ -1494,7 +1522,7 @@ __metadata: "@babel/helper-validator-identifier": ^7.19.1 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 1843b2044b711765581d6130ea7901afde6e6f5af4e4219ab675033a090f4dacb6656bfada8f211a2cd9bbae256c7f4bd0b8613b750e56674feee5252de1ad76 + checksum: 0f05058170f1d2027bda95ae8d57b021698f4d7f33df859c95db072ae80941079c5049ac12bde3bc87311436e9451e5edca8205754e9a4e5b54bd6e4f3ecf2ed languageName: node linkType: hard @@ -2035,7 +2063,25 @@ __metadata: languageName: node linkType: hard -"@babel/traverse@npm:^7.1.6, @babel/traverse@npm:^7.20.1, @babel/traverse@npm:^7.20.10, @babel/traverse@npm:^7.20.12, @babel/traverse@npm:^7.20.5, @babel/traverse@npm:^7.20.7, @babel/traverse@npm:^7.4.5, @babel/traverse@npm:^7.7.0, @babel/traverse@npm:^7.7.2, @babel/traverse@npm:^7.8.6": +"@babel/traverse@npm:^7.1.6, @babel/traverse@npm:^7.20.1, @babel/traverse@npm:^7.20.5, @babel/traverse@npm:^7.4.5, @babel/traverse@npm:^7.7.0, @babel/traverse@npm:^7.7.2, @babel/traverse@npm:^7.8.6": + version: 7.20.8 + resolution: "@babel/traverse@npm:7.20.8" + dependencies: + "@babel/code-frame": ^7.18.6 + "@babel/generator": ^7.20.7 + "@babel/helper-environment-visitor": ^7.18.9 + "@babel/helper-function-name": ^7.19.0 + "@babel/helper-hoist-variables": ^7.18.6 + "@babel/helper-split-export-declaration": ^7.18.6 + "@babel/parser": ^7.20.7 + "@babel/types": ^7.20.7 + debug: ^4.1.0 + globals: ^11.1.0 + checksum: aef74e2b334b5c92a224dbe68357ba2383d43804fb7a5c6e76ca477d6640ddd3f428280687fdd413d6729a00d3f61f6ba86acd91a18d75126e107d9db91f008c + languageName: node + linkType: hard + +"@babel/traverse@npm:^7.20.10, @babel/traverse@npm:^7.20.12": version: 7.20.12 resolution: "@babel/traverse@npm:7.20.12" dependencies: @@ -2053,6 +2099,24 @@ __metadata: languageName: node linkType: hard +"@babel/traverse@npm:^7.20.7": + version: 7.20.10 + resolution: "@babel/traverse@npm:7.20.10" + dependencies: + "@babel/code-frame": ^7.18.6 + "@babel/generator": ^7.20.7 + "@babel/helper-environment-visitor": ^7.18.9 + "@babel/helper-function-name": ^7.19.0 + "@babel/helper-hoist-variables": ^7.18.6 + "@babel/helper-split-export-declaration": ^7.18.6 + "@babel/parser": ^7.20.7 + "@babel/types": ^7.20.7 + debug: ^4.1.0 + globals: ^11.1.0 + checksum: a712402374c2e1cdd7e7880deda0f0051123c09abc9a110e4594bf90c858211e678185b927dffe8780de981ff87ac98bcffdc3fbf46c262bd21b6d64cd1d3b58 + languageName: node + linkType: hard + "@babel/types@npm:^7.0.0, @babel/types@npm:^7.11.5, @babel/types@npm:^7.18.10, @babel/types@npm:^7.18.6, @babel/types@npm:^7.18.8, @babel/types@npm:^7.18.9, @babel/types@npm:^7.19.0, @babel/types@npm:^7.2.0, @babel/types@npm:^7.20.0, @babel/types@npm:^7.20.2, @babel/types@npm:^7.20.5, @babel/types@npm:^7.20.7, @babel/types@npm:^7.3.0, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.6.1, @babel/types@npm:^7.7.0, @babel/types@npm:^7.7.2, @babel/types@npm:^7.8.3, @babel/types@npm:^7.8.6, @babel/types@npm:^7.8.7, @babel/types@npm:^7.9.6": version: 7.20.7 resolution: "@babel/types@npm:7.20.7" @@ -4429,14 +4493,14 @@ __metadata: languageName: node linkType: hard -"@ngtools/webpack@npm:15.0.5": - version: 15.0.5 - resolution: "@ngtools/webpack@npm:15.0.5" +"@ngtools/webpack@npm:15.0.4": + version: 15.0.4 + resolution: "@ngtools/webpack@npm:15.0.4" peerDependencies: "@angular/compiler-cli": ^15.0.0 typescript: ~4.8.2 webpack: ^5.54.0 - checksum: 8314dbba50bdbbc396baad9408c99aa56230de833e32398821f4b7c03f9db87d03fafbc1c098780172b42e92f71c0b86a6e25b0c1acba79037d14872108f125d + checksum: 978fa56a13a86974d678c57344a5e4390cddf29fadb4adb1e1012210b77c4c91a581af9d2488f164258ce6a03918b60585c3c559523bf6c6a2bf415c11990c07 languageName: node linkType: hard @@ -5144,14 +5208,14 @@ __metadata: languageName: node linkType: hard -"@schematics/angular@npm:15.0.5": - version: 15.0.5 - resolution: "@schematics/angular@npm:15.0.5" +"@schematics/angular@npm:15.0.4": + version: 15.0.4 + resolution: "@schematics/angular@npm:15.0.4" dependencies: - "@angular-devkit/core": 15.0.5 - "@angular-devkit/schematics": 15.0.5 + "@angular-devkit/core": 15.0.4 + "@angular-devkit/schematics": 15.0.4 jsonc-parser: 3.2.0 - checksum: 1c978e1fde5b4028be4e5a2a632f32c8b1330bb85d27b1bf80cb62515905a77bf36bce224691c9a9b1d002c7bbf2352993181dd0c7f3eee6348ea933ec9cf991 + checksum: 4b5475acaeddb31d424e3911014d12e85bf75caff267c2d9038e967ce7f3cff2d172fef63a88e3f40bbb9cf4f071d7a1fcbc2745f9ec432c5e5b96128924b576 languageName: node linkType: hard @@ -12354,9 +12418,9 @@ __metadata: linkType: hard "caniuse-lite@npm:^1.0.30001400, caniuse-lite@npm:^1.0.30001406, caniuse-lite@npm:^1.0.30001426": - version: 1.0.30001442 - resolution: "caniuse-lite@npm:1.0.30001442" - checksum: 02d10a1d6a83cc88771a42ea5aa0c98f5768180c69badeec2bf40d269bbcbd0239a3c197af5e5dce51d0bd5d04e069394cbe611f489082c8244ab95f597e1842 + version: 1.0.30001441 + resolution: "caniuse-lite@npm:1.0.30001441" + checksum: 4b91bfc03cdbb9cf54225bbc36c2c568879d05ff8f2a34bdafbd7e5acc578d913b2d169bab4bf8a0992678e308779cd5603be0928d6552acefebfc52ded73aa1 languageName: node linkType: hard @@ -13393,11 +13457,11 @@ __metadata: linkType: hard "core-js-compat@npm:^3.25.1": - version: 3.27.1 - resolution: "core-js-compat@npm:3.27.1" + version: 3.26.1 + resolution: "core-js-compat@npm:3.26.1" dependencies: browserslist: ^4.21.4 - checksum: 635ffcc3f40ca4cb45b10ea805ebf57bbba69873014c89bec96ae09f15cbd3012bd5102bdf87551ef2f1c629e279837632200c4888428035cf822f6e40dc383b + checksum: 2d798049758900a7fd83958e02d1d46d35157dbaa6f916c358f735bfe3095cdf5b54dc999363e654445a94417005eb548b9acc47e1d18eda3d1a43cf05b350a5 languageName: node linkType: hard @@ -23034,7 +23098,7 @@ __metadata: languageName: node linkType: hard -"memfs@npm:^3.4.1, memfs@npm:^3.4.12, memfs@npm:^3.4.3": +"memfs@npm:^3.4.1, memfs@npm:^3.4.3": version: 3.4.12 resolution: "memfs@npm:3.4.12" dependencies: @@ -32685,22 +32749,7 @@ __metadata: languageName: node linkType: hard -"webpack-dev-middleware@npm:*": - version: 6.0.1 - resolution: "webpack-dev-middleware@npm:6.0.1" - dependencies: - colorette: ^2.0.10 - memfs: ^3.4.12 - mime-types: ^2.1.31 - range-parser: ^1.2.1 - schema-utils: ^4.0.0 - peerDependencies: - webpack: ^5.0.0 - checksum: ec095392a0fd97663a5a36a86f8bff898983aa0dfcfc8d16c918a745ae31cfc74a127946d998b4f583972647f8370d43296d2c665f09379182a26ebadaf6c50e - languageName: node - linkType: hard - -"webpack-dev-middleware@npm:5.3.3, webpack-dev-middleware@npm:^5.3.1": +"webpack-dev-middleware@npm:*, webpack-dev-middleware@npm:5.3.3, webpack-dev-middleware@npm:^5.3.1": version: 5.3.3 resolution: "webpack-dev-middleware@npm:5.3.3" dependencies: diff --git a/docs/get-started/installation-command-section/angular.mdx b/docs/get-started/installation-command-section/angular.mdx index 33024a1d6619..806df6d06a57 100644 --- a/docs/get-started/installation-command-section/angular.mdx +++ b/docs/get-started/installation-command-section/angular.mdx @@ -5,24 +5,4 @@ npx storybook init ``` -- Update your `angular.json` file to include Storybook's custom builder: - -```json -{ - "storybook": { - "builder": "@storybook/angular:start-storybook", - "options": { - "browserTarget": "angular-cli:build", - "port": 6006 - } - }, - "build-storybook": { - "builder": "@storybook/angular:build-storybook", - "options": { - "browserTarget": "angular-cli:build" - } - } -} -``` - If you run into issues with the installation, check the [Troubleshooting section](#troubleshooting) below for guidance on how to solve it. \ No newline at end of file diff --git a/scripts/utils/package-json.ts b/scripts/utils/package-json.ts index 6b5822e35224..35a98f0c5872 100644 --- a/scripts/utils/package-json.ts +++ b/scripts/utils/package-json.ts @@ -1,20 +1,15 @@ import { readJSON, writeJSON } from 'fs-extra'; import { join } from 'path'; -const logger = console; - export async function updatePackageScripts({ cwd, prefix }: { cwd: string; prefix: string }) { - logger.info(`🔢 Adding package scripts:`); const packageJsonPath = join(cwd, 'package.json'); const packageJson = await readJSON(packageJsonPath); packageJson.scripts = { ...packageJson.scripts, - storybook: packageJson.scripts.storybook.replace(/(npx )?storybook/, `${prefix} storybook`), - 'build-storybook': packageJson.scripts['build-storybook'].replace( - /(npx )?storybook/, - `${prefix} storybook` - ), - + ...(packageJson.scripts.storybook && { + storybook: `${prefix} ${packageJson.scripts.storybook}`, + 'build-storybook': `${prefix} ${packageJson.scripts['build-storybook']}`, + }), // See comment in combine-compodoc as to why this is necessary ...(packageJson.scripts['docs:json'] && { 'docs:json': 'DIR=$PWD; cd ../../scripts; yarn ts-node combine-compodoc $DIR',