Skip to content

Svelte: Call tick() after mount #31476

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

Open
wants to merge 5 commits into
base: next
Choose a base branch
from

Conversation

JReinhold
Copy link
Contributor

@JReinhold JReinhold commented May 14, 2025

Closes #

What I did

  1. Added a call to tick() after mounting and re-rendering Svelte components, to ensure that any effects are completed before calling the render phase complete. @testing-library/svelte uses flushSync, but because we're in an async context we can await tick() instead, which is supposedly better.
  2. Added test stories for Async components, but disabled since they haven't been released yet, and so they would break CI currently.

Originally I did this to test out the await settled() call, but concluded that we should not be calling that automatically similar to tick(). The reason being that it would block users from testing their components in the pending state, as it would cause play to wait for all promises to settled, not allowing users to make assertions before so. If users want to, they can call settled() in their play-function for maximum flexibility.

  1. I did however add a top-level <svelte:boundary>, so that if users try to render async components without wrapping them in a boundary, it won't crash, it will just use our top-level boundary instead. Users can add their own lower-level boundaries if they want to. This is a no-op in current Svelte versions so it should be safe to add now.

Checklist for Contributors

Testing

You can test out the async stuff (but you don't have to right now) by creating a Svelte sandbox and then:

  1. yarn add svelte@https://pkg.pr.new/svelte@15844
  2. Add compilerOptions: { experimental: { async: true } } to the svelte.config.js of the sandbox
  3. Uncomment the stories in the settled.stories.ts file, as well as the async logic in the AsyncComponent.svelte file.

The new uncommented story should work properly.

The changes in this PR are covered in the following automated tests:

  • stories
  • unit tests
  • integration tests
  • end-to-end tests

Manual testing

This section is mandatory for all contributions. If you believe no manual test is necessary, please state so explicitly. Thanks!

Documentation

  • Add or update documentation reflecting your changes
  • If you are deprecating/removing a feature, make sure to update
    MIGRATION.MD

Checklist for Maintainers

  • When this PR is ready for testing, make sure to add ci:normal, ci:merged or ci:daily GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found in code/lib/cli-storybook/src/sandbox-templates.ts

  • Make sure this PR contains one of the labels below:

    Available labels
    • bug: Internal changes that fixes incorrect behavior.
    • maintenance: User-facing maintenance tasks.
    • dependencies: Upgrading (sometimes downgrading) dependencies.
    • build: Internal-facing build tooling & test updates. Will not show up in release changelog.
    • cleanup: Minor cleanup style change. Will not show up in release changelog.
    • documentation: Documentation only changes. Will not show up in release changelog.
    • feature request: Introducing a new feature.
    • BREAKING CHANGE: Changes that break compatibility in some way with current major version.
    • other: Changes that don't fit in the above categories.

🦋 Canary release

This PR does not have a canary release associated. You can request a canary release of this pull request by mentioning the @storybookjs/core team here.

core team members can create a canary release here or locally with gh workflow run --repo storybookjs/storybook canary-release-pr.yml --field pr=<PR_NUMBER>

Greptile Summary

Added support for Svelte async components by ensuring effects complete before rendering, with proper handling of component mounting and state transitions.

  • Added await svelte.tick() calls after mounting/re-rendering in code/renderers/svelte/src/render.ts to ensure effects complete
  • Added top-level <svelte:boundary> in code/renderers/svelte/src/components/PreviewRender.svelte to safely handle async components
  • Added test stories in code/renderers/svelte/template/stories/settled.stories.ts with sync component tests and commented async tests
  • Intentionally avoided auto-calling settled() to allow testing pending component states
  • Added AsyncComponent.svelte and SyncComponent.svelte test components demonstrating effect handling

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 file(s) reviewed, 3 comment(s)
Edit PR Review Bot Settings | Greptile

Comment on lines +16 to +19
$effect(() => {
onEffect?.();
shown = true;
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: The sync and async versions have different timing characteristics which could cause inconsistent behavior when switching between them

Comment on lines +5 to +8
$effect(() => {
onEffect?.();
shown = true;
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: The effect runs synchronously and modifies state. Consider if this could cause issues with test timing or race conditions when testing async behavior.

Comment on lines +39 to +40
await expect(args.onEffect).not.toHaveBeenCalled();
await expect(canvas.getElementById('sb-pending-async-component-notice')).toBeInTheDocument();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: getElementById is less reliable than getByTestId for testing. Consider using data-testid here for consistency with other tests.

Copy link

nx-cloud bot commented May 14, 2025

View your CI Pipeline Execution ↗ for commit c997203.

Command Status Duration Result
nx run-many -t build --parallel=3 ✅ Succeeded 1m 25s View ↗

☁️ Nx Cloud last updated this comment at 2025-05-20 13:48:12 UTC

@JReinhold JReinhold changed the title Svelte: call tick() after mount Svelte: Call tick() after mount May 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant