ContactSign inSign up
Contact
Setup
Interaction tests
Publish
Composition

Troubleshooting your TurboSnap setup

How to prepare your local Storybook for debugging
Debugging TurboSnap with the Chromatic Trace Utility

Why are no changes being detected?

If the build output shows no story files being detected by changes, there might be an issue matching the git changes with the files in your Storybook build. Use the --debug flag for more information about what Chromatic is doing.

Another reason that changes may be missed is if the changed files aren’t directly included in the webpack build; use the externals flag to tell Chromatic about this.

If you’re trying to figure out why certain stories are being re-tested, you can pass the --trace-changed flag, which will print a visual report of how changed files link to your story files:

npx chromatic --only-changed --trace-changed

Alternatively, using the trace utility, you can manually trace a set of files to a set of related story files based on a Webpack stats file. First, you need to generate a preview-stats.json like so (requires Storybook >=6.3):

# npm
npm run build-storybook -- --webpack-stats-json

# yarn
yarn build-storybook --webpack-stats-json

The preview-stats.json will end up in the build directory, typically storybook-static. If you want to inspect this file manually, you can trim it down to its bare essentials using this command:

npx chromatic trim-stats-file

Or, if you’re using a custom build directory:

npx chromatic trim-stats-file ./path/to/preview-stats.json

This will output a preview-stats.trimmed.json file which should be much more human-readable (sort of).

Now, to trace a set of changed file paths to their dependent story files, run the following:

npx chromatic trace [...changed file paths]

For example:

npx chromatic trace ./src/components/link.js ./src/pages/index.js

This prints the number of detected CSF globs, the total number of modules, and a map of Webpack module ID -> file path for each of the found story files (typically *.stories.js).

Example output:

Found 2 CSF globs
Found 218 user modules
{
  '114': './src/components/buildPassed.stories.js',
  '228': './src/components/buildHasChanges.stories.js',
  '229': './src/components/storybookPublished.stories.js',
  ...
}

In this example, it found 2 CSF globs, which are the stories configured in your Storybook’s main.js config file. From those globs, it detected a total of 218 modules (i.e., source files traceable from those globs via imports). What follows is a list of stories files, the IDs of which will get sent to Chromatic and used to limit the stories files to be tested.

If this list of files contains things you didn’t expect, look at any global decorators (e.g., theme providers, wrapper components). These are typically configured in Storybook’s preview.js file. You might have a decorator that’s imported from e.g. an index.js file, which itself imports a bunch of other files. This can lead to all stories depending on a big swath of seemingly unrelated files.

Why are changes not being detected correctly?

Teams frequently use an index file (barrel file) to simplify imports. This practice allows for easier importing, such as accessing a component from @component-library instead of specifying the full path like @component-library/elements/table. However, the usage of barrels impacts TurboSnap’s ability to detect changes.

When encountering a barrel file, TurboSnap relies on Webpack’s tree-shaking abilities to accurately identify changes. Otherwise, a modification in @component-library/elements/table would prompt changes in all files importing from the barrel file, meaning all files that import from @component-library.

Therefore, if you use barrel files, you’ll want to ensure that Webpack tree-shaking (dead-code-elimination) is working properly. Here are some tips:

  1. Use ES2015 module syntax (i.e., import and export)
  2. Build using production mode (NODE_ENV) to enable various optimizations including minification and tree-shaking.
  3. Make sure that compilers do not automatically convert your ES2015 module syntax into CommonJS modules. This is the default behavior of the popular Babel preset @babel/preset-env. See the documentation for more details.

Why are full rebuilds required?

Full rebuilds can be required for various reasons (see the list in how it works). Another scenario where a full rebuild will also be required is due to a change to a package.json or lock file for a subproject that doesn’t affect the Storybook (we need to be very conservative as we cannot tell if a change to a lock file could affect node_modules imported by Storybook).

If you run into this situation frequently, upvote the open issue in the Chromatic CLI’s issue tracker to opt-out of this behavior for specific directories in your repository.

Why is my build failing with an Out of memory error?

An Out of Memory error typically happens when the Node.js process runs out of allocated memory, especially if your project has a large dependency tree or TurboSnap is enabled. Here are a few steps that can help resolve this issue:

  • Increase Node.js memory allocation: Try rerunning Chromatic’s CLI with a higher memory limit by setting NODE_OPTIONS=--max_old_space_size=4096 (4GB) or higher. This provides more memory to Node.js, which can help with larger builds.

  • Adjust CI runner memory settings: Make sure your CI runner has sufficient memory. Chromatic recommends a minimum of 4GB, and if needed, up to 8GB. Some CI providers may require specific configurations to allocate more memory to certain steps or to the entire runner environment.

Builds are split between your environment and Chromatic’s. Processes that require access to your code (like dependency tracing) run in your environment, while tasks like the Capture process run on Chromatic’s end.

Why do merge commits test more changes than I expect?

Ordinarily, TurboSnap uses git to find all files that have changed since the ancestor build to determine which components/stories to snapshot. The changed file behavior is more complex with merge commits because there are two “ancestor builds”.

When you have a merge commit, Chromatic considers any file that has changed since either ancestor’s commit to decide if a story needs to be re-snapshotted. In other words, the union of the git changes.

The reason for this behavior relates to what Chromatic does when it chooses not to re-snapshot a story. In such case, it “copies” the snapshot for the story from the ancestor build, knowing (due to the git check) that the story cannot have changed in the meantime.

In the case of merge commits, Chromatic does not know ahead of time which side of the merge the snapshot might be copied from because that involves running the complete baseline selection process, so it needs to be conservative and allow for changes on either branch.

Does TurboSnap work with squash/rebase merge?

TurboSnap is compatible with squash and merge rebasing as of version 6.6+. Please update your package to get support.

What do the TurboSnap bail reasons in my usage report mean?

Your usage data (CSV report) can help you faster identify opportunities to improve your TurboSnap configuration. The “TurboSnaps Bail Reason” column tells you what caused TurboSnap triggered a full rebuild. Here’s what each reason means:

changedExternalFiles

TurboSnap bailed due to matching externals.

You may need to check your glob pattern or revisit the paths you’re including with externals if these changes are unexpected.

changedPackageFiles

TurboSnap bailed due to one or more package file changes (package.json, package-lock.json, yarn.lock).

This bail should be expected from time to time as dependencies are updated, but can become more of an issue if you run out of a monorepo or have dependencies in subdirectories. If you find this happening frequently, consider using untraced to avoid re-testing on changes to your package control files.

changedStaticFiles

TurboSnap bailed due to matching static file (--static-dir).

This message should only present to customers using TurboSnap with older Storybook versions, since --static-dir was deprecated in Storybook 8. Customers on Storybook 8+ need to add their static dirs using externals. This error may indicate that you need to check the value you’ve configured for --static-dir.

changedStorybookFiles

TurboSnap bailed due to a change in Storybook config (.storybook dir files, such as main.js|ts and preview.js|ts).

You may have made changes to one of the files within your Storybook configuration, or to a dependency that is being imported by your configuration. It’s important to keep in mind that second part, since it’s common practice ot import decorators into the preview.js config.

Additionally, if you’re utilizing barrel/index files (whether directly importing in your preview.js or in a file that preview.js is dependent on), it’s likely to cause more bails since a change to any of these modules would cause any file that imports the index file to be considered “dirty”, even if it’s not using the changed module.

invalidChangedFiles

TurboSnap bailed due to missing git history.

TurboSnap is having issues retrieving your git history. This commonly happens when a repo is shallow cloning, which can be fixed by setting your fetch depth to 0 in your .yml workflow file. Another common cause of this issue is when customers use GitHub Actions with the pull_request event. If this is the case, you’ll want to make sure you set the correct ref in your checkout step.

missingStatsFile

TurboSnap bailed due to missing stats file.

Since the stats file is needed for TurboSnap to analyze your dependencies, make sure your Storybook script includes --stats-json.

noAncestorBuild

TurboSnap bailed due to not finding an ancestor build for the commit.

This bail reason is reserved for when no ancestor build is found at all for a commit. This can be due to rebasing, squash-merging, force-pushing, or running against ephemeral merge commits. If it’s happening on builds that don’t fit those categories, it may indicate an issue with fetching your git history.

rebuild

TurboSnap bailed because the commit is a rerun of a previous build, based on the baseline build having the same commit and branch name.

Most reruns are intentional, but if you weren’t expecting the ones you’re seeing, this may indicate you need to check your CI workflow to see what could be kicking off an additional build for the same commit.