Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/next' into valentin/introduce-in…
Browse files Browse the repository at this point in the history
…stances-vitest-3
  • Loading branch information
valentinpalkovic committed Jan 20, 2025
2 parents c4c2463 + f3c87f1 commit 678fb8f
Show file tree
Hide file tree
Showing 17 changed files with 3,986 additions and 1,420 deletions.
37 changes: 34 additions & 3 deletions MIGRATION.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<h1>Migration</h1>

- [From version 8.4.x to 8.5.x](#from-version-84x-to-85x)
- [Introducing features.developmentModeForBuild](#introducing-featuresdevelopmentmodeforbuild)
- [From version 8.5.x to 8.6.x](#from-version-85x-to-86x)
- [Angular: Support experimental zoneless support](#angular-support-experimental-zoneless-support)
- [Added source code panel to docs](#added-source-code-panel-to-docs)
- [Addon-a11y: Component test integration](#addon-a11y-component-test-integration)
- [Addon-a11y: Changing the default element selector](#addon-a11y-changing-the-default-element-selector)
Expand Down Expand Up @@ -427,6 +427,37 @@
- [Packages renaming](#packages-renaming)
- [Deprecated embedded addons](#deprecated-embedded-addons)

## From version 8.5.x to 8.6.x

### Angular: Support experimental zoneless support

Storybook now supports [Angular's experimental zoneless mode](https://angular.dev/guide/experimental/zoneless). This mode is intended to improve performance by removing Angular's zone.js dependency. To enable zoneless mode in your Angular Storybook, set the `experimentalZoneless` config in your `angular.json` file:

````diff
{
"projects": {
"your-project": {
"architect": {
"storybook": {
...
"options": {
...
+ "experimentalZoneless": true
}
}
"build-storybook": {
...
"options": {
...
+ "experimentalZoneless": true
}
}
}
}
}
}
```

## From version 8.4.x to 8.5.x

### Introducing features.developmentModeForBuild
Expand All @@ -442,7 +473,7 @@ export default {
developmentModeForBuild: true,
},
};
```
````

### Added source code panel to docs

Expand Down
32 changes: 18 additions & 14 deletions code/frameworks/angular/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,27 +58,28 @@
"webpack": "5"
},
"devDependencies": {
"@analogjs/vite-plugin-angular": "^0.2.24",
"@angular-devkit/architect": "^0.1703.0",
"@angular-devkit/build-angular": "^17.3.0",
"@angular-devkit/core": "^17.3.0",
"@angular/animations": "^17.3.0",
"@angular/cli": "^17.3.0",
"@angular/common": "^17.3.0",
"@angular/compiler": "^17.3.0",
"@angular/compiler-cli": "^17.3.0",
"@angular/core": "^17.3.0",
"@angular/forms": "^17.3.0",
"@angular/platform-browser": "^17.3.0",
"@angular/platform-browser-dynamic": "^17.3.0",
"@analogjs/vite-plugin-angular": "^1.12.1",
"@angular-devkit/architect": "^0.1901.1",
"@angular-devkit/build-angular": "^19.1.1",
"@angular-devkit/core": "^19.1.1",
"@angular/animations": "^19.1.1",
"@angular/cli": "^19.1.1",
"@angular/common": "^19.1.1",
"@angular/compiler": "^19.1.1",
"@angular/compiler-cli": "^19.1.1",
"@angular/core": "^19.1.1",
"@angular/forms": "^19.1.1",
"@angular/platform-browser": "^19.1.1",
"@angular/platform-browser-dynamic": "^19.1.1",
"@types/cross-spawn": "^6.0.2",
"@types/node": "^22.0.0",
"@types/tmp": "^0.2.3",
"cross-spawn": "^7.0.3",
"rimraf": "^6.0.1",
"tmp": "^0.2.1",
"typescript": "^5.3.2",
"webpack": "5",
"zone.js": "^0.14.2"
"zone.js": "^0.15.0"
},
"peerDependencies": {
"@angular-devkit/architect": ">=0.1500.0 < 0.2000.0",
Expand All @@ -100,6 +101,9 @@
"peerDependenciesMeta": {
"@angular/cli": {
"optional": true
},
"zone.js": {
"optional": true
}
},
"engines": {
Expand Down
3 changes: 3 additions & 0 deletions code/frameworks/angular/src/builders/build-storybook/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export type StorybookBuilderOptions = JsonObject & {
preserveSymlinks?: boolean;
assets?: AssetPattern[];
sourceMap?: SourceMapUnion;
experimentalZoneless?: boolean;
} & Pick<
// makes sure the option exists
CLIOptions,
Expand Down Expand Up @@ -104,6 +105,7 @@ const commandBuilder: BuilderHandlerFn<StorybookBuilderOptions> = (
previewUrl,
sourceMap = false,
preserveSymlinks = false,
experimentalZoneless = false,
} = options;

const standaloneOptions: StandaloneBuildOptions = {
Expand All @@ -124,6 +126,7 @@ const commandBuilder: BuilderHandlerFn<StorybookBuilderOptions> = (
...(assets ? { assets } : {}),
sourceMap,
preserveSymlinks,
experimentalZoneless,
},
tsConfig,
webpackStatsJson,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,11 @@
"type": ["boolean", "object"],
"description": "Configure sourcemaps. See: https://angular.io/guide/workspace-config#source-map-configuration",
"default": false
},
"experimentalZoneless": {
"type": "boolean",
"description": "Experimental: Use zoneless change detection.",
"default": false
}
},
"additionalProperties": false,
Expand Down
3 changes: 3 additions & 0 deletions code/frameworks/angular/src/builders/start-storybook/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export type StorybookBuilderOptions = JsonObject & {
assets?: AssetPattern[];
preserveSymlinks?: boolean;
sourceMap?: SourceMapUnion;
experimentalZoneless?: boolean;
} & Pick<
// makes sure the option exists
CLIOptions,
Expand Down Expand Up @@ -121,6 +122,7 @@ const commandBuilder: BuilderHandlerFn<StorybookBuilderOptions> = (options, cont
previewUrl,
sourceMap = false,
preserveSymlinks = false,
experimentalZoneless = false,
} = options;

const standaloneOptions: StandaloneOptions = {
Expand All @@ -146,6 +148,7 @@ const commandBuilder: BuilderHandlerFn<StorybookBuilderOptions> = (options, cont
...(assets ? { assets } : {}),
preserveSymlinks,
sourceMap,
experimentalZoneless,
},
tsConfig,
initialPath,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,11 @@
"type": ["boolean", "object"],
"description": "Configure sourcemaps. See: https://angular.io/guide/workspace-config#source-map-configuration",
"default": false
},
"experimentalZoneless": {
"type": "boolean",
"description": "Experimental: Use zoneless change detection.",
"default": false
}
},
"additionalProperties": false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export type StandaloneOptions = CLIOptions &
assets?: AssetPattern[];
sourceMap?: SourceMapUnion;
preserveSymlinks?: boolean;
experimentalZoneless?: boolean;
};
angularBuilderContext?: BuilderContext | null;
tsConfig?: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ApplicationRef, NgModule, enableProdMode } from '@angular/core';
import { ApplicationRef, NgModule } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { BehaviorSubject, Subject } from 'rxjs';
import { stringify } from 'telejson';
Expand All @@ -14,6 +14,12 @@ type StoryRenderInfo = {
moduleMetadataSnapshot: string;
};

declare global {
const STORYBOOK_ANGULAR_OPTIONS: {
experimentalZoneless: boolean;
};
}

const applicationRefs = new Map<HTMLElement, ApplicationRef>();

/**
Expand Down Expand Up @@ -112,14 +118,25 @@ export abstract class AbstractRenderer {
analyzedMetadata,
});

const providers = [
storyPropsProvider(newStoryProps$),
...analyzedMetadata.applicationProviders,
...(storyFnAngular.applicationConfig?.providers ?? []),
];

if (STORYBOOK_ANGULAR_OPTIONS?.experimentalZoneless) {
const { provideExperimentalZonelessChangeDetection } = await import('@angular/core');
if (!provideExperimentalZonelessChangeDetection) {
throw new Error('Experimental zoneless change detection requires Angular 18 or higher');
} else {
providers.unshift(provideExperimentalZonelessChangeDetection());
}
}

const applicationRef = await queueBootstrapping(() => {
return bootstrapApplication(application, {
...storyFnAngular.applicationConfig,
providers: [
storyPropsProvider(newStoryProps$),
...analyzedMetadata.applicationProviders,
...(storyFnAngular.applicationConfig?.providers ?? []),
],
providers,
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ describe('RendererFactory', () => {
rootDocstargetDOMNode = global.document.getElementById('root-docs');
(platformBrowserDynamic as any).mockImplementation(platformBrowserDynamicTesting);
vi.spyOn(console, 'log').mockImplementation(() => {});
// @ts-expect-error Ignore
globalThis.STORYBOOK_ANGULAR_OPTIONS = { experimentalZoneless: false };
});

afterEach(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {
Input,
Output,
Pipe,
input,
output,
} from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/testing';
Expand All @@ -26,7 +28,9 @@ import {

describe('getComponentInputsOutputs', () => {
it('should return empty if no I/O found', () => {
@Component({})
@Component({
standalone: false,
})
class FooComponent {}

expect(getComponentInputsOutputs(FooComponent)).toEqual({
Expand All @@ -47,11 +51,18 @@ describe('getComponentInputsOutputs', () => {
template: '',
inputs: ['inputInComponentMetadata'],
outputs: ['outputInComponentMetadata'],
standalone: false,
})
class FooComponent {
@Input()
public input: string;

public signalInput = input<string>();

public signalInputAliased = input<string>('signalInputAliased', {
alias: 'signalInputAliasedAlias',
});

@Input('inputPropertyName')
public inputWithBindingPropertyName: string;

Expand All @@ -60,6 +71,8 @@ describe('getComponentInputsOutputs', () => {

@Output('outputPropertyName')
public outputWithBindingPropertyName = new EventEmitter<Event>();

public signalOutput = output<string>();
}

const fooComponentFactory = resolveComponentFactory(FooComponent);
Expand All @@ -79,7 +92,9 @@ describe('getComponentInputsOutputs', () => {
],
});

expect(sortByPropName(inputs)).toEqual(sortByPropName(fooComponentFactory.inputs));
expect(sortByPropName(inputs)).toEqual(
sortByPropName(fooComponentFactory.inputs.map(({ isSignal, ...rest }) => rest))
);
expect(sortByPropName(outputs)).toEqual(sortByPropName(fooComponentFactory.outputs));
});

Expand All @@ -88,6 +103,7 @@ describe('getComponentInputsOutputs', () => {
template: '',
inputs: ['input', 'inputWithBindingPropertyName'],
outputs: ['outputWithBindingPropertyName'],
standalone: false,
})
class FooComponent {
@Input()
Expand All @@ -107,13 +123,16 @@ describe('getComponentInputsOutputs', () => {

const { inputs, outputs } = getComponentInputsOutputs(FooComponent);

expect(sortByPropName(inputs)).toEqual(sortByPropName(fooComponentFactory.inputs));
expect(sortByPropName(inputs)).toEqual(
sortByPropName(fooComponentFactory.inputs.map(({ isSignal, ...rest }) => rest))
);
expect(sortByPropName(outputs)).toEqual(sortByPropName(fooComponentFactory.outputs));
});

it('should return I/O in the presence of multiple decorators', () => {
@Component({
template: '',
standalone: false,
})
class FooComponent {
@Input()
Expand All @@ -137,13 +156,16 @@ describe('getComponentInputsOutputs', () => {
outputs: [],
});

expect(sortByPropName(inputs)).toEqual(sortByPropName(fooComponentFactory.inputs));
expect(sortByPropName(inputs)).toEqual(
sortByPropName(fooComponentFactory.inputs.map(({ isSignal, ...rest }) => rest))
);
expect(sortByPropName(outputs)).toEqual(sortByPropName(fooComponentFactory.outputs));
});

it('should return I/O with extending classes', () => {
@Component({
template: '',
standalone: false,
})
class BarComponent {
@Input()
Expand All @@ -155,6 +177,7 @@ describe('getComponentInputsOutputs', () => {

@Component({
template: '',
standalone: false,
})
class FooComponent extends BarComponent {
@Input()
Expand All @@ -177,7 +200,9 @@ describe('getComponentInputsOutputs', () => {
outputs: [],
});

expect(sortByPropName(inputs)).toEqual(sortByPropName(fooComponentFactory.inputs));
expect(sortByPropName(inputs)).toEqual(
sortByPropName(fooComponentFactory.inputs.map(({ isSignal, ...rest }) => rest))
);
expect(sortByPropName(outputs)).toEqual(sortByPropName(fooComponentFactory.outputs));
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,13 @@ import { PropertyExtractor } from './PropertyExtractor';
const TEST_TOKEN = new InjectionToken('testToken');
const TestTokenProvider = { provide: TEST_TOKEN, useValue: 123 };
const TestService = Injectable()(class {});
const TestComponent1 = Component({})(class {});
const TestComponent2 = Component({})(class {});
const StandaloneTestComponent = Component({ standalone: true })(class {});
const StandaloneTestDirective = Directive({ standalone: true })(class {});
const MixedTestComponent1 = Component({ standalone: true })(
class extends StandaloneTestComponent {}
);
const MixedTestComponent2 = Component({})(class extends MixedTestComponent1 {});
const MixedTestComponent3 = Component({ standalone: true })(class extends MixedTestComponent2 {});
const TestComponent1 = Component({ standalone: false })(class {});
const TestComponent2 = Component({ standalone: false })(class {});
const StandaloneTestComponent = Component({})(class {});
const StandaloneTestDirective = Directive({})(class {});
const MixedTestComponent1 = Component({})(class extends StandaloneTestComponent {});
const MixedTestComponent2 = Component({ standalone: false })(class extends MixedTestComponent1 {});
const MixedTestComponent3 = Component({})(class extends MixedTestComponent2 {});
const TestModuleWithDeclarations = NgModule({ declarations: [TestComponent1] })(class {});
const TestModuleWithImportsAndProviders = NgModule({
imports: [TestModuleWithDeclarations],
Expand Down
Loading

0 comments on commit 678fb8f

Please sign in to comment.