-
-
Notifications
You must be signed in to change notification settings - Fork 9.8k
Rework Ember framework to use Vite #33048
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: next
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import { enhanceArgTypes } from 'storybook/internal/docs-tools'; | ||
| import type { ArgTypesEnhancer, Parameters } from 'storybook/internal/types'; | ||
|
|
||
| export { renderToCanvas, render } from './render'; | ||
|
|
||
| export const parameters: Parameters = { | ||
| renderer: 'ember', | ||
| docs: { | ||
| story: { inline: true }, | ||
| }, | ||
| }; | ||
|
|
||
| export const argTypesEnhancers: ArgTypesEnhancer[] = [enhanceArgTypes]; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| import { SourceType } from 'storybook/internal/docs-tools'; | ||
| import type { DecoratorFunction, Parameters } from 'storybook/internal/types'; | ||
|
|
||
| import { sourceDecorator } from './sourceDecorator'; | ||
|
|
||
| export const parameters: Parameters = { | ||
| docs: { | ||
| source: { | ||
| type: SourceType.DYNAMIC, | ||
| language: 'html', | ||
| }, | ||
| }, | ||
| }; | ||
|
|
||
| export const decorators: DecoratorFunction[] = [sourceDecorator]; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| import { SourceType } from 'storybook/internal/docs-tools'; | ||
| import type { ArgTypes, Args, DecoratorFunction } from 'storybook/internal/types'; | ||
|
|
||
| import { emitTransformCode, useEffect, useRef } from 'storybook/preview-api'; | ||
|
|
||
| import type { StoryFn } from '../public-types'; | ||
| import type { EmberRenderer } from '../types'; | ||
|
|
||
| function skipSourceRender(context: Parameters<DecoratorFunction<EmberRenderer>>[1]) { | ||
| const sourceParams = context?.parameters.docs?.source; | ||
| const isArgsStory = context?.parameters.__isArgsStory; | ||
|
|
||
| // always render if the user forces it | ||
| if (sourceParams?.type === SourceType.DYNAMIC) { | ||
| return false; | ||
| } | ||
|
|
||
| // never render if the user is forcing the block to render code, or | ||
| // if the user provides code, or if it's not an args story. | ||
| return !isArgsStory || sourceParams?.code || sourceParams?.type === SourceType.CODE; | ||
| } | ||
|
|
||
| export const sourceDecorator: DecoratorFunction<EmberRenderer> = (storyFn, context) => { | ||
| const source = useRef<string | undefined>(undefined); | ||
| const story = storyFn(); | ||
|
|
||
| useEffect(() => { | ||
| const renderedForSource = context?.parameters.docs?.source?.excludeDecorators | ||
| ? (context.originalStoryFn as StoryFn)(context.args, context) | ||
| : story; | ||
|
|
||
| if (!skipSourceRender(context)) { | ||
| const code = | ||
| generateGlimmerSource(renderedForSource, context.args, context.argTypes) ?? undefined; | ||
| emitTransformCode(code, context); | ||
| source.current = code; | ||
| } | ||
| }); | ||
|
|
||
| return story; | ||
| }; | ||
|
|
||
| export function generateGlimmerSource( | ||
| component: object & { name?: string }, | ||
| args: Args, | ||
| argTypes: ArgTypes | ||
| ): string | null { | ||
| const name = component.name; | ||
| if (!name) { | ||
| return null; | ||
| } | ||
|
|
||
| const propsArray = Object.entries(args) | ||
| .map(([k, v]) => toArgument(k, v, argTypes)) | ||
| .filter((p) => p); | ||
|
|
||
| if (propsArray.length === 0) { | ||
| return `<${name} />`; | ||
| } else if (propsArray.length > 3) { | ||
| return `<${name}\n ${propsArray.join('\n ')}\n/>`; | ||
| } | ||
| return `<${name} ${propsArray.join(' ')} />`; | ||
| } | ||
|
Comment on lines
+43
to
+63
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
export function generateGlimmerSource(
- component: object & { name?: string },
+ rendered: any,
args: Args,
argTypes: ArgTypes
): string | null {
- const name = component.name;
+ const component = rendered?.Component ?? rendered;
+ const name: string | undefined = component?.name;
if (!name) {
return null;
}
@@
}🤖 Prompt for AI Agents |
||
|
|
||
| function toArgument(key: string, value: unknown, argTypes: ArgTypes): string | null { | ||
| if (value === undefined || value === null) { | ||
| return null; | ||
| } | ||
|
|
||
| const argType = argTypes[key]; | ||
|
|
||
| // event should be skipped | ||
| if (argType && argType.action) { | ||
| return null; | ||
| } | ||
|
|
||
| if (typeof value === 'string') { | ||
| return `@${key}=${JSON.stringify(value)}`; | ||
| } | ||
|
|
||
| if (typeof value === 'number' || typeof value === 'boolean') { | ||
| return `@${key}={{${JSON.stringify(value)}}}`; | ||
| } | ||
|
|
||
| return null; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| globalThis.STORYBOOK_ENV = 'ember'; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| import './globals.ts'; | ||
|
|
||
| export { renderToCanvas } from './render'; | ||
| export * from './public-types'; | ||
| export * from './portable-stories'; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| import type { | ||
| NamedOrDefaultProjectAnnotations, | ||
| NormalizedProjectAnnotations, | ||
| } from 'storybook/internal/types'; | ||
|
|
||
| import { | ||
| setProjectAnnotations as originalSetProjectAnnotations, | ||
| setDefaultProjectAnnotations, | ||
| } from 'storybook/preview-api'; | ||
|
|
||
| import * as INTERNAL_DEFAULT_PROJECT_ANNOTATIONS from './render'; | ||
| import type { EmberRenderer } from './types'; | ||
|
|
||
| /** | ||
| * Function that sets the globalConfig of your storybook. The global config is the preview module of | ||
| * your .storybook folder. | ||
| * | ||
| * It should be run a single time, so that your global config (e.g. decorators) is applied to your | ||
| * stories when using `composeStories` or `composeStory`. | ||
| * | ||
| * Example: | ||
| * | ||
| * ```jsx | ||
| * // setup-file.js | ||
| * import { setProjectAnnotations } from '@storybook/preact'; | ||
| * import projectAnnotations from './.storybook/preview'; | ||
| * | ||
| * setProjectAnnotations(projectAnnotations); | ||
| * ``` | ||
| * | ||
| * @param projectAnnotations - E.g. (import projectAnnotations from '../.storybook/preview') | ||
| */ | ||
| export function setProjectAnnotations( | ||
| projectAnnotations: | ||
| | NamedOrDefaultProjectAnnotations<any> | ||
| | NamedOrDefaultProjectAnnotations<any>[] | ||
| ): NormalizedProjectAnnotations<EmberRenderer> { | ||
| setDefaultProjectAnnotations(INTERNAL_DEFAULT_PROJECT_ANNOTATIONS); | ||
| return originalSetProjectAnnotations( | ||
| projectAnnotations | ||
| ) as NormalizedProjectAnnotations<EmberRenderer>; | ||
|
Comment on lines
+11
to
+41
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# First, check if the file exists and get its current state
echo "=== Checking portable-stories.ts file existence and content ==="
wc -l code/frameworks/ember/src/client/portable-stories.ts
# Inspect what ./render exports to ensure it's suitable as default project annotations
echo -e "\n=== Inspecting render.ts exports ==="
rg -n --type=ts "^export\s+(const|function|type|interface|class)\s+" code/frameworks/ember/src/client/render.ts
# Also check for namespace exports and default exports
echo -e "\n=== Checking for export patterns in render.ts ==="
rg -n "^export\s+" code/frameworks/ember/src/client/render.ts | head -20
# Check the entire render.ts file to understand its structure
echo -e "\n=== Checking render.ts file size and structure ==="
wc -l code/frameworks/ember/src/client/render.tsRepository: storybookjs/storybook Length of output: 560 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Check the actual imports and type definitions in portable-stories.ts
echo "=== Reading portable-stories.ts to see current state ==="
cat -n code/frameworks/ember/src/client/portable-stories.ts | head -50
# Look for setDefaultProjectAnnotations import
echo -e "\n=== Checking for setDefaultProjectAnnotations import ==="
rg -n "setDefaultProjectAnnotations|originalSetProjectAnnotations" code/frameworks/ember/src/client/portable-stories.tsRepository: storybookjs/storybook Length of output: 2051 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Check the render.ts file content to understand what gets exported as INTERNAL_DEFAULT_PROJECT_ANNOTATIONS
echo "=== Reading render.ts file content ==="
cat -n code/frameworks/ember/src/client/render.tsRepository: storybookjs/storybook Length of output: 3343 🏁 Script executed: #!/bin/bash
set -eulo pipefail
# Search for NamedOrDefaultProjectAnnotations type definition
echo "=== Searching for NamedOrDefaultProjectAnnotations type definition ==="
rg -n "NamedOrDefaultProjectAnnotations" code/frameworks/ember/src/client/ -A 3
# Also search in common locations
echo -e "\n=== Searching in storybook internal types ==="
fd "types.ts" code/ | xargs rg -l "NamedOrDefaultProjectAnnotations" 2>/dev/null || echo "Not found with fd approach"
# Direct search
echo -e "\n=== Direct search for type definition ==="
rg "type NamedOrDefaultProjectAnnotations|interface NamedOrDefaultProjectAnnotations" -A 3Repository: storybookjs/storybook Length of output: 1622 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Find and examine setDefaultProjectAnnotations signature
echo "=== Searching for setDefaultProjectAnnotations definition ==="
rg -n "setDefaultProjectAnnotations" code/core/src --type=ts -A 5 | head -40
# Look at the ProjectAnnotations type to understand what should be passed
echo -e "\n=== Searching for ProjectAnnotations type definition ==="
rg -n "type ProjectAnnotations|interface ProjectAnnotations" code/core/src --type=ts -A 10 | head -50Repository: storybookjs/storybook Length of output: 3215 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Compare how other frameworks (like react) handle portable-stories
echo "=== Checking react framework's portable-stories ==="
if [ -f "code/frameworks/react/src/client/portable-stories.ts" ]; then
cat -n code/frameworks/react/src/client/portable-stories.ts | head -50
fi
# Check preact too
echo -e "\n=== Checking preact framework's portable-stories ==="
if [ -f "code/frameworks/preact/src/client/portable-stories.ts" ]; then
cat -n code/frameworks/preact/src/client/portable-stories.ts | head -50
fiRepository: storybookjs/storybook Length of output: 170 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Search for other frameworks' render.ts to see what they export
echo "=== Checking react framework's render.ts exports ==="
if [ -f "code/frameworks/react/src/client/render.ts" ]; then
rg -n "^export\s+" code/frameworks/react/src/client/render.ts
fi
echo -e "\n=== Checking preact framework's render.ts exports ==="
if [ -f "code/frameworks/preact/src/client/render.ts" ]; then
rg -n "^export\s+" code/frameworks/preact/src/client/render.ts
fi
echo -e "\n=== Checking vue framework's render.ts exports ==="
if [ -f "code/frameworks/vue3/src/client/render.ts" ]; then
rg -n "^export\s+" code/frameworks/vue3/src/client/render.ts
fiRepository: storybookjs/storybook Length of output: 224 🏁 Script executed: #!/bin/bash
set -euo pipefail
# List all client directory structures
echo "=== Framework structure comparison ==="
for dir in code/frameworks/*/src/client/; do
echo "Framework: $(basename $(dirname $(dirname $(dirname "$dir"))))"
ls -1 "$dir" | grep -E "(render|portable-stories|preview)" || echo " (no matching files)"
doneRepository: storybookjs/storybook Length of output: 223 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Search for any explicit ProjectAnnotations assignments or exports in ember
echo "=== Searching for ProjectAnnotations in ember framework ==="
rg -n "ProjectAnnotations" code/frameworks/ember/src/client/ --type=ts
# Check if there's a preview or index file
echo -e "\n=== Files in ember client directory ==="
ls -la code/frameworks/ember/src/client/
# Look for any setDefaultProjectAnnotations calls to understand the pattern
echo -e "\n=== All setDefaultProjectAnnotations usage patterns ==="
rg -B 5 "setDefaultProjectAnnotations\(" code/frameworks/ --type=tsRepository: storybookjs/storybook Length of output: 5235 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Check the actual behavior - what does renderToCanvas signature expect?
echo "=== Checking RenderToCanvas type definition ==="
rg -n "type RenderToCanvas|interface RenderToCanvas" code/core/src --type=ts -A 5
# Check if render function is supposed to be in ProjectAnnotations
echo -e "\n=== Checking ArgsStoryFn usage ==="
rg -n "ArgsStoryFn" code/core/src/types --type=ts -A 3 | head -30Repository: storybookjs/storybook Length of output: 2471 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Check if INTERNAL_DEFAULT_PROJECT_ANNOTATIONS needs type casting
echo "=== Checking if similar patterns exist in nextjs-vite ==="
cat -n code/frameworks/nextjs-vite/src/portable-stories.ts | head -50
# Check if there's a type definition or explicit casting
echo -e "\n=== Checking nextjs-vite render.ts for comparison ==="
if [ -f "code/frameworks/nextjs-vite/src/render.ts" ]; then
head -30 code/frameworks/nextjs-vite/src/render.ts
fiRepository: storybookjs/storybook Length of output: 2251 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Verify types are consistent - check BaseProjectAnnotations
echo "=== Checking BaseProjectAnnotations ==="
rg -n "interface BaseProjectAnnotations|type BaseProjectAnnotations" code/core/src --type=ts -A 15 | head -40Repository: storybookjs/storybook Length of output: 104 Fix the JSDoc example + tighten types; verify
import type {
NamedOrDefaultProjectAnnotations,
NormalizedProjectAnnotations,
} from 'storybook/internal/types';
import {
setProjectAnnotations as originalSetProjectAnnotations,
setDefaultProjectAnnotations,
} from 'storybook/preview-api';
import * as INTERNAL_DEFAULT_PROJECT_ANNOTATIONS from './render';
import type { EmberRenderer } from './types';
/**
* Function that sets the globalConfig of your storybook. The global config is the preview module of
* your .storybook folder.
*
* It should be run a single time, so that your global config (e.g. decorators) is applied to your
* stories when using `composeStories` or `composeStory`.
*
* Example:
*
* ```jsx
* // setup-file.js
- * import { setProjectAnnotations } from '@storybook/preact';
+ * import { setProjectAnnotations } from '@storybook/ember';
* import projectAnnotations from './.storybook/preview';
*
* setProjectAnnotations(projectAnnotations);
* ```
*
* @param projectAnnotations - E.g. (import projectAnnotations from '../.storybook/preview')
*/
export function setProjectAnnotations(
projectAnnotations:
- | NamedOrDefaultProjectAnnotations<any>
- | NamedOrDefaultProjectAnnotations<any>[]
+ | NamedOrDefaultProjectAnnotations<EmberRenderer>
+ | NamedOrDefaultProjectAnnotations<EmberRenderer>[]
): NormalizedProjectAnnotations<EmberRenderer> {
setDefaultProjectAnnotations(INTERNAL_DEFAULT_PROJECT_ANNOTATIONS);
return originalSetProjectAnnotations(
projectAnnotations
) as NormalizedProjectAnnotations<EmberRenderer>;
}🤖 Prompt for AI Agents |
||
| } | ||
This file was deleted.
This file was deleted.
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add dependency array and cache guard to prevent emitting transformed source on every render.
The
useEffect()hook currently lacks a dependency array, causing it to run after every render and callingemitTransformCodeunnecessarily. Thesource.currentcache is assigned but never checked before emitting. This differs from the React and other framework implementations, which properly track dependencies and avoid redundant channel emissions.export const sourceDecorator: DecoratorFunction<EmberRenderer> = (storyFn, context) => { const source = useRef<string | undefined>(undefined); const story = storyFn(); useEffect(() => { const renderedForSource = context?.parameters.docs?.source?.excludeDecorators ? (context.originalStoryFn as StoryFn)(context.args, context) : story; - if (!skipSourceRender(context)) { - const code = - generateGlimmerSource(renderedForSource, context.args, context.argTypes) ?? undefined; - emitTransformCode(code, context); - source.current = code; - } - }); + if (skipSourceRender(context)) return; + + const code = + generateGlimmerSource(renderedForSource as any, context.args, context.argTypes) ?? undefined; + + if (code !== source.current) { + emitTransformCode(code, context); + source.current = code; + } + }, [ + context.id, + context.args, + context.argTypes, + context.parameters.docs?.source?.excludeDecorators, + context.parameters.docs?.source?.type, + context.parameters.docs?.source?.code, + context.parameters.__isArgsStory, + ]);🤖 Prompt for AI Agents