diff --git a/.changeset/pink-feet-trade.md b/.changeset/pink-feet-trade.md
new file mode 100644
index 000000000..d63683ebd
--- /dev/null
+++ b/.changeset/pink-feet-trade.md
@@ -0,0 +1,11 @@
+---
+'sku': minor
+---
+
+Adds support for Storybook configuration via the `.storybook` directory
+
+sku now supports the standard `.storybook` configuration directory, as documented in [Storybook's configuration documentation].
+Please read [sku's storybook documentation][sku storybook docs] for more info.
+
+[Storybook configuration documentation]: https://storybook.js.org/docs/react/configure/overview
+[sku storybook docs]: https://seek-oss.github.io/sku/#/./docs/storybook
diff --git a/.changeset/real-rabbits-yawn.md b/.changeset/real-rabbits-yawn.md
new file mode 100644
index 000000000..f05d82128
--- /dev/null
+++ b/.changeset/real-rabbits-yawn.md
@@ -0,0 +1,13 @@
+---
+'sku': minor
+---
+
+Drop support for running `devServerMiddleware` alongside `sku storybook`
+
+Now that sku supports Storybook configuration via the `.storybook` directory, this feature is unnecessary.
+Storybook middleware can be configured by creating a `middleware.js` file in the `.storybook` directory.
+See [the sku docs][sku storybook middleware] for more info.
+
+**NOTE**: While this is technically a breaking change, it does not affect app builds, therefore it has been downgraded to a `minor` release.
+
+[sku storybook middleware]: https://seek-oss.github.io/sku/#/./docs/storybook?id=devserver-middleware
diff --git a/.changeset/thick-cameras-arrive.md b/.changeset/thick-cameras-arrive.md
new file mode 100644
index 000000000..0e0726122
--- /dev/null
+++ b/.changeset/thick-cameras-arrive.md
@@ -0,0 +1,5 @@
+---
+'sku': patch
+---
+
+Disable Storybook telemetry
diff --git a/docs/docs/storybook.md b/docs/docs/storybook.md
index 28d198cc6..353af6f59 100644
--- a/docs/docs/storybook.md
+++ b/docs/docs/storybook.md
@@ -21,6 +21,35 @@ export const Secondary = () => ;
_**NOTE:** To access the Storybook API, you should import from `sku/@storybook/...`, since your project isn't depending on Storybook packages directly._
+## Configuration
+
+Storybook can be configured by creating specially-named files inside the `.storybook` folder of your app.
+Take a look at the [Storybook configuration docs] for all the ways to customize your Storybook.
+
+_**NOTE:** sku maintains control of the `main.js` configuration file as it is critical to ensuring compatibility between Storybook and your app.
+If you have a valid use case for customizing this file, please reach out in [`#sku-support`]._
+
+[Storybook configuration docs]: https://storybook.js.org/docs/react/configure/overview
+[`#sku-support`]: https://seekchat.slack.com/channels/sku-support
+
+### Addons
+
+There are no storybook addons configured by default in sku but they can be added through the `storybookAddons` option in `sku.config.ts`.
+
+For example, if you want to use `@storybook/addon-essentials`, first install the addon.
+
+```bash
+yarn add --dev @storybook/addon-essentials
+```
+
+Then add it to your `sku.config.ts`.
+
+```ts
+export default {
+ storybookAddons: ['@storybook/addon-essentials'],
+} satisfies SkuConfig;
+```
+
### Story Rendering
Story rendering can be customized globally by creating a `.storybook/preview.js` (or `.ts`, or `.tsx`) file.
@@ -53,7 +82,14 @@ See [the Storybook docs][storybook preview.js] for more info.
### DevServer Middleware
-When running `sku storybook`, if you have configured [`devServerMiddleware`][devserver middleware] in your sku config, that middleware will be passed through to storybook and injected into its own middleware stack.
+When running `sku storybook`, if you want to run your [`devServerMiddleware`][devserver middleware] at the same time, add a `middleware.js` file to the `.storybook` folder and export it:
+
+```js
+// .storybook/middleware.js
+import devServerMiddleware from '../devServerMiddleware.js';
+
+export default devServerMiddleware;
+```
[devserver middleware]: ./docs/extra-features.md#devserver-middleware
@@ -68,24 +104,6 @@ export default {
} satisfies SkuConfig;
```
-## Addons
-
-There are no storybook addons configured by default in sku but they can be added through the `storybookAddons` option in `sku.config.ts`.
-
-For example, if you want to use `@storybook/addon-essentials`, first install the addon.
-
-```bash
-yarn add --dev @storybook/addon-essentials
-```
-
-Then add it to your `sku.config.ts`.
-
-```ts
-export default {
- storybookAddons: ['@storybook/addon-essentials'],
-} satisfies SkuConfig;
-```
-
## Build Storybook
To build your Storybook, first add the following npm script:
diff --git a/fixtures/assertion-removal/.eslintignore b/fixtures/assertion-removal/.eslintignore
index be5af46ed..a8fee4a3e 100644
--- a/fixtures/assertion-removal/.eslintignore
+++ b/fixtures/assertion-removal/.eslintignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/assertion-removal/.gitignore b/fixtures/assertion-removal/.gitignore
index 9472e0ebe..d2e00244e 100644
--- a/fixtures/assertion-removal/.gitignore
+++ b/fixtures/assertion-removal/.gitignore
@@ -1,6 +1,7 @@
# managed by sku
.eslintrc
.prettierrc
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/assertion-removal/.prettierignore b/fixtures/assertion-removal/.prettierignore
index be5af46ed..a8fee4a3e 100644
--- a/fixtures/assertion-removal/.prettierignore
+++ b/fixtures/assertion-removal/.prettierignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/braid-design-system/.eslintignore b/fixtures/braid-design-system/.eslintignore
index be5af46ed..a8fee4a3e 100644
--- a/fixtures/braid-design-system/.eslintignore
+++ b/fixtures/braid-design-system/.eslintignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/braid-design-system/.gitignore b/fixtures/braid-design-system/.gitignore
index 9472e0ebe..d2e00244e 100644
--- a/fixtures/braid-design-system/.gitignore
+++ b/fixtures/braid-design-system/.gitignore
@@ -1,6 +1,7 @@
# managed by sku
.eslintrc
.prettierrc
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/braid-design-system/.prettierignore b/fixtures/braid-design-system/.prettierignore
index be5af46ed..a8fee4a3e 100644
--- a/fixtures/braid-design-system/.prettierignore
+++ b/fixtures/braid-design-system/.prettierignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/custom-src-paths/.eslintignore b/fixtures/custom-src-paths/.eslintignore
index be5af46ed..a8fee4a3e 100644
--- a/fixtures/custom-src-paths/.eslintignore
+++ b/fixtures/custom-src-paths/.eslintignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/custom-src-paths/.gitignore b/fixtures/custom-src-paths/.gitignore
index 9472e0ebe..d2e00244e 100644
--- a/fixtures/custom-src-paths/.gitignore
+++ b/fixtures/custom-src-paths/.gitignore
@@ -1,6 +1,7 @@
# managed by sku
.eslintrc
.prettierrc
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/custom-src-paths/.prettierignore b/fixtures/custom-src-paths/.prettierignore
index be5af46ed..a8fee4a3e 100644
--- a/fixtures/custom-src-paths/.prettierignore
+++ b/fixtures/custom-src-paths/.prettierignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/library-build/.eslintignore b/fixtures/library-build/.eslintignore
index be5af46ed..a8fee4a3e 100644
--- a/fixtures/library-build/.eslintignore
+++ b/fixtures/library-build/.eslintignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/library-build/.gitignore b/fixtures/library-build/.gitignore
index 9472e0ebe..d2e00244e 100644
--- a/fixtures/library-build/.gitignore
+++ b/fixtures/library-build/.gitignore
@@ -1,6 +1,7 @@
# managed by sku
.eslintrc
.prettierrc
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/library-build/.prettierignore b/fixtures/library-build/.prettierignore
index be5af46ed..a8fee4a3e 100644
--- a/fixtures/library-build/.prettierignore
+++ b/fixtures/library-build/.prettierignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/library-file/.eslintignore b/fixtures/library-file/.eslintignore
index be5af46ed..a8fee4a3e 100644
--- a/fixtures/library-file/.eslintignore
+++ b/fixtures/library-file/.eslintignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/library-file/.gitignore b/fixtures/library-file/.gitignore
index 9472e0ebe..d2e00244e 100644
--- a/fixtures/library-file/.gitignore
+++ b/fixtures/library-file/.gitignore
@@ -1,6 +1,7 @@
# managed by sku
.eslintrc
.prettierrc
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/library-file/.prettierignore b/fixtures/library-file/.prettierignore
index be5af46ed..a8fee4a3e 100644
--- a/fixtures/library-file/.prettierignore
+++ b/fixtures/library-file/.prettierignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/lint-format/.eslintignore b/fixtures/lint-format/.eslintignore
index be5af46ed..a8fee4a3e 100644
--- a/fixtures/lint-format/.eslintignore
+++ b/fixtures/lint-format/.eslintignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/lint-format/.gitignore b/fixtures/lint-format/.gitignore
index e603e2924..4f42a791f 100644
--- a/fixtures/lint-format/.gitignore
+++ b/fixtures/lint-format/.gitignore
@@ -1,6 +1,7 @@
# managed by sku
.eslintrc
.prettierrc
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/lint-format/.prettierignore b/fixtures/lint-format/.prettierignore
index be5af46ed..a8fee4a3e 100644
--- a/fixtures/lint-format/.prettierignore
+++ b/fixtures/lint-format/.prettierignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/multiple-routes/.eslintignore b/fixtures/multiple-routes/.eslintignore
index be5af46ed..a8fee4a3e 100644
--- a/fixtures/multiple-routes/.eslintignore
+++ b/fixtures/multiple-routes/.eslintignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/multiple-routes/.gitignore b/fixtures/multiple-routes/.gitignore
index 9472e0ebe..d2e00244e 100644
--- a/fixtures/multiple-routes/.gitignore
+++ b/fixtures/multiple-routes/.gitignore
@@ -1,6 +1,7 @@
# managed by sku
.eslintrc
.prettierrc
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/multiple-routes/.prettierignore b/fixtures/multiple-routes/.prettierignore
index be5af46ed..a8fee4a3e 100644
--- a/fixtures/multiple-routes/.prettierignore
+++ b/fixtures/multiple-routes/.prettierignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/public-path/.eslintignore b/fixtures/public-path/.eslintignore
index 58df60132..1c8778aba 100644
--- a/fixtures/public-path/.eslintignore
+++ b/fixtures/public-path/.eslintignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-storybook/
dist/static/
diff --git a/fixtures/public-path/.gitignore b/fixtures/public-path/.gitignore
index 987acfe8f..f10987025 100644
--- a/fixtures/public-path/.gitignore
+++ b/fixtures/public-path/.gitignore
@@ -1,6 +1,7 @@
# managed by sku
.eslintrc
.prettierrc
+.storybook/main.js
coverage/
dist-storybook/
dist/static/
diff --git a/fixtures/public-path/.prettierignore b/fixtures/public-path/.prettierignore
index 58df60132..1c8778aba 100644
--- a/fixtures/public-path/.prettierignore
+++ b/fixtures/public-path/.prettierignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-storybook/
dist/static/
diff --git a/fixtures/react-css-modules/.eslintignore b/fixtures/react-css-modules/.eslintignore
index be5af46ed..a8fee4a3e 100644
--- a/fixtures/react-css-modules/.eslintignore
+++ b/fixtures/react-css-modules/.eslintignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/react-css-modules/.gitignore b/fixtures/react-css-modules/.gitignore
index 9472e0ebe..d2e00244e 100644
--- a/fixtures/react-css-modules/.gitignore
+++ b/fixtures/react-css-modules/.gitignore
@@ -1,6 +1,7 @@
# managed by sku
.eslintrc
.prettierrc
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/react-css-modules/.prettierignore b/fixtures/react-css-modules/.prettierignore
index be5af46ed..a8fee4a3e 100644
--- a/fixtures/react-css-modules/.prettierignore
+++ b/fixtures/react-css-modules/.prettierignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/sku-test/.eslintignore b/fixtures/sku-test/.eslintignore
index be5af46ed..a8fee4a3e 100644
--- a/fixtures/sku-test/.eslintignore
+++ b/fixtures/sku-test/.eslintignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/sku-test/.gitignore b/fixtures/sku-test/.gitignore
index 9472e0ebe..d2e00244e 100644
--- a/fixtures/sku-test/.gitignore
+++ b/fixtures/sku-test/.gitignore
@@ -1,6 +1,7 @@
# managed by sku
.eslintrc
.prettierrc
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/sku-test/.prettierignore b/fixtures/sku-test/.prettierignore
index be5af46ed..a8fee4a3e 100644
--- a/fixtures/sku-test/.prettierignore
+++ b/fixtures/sku-test/.prettierignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/sku-with-https/.eslintignore b/fixtures/sku-with-https/.eslintignore
index be5af46ed..a8fee4a3e 100644
--- a/fixtures/sku-with-https/.eslintignore
+++ b/fixtures/sku-with-https/.eslintignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/sku-with-https/.gitignore b/fixtures/sku-with-https/.gitignore
index 7bfb4a45b..f6980b14d 100644
--- a/fixtures/sku-with-https/.gitignore
+++ b/fixtures/sku-with-https/.gitignore
@@ -2,6 +2,7 @@
.eslintrc
.prettierrc
.ssl
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/sku-with-https/.prettierignore b/fixtures/sku-with-https/.prettierignore
index be5af46ed..a8fee4a3e 100644
--- a/fixtures/sku-with-https/.prettierignore
+++ b/fixtures/sku-with-https/.prettierignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/source-maps/.eslintignore b/fixtures/source-maps/.eslintignore
index be5af46ed..a8fee4a3e 100644
--- a/fixtures/source-maps/.eslintignore
+++ b/fixtures/source-maps/.eslintignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/source-maps/.gitignore b/fixtures/source-maps/.gitignore
index 9472e0ebe..d2e00244e 100644
--- a/fixtures/source-maps/.gitignore
+++ b/fixtures/source-maps/.gitignore
@@ -1,6 +1,7 @@
# managed by sku
.eslintrc
.prettierrc
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/source-maps/.prettierignore b/fixtures/source-maps/.prettierignore
index be5af46ed..a8fee4a3e 100644
--- a/fixtures/source-maps/.prettierignore
+++ b/fixtures/source-maps/.prettierignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/ssr-hello-world/.eslintignore b/fixtures/ssr-hello-world/.eslintignore
index e9b94e25e..bca860144 100644
--- a/fixtures/ssr-hello-world/.eslintignore
+++ b/fixtures/ssr-hello-world/.eslintignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-build/
dist-storybook/
diff --git a/fixtures/ssr-hello-world/.gitignore b/fixtures/ssr-hello-world/.gitignore
index 2395ad75e..e646cbdd9 100644
--- a/fixtures/ssr-hello-world/.gitignore
+++ b/fixtures/ssr-hello-world/.gitignore
@@ -1,6 +1,7 @@
# managed by sku
.eslintrc
.prettierrc
+.storybook/main.js
coverage/
dist-build/
dist-storybook/
diff --git a/fixtures/ssr-hello-world/.prettierignore b/fixtures/ssr-hello-world/.prettierignore
index e9b94e25e..bca860144 100644
--- a/fixtures/ssr-hello-world/.prettierignore
+++ b/fixtures/ssr-hello-world/.prettierignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-build/
dist-storybook/
diff --git a/fixtures/storybook-config/.eslintignore b/fixtures/storybook-config/.eslintignore
index be5af46ed..a8fee4a3e 100644
--- a/fixtures/storybook-config/.eslintignore
+++ b/fixtures/storybook-config/.eslintignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/storybook-config/.gitignore b/fixtures/storybook-config/.gitignore
index 6e1650ecc..5d73a2f5c 100644
--- a/fixtures/storybook-config/.gitignore
+++ b/fixtures/storybook-config/.gitignore
@@ -4,6 +4,7 @@ npm-debug.log
# managed by sku
.eslintrc
.prettierrc
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/storybook-config/.prettierignore b/fixtures/storybook-config/.prettierignore
index be5af46ed..a8fee4a3e 100644
--- a/fixtures/storybook-config/.prettierignore
+++ b/fixtures/storybook-config/.prettierignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/storybook-config/.storybook/middleware.js b/fixtures/storybook-config/.storybook/middleware.js
new file mode 100644
index 000000000..6d7fa83d6
--- /dev/null
+++ b/fixtures/storybook-config/.storybook/middleware.js
@@ -0,0 +1,3 @@
+import middleware from '../dev-middleware';
+
+export default middleware;
diff --git a/fixtures/storybook-config/.storybook/preview.tsx b/fixtures/storybook-config/.storybook/preview.tsx
index f561527bb..57fe89090 100644
--- a/fixtures/storybook-config/.storybook/preview.tsx
+++ b/fixtures/storybook-config/.storybook/preview.tsx
@@ -5,7 +5,7 @@ import apac from 'braid-design-system/themes/apac';
import type { Preview } from 'sku/@storybook/react';
-const preview: Preview = {
+export default {
decorators: [
(Story) => (
@@ -21,6 +21,4 @@ const preview: Preview = {
),
],
-};
-
-export default preview;
+} satisfies Preview;
diff --git a/fixtures/styling/.eslintignore b/fixtures/styling/.eslintignore
index be5af46ed..a8fee4a3e 100644
--- a/fixtures/styling/.eslintignore
+++ b/fixtures/styling/.eslintignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/styling/.gitignore b/fixtures/styling/.gitignore
index 9472e0ebe..d2e00244e 100644
--- a/fixtures/styling/.gitignore
+++ b/fixtures/styling/.gitignore
@@ -1,6 +1,7 @@
# managed by sku
.eslintrc
.prettierrc
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/styling/.prettierignore b/fixtures/styling/.prettierignore
index be5af46ed..a8fee4a3e 100644
--- a/fixtures/styling/.prettierignore
+++ b/fixtures/styling/.prettierignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/translations/.eslintignore b/fixtures/translations/.eslintignore
index b2d0a058b..70e1e3110 100644
--- a/fixtures/translations/.eslintignore
+++ b/fixtures/translations/.eslintignore
@@ -1,6 +1,7 @@
# managed by sku
**/*.vocab/index.ts
*.less.d.ts
+.storybook/main.js
coverage/
dist-ssr/
dist-storybook/
diff --git a/fixtures/translations/.gitignore b/fixtures/translations/.gitignore
index 9aaf8c715..83ebc8152 100644
--- a/fixtures/translations/.gitignore
+++ b/fixtures/translations/.gitignore
@@ -4,6 +4,7 @@
**/*.vocab/index.ts
.eslintrc
.prettierrc
+.storybook/main.js
coverage/
dist-ssr/
dist-storybook/
diff --git a/fixtures/translations/.prettierignore b/fixtures/translations/.prettierignore
index 5121f98f6..ba10121aa 100644
--- a/fixtures/translations/.prettierignore
+++ b/fixtures/translations/.prettierignore
@@ -3,6 +3,7 @@ translations.ts
# managed by sku
**/*.vocab/index.ts
*.less.d.ts
+.storybook/main.js
coverage/
dist-ssr/
dist-storybook/
diff --git a/fixtures/typescript-css-modules/.eslintignore b/fixtures/typescript-css-modules/.eslintignore
index be5af46ed..a8fee4a3e 100644
--- a/fixtures/typescript-css-modules/.eslintignore
+++ b/fixtures/typescript-css-modules/.eslintignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/typescript-css-modules/.gitignore b/fixtures/typescript-css-modules/.gitignore
index 9472e0ebe..d2e00244e 100644
--- a/fixtures/typescript-css-modules/.gitignore
+++ b/fixtures/typescript-css-modules/.gitignore
@@ -1,6 +1,7 @@
# managed by sku
.eslintrc
.prettierrc
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/fixtures/typescript-css-modules/.prettierignore b/fixtures/typescript-css-modules/.prettierignore
index be5af46ed..a8fee4a3e 100644
--- a/fixtures/typescript-css-modules/.prettierignore
+++ b/fixtures/typescript-css-modules/.prettierignore
@@ -1,5 +1,6 @@
# managed by sku
*.less.d.ts
+.storybook/main.js
coverage/
dist-storybook/
dist/
diff --git a/packages/sku/config/storybook/build/main.js b/packages/sku/config/storybook/build/main.js
deleted file mode 100644
index 5686f9864..000000000
--- a/packages/sku/config/storybook/build/main.js
+++ /dev/null
@@ -1 +0,0 @@
-module.exports = require('../config');
diff --git a/packages/sku/config/storybook/build/webpack.config.js b/packages/sku/config/storybook/build/webpack.config.js
deleted file mode 100644
index f150312fa..000000000
--- a/packages/sku/config/storybook/build/webpack.config.js
+++ /dev/null
@@ -1,4 +0,0 @@
-const storybookWebpackConfig = require('../storybookWebpackConfig');
-
-module.exports = (storybookConfig) =>
- storybookWebpackConfig(storybookConfig, { isDevServer: false });
diff --git a/packages/sku/config/storybook/config.js b/packages/sku/config/storybook/config.js
deleted file mode 100644
index c060dc4e4..000000000
--- a/packages/sku/config/storybook/config.js
+++ /dev/null
@@ -1,45 +0,0 @@
-const fs = require('fs');
-const path = require('path');
-const {
- paths,
- storybookAddons,
- storybookStoryStore,
-} = require('../../context');
-
-/** @type {import("@storybook/react-webpack5").StorybookConfig} */
-module.exports = {
- stories: paths.src
- .filter((srcPath) => fs.statSync(srcPath).isDirectory())
- .map((srcPath) => path.join(srcPath, '**/*.stories.@(js|ts|tsx)')),
- addons: storybookAddons,
- framework: {
- name: '@storybook/react-webpack5',
- options: {},
- },
- core: {
- builder: {
- name: '@storybook/builder-webpack5',
- options: {
- fsCache: true,
- },
- },
- },
- features: {
- storyStoreV7: storybookStoryStore,
- },
- babel: (config) => ({
- ...config,
- presets: [
- ...config.presets,
- [
- require.resolve('@babel/preset-env'),
- {
- targets: {
- chrome: 100,
- },
- },
- ],
- require.resolve('@babel/preset-typescript'),
- ],
- }),
-};
diff --git a/packages/sku/config/storybook/index.js b/packages/sku/config/storybook/index.js
new file mode 100644
index 000000000..b5a277560
--- /dev/null
+++ b/packages/sku/config/storybook/index.js
@@ -0,0 +1,75 @@
+/**
+ * This file and all its dependencies must be CJS
+ * https://github.com/storybookjs/storybook/pull/23018
+ */
+
+const fs = require('fs');
+const path = require('path');
+const {
+ paths,
+ storybookAddons,
+ storybookStoryStore,
+} = require('../../context');
+
+const makeStorybookWebpackConfig = require('./storybookWebpackConfig');
+
+/** @type {import("@storybook/react-webpack5").StorybookConfig} */
+module.exports = {
+ stories: paths.src
+ .filter((srcPath) => fs.statSync(srcPath).isDirectory())
+ .map((srcPath) => path.join(srcPath, '**/*.stories.@(js|ts|tsx)')),
+ addons: storybookAddons,
+ framework: {
+ // Storybook looks for a `/preset` entrypoint on the framework package,
+ // so we give it the dirname of the resolved path to package.json
+ // https://github.com/storybookjs/storybook/blob/aecfa1791f982bef6a06b51d20df3e31dd82b5b4/code/lib/core-common/src/utils/validate-config.ts#L34
+ name: path.dirname(
+ require.resolve('@storybook/react-webpack5/package.json'),
+ ),
+ options: {},
+ },
+ core: {
+ builder: {
+ name: require.resolve('@storybook/builder-webpack5'),
+ options: {
+ fsCache: true,
+ },
+ },
+ disableTelemetry: true,
+ },
+ features: {
+ storyStoreV7: storybookStoryStore,
+ },
+ // sku storybook -> configType === 'DEVELOPMENT'
+ // sku build-storybook -> configType === 'PRODUCTION'
+ webpackFinal: (config, { configType }) =>
+ makeStorybookWebpackConfig(config, {
+ isDevServer: configType === 'DEVELOPMENT',
+ }),
+ babel: (config) => ({
+ ...config,
+ presets: [
+ // Includes `@babel/preset-react`
+ ...config.presets,
+
+ // Storybook as of 7.0 no longer handles babel stuff for you (other than react)
+ // We need to configure TypeScript support ourselves, if we want it
+ // https://github.com/storybookjs/storybook/issues/22357#issuecomment-1532548058
+ [
+ require.resolve('@babel/preset-env'),
+ {
+ targets: {
+ chrome: 100,
+ },
+ },
+ ],
+ [
+ require.resolve('@babel/preset-typescript'),
+ {
+ allExtensions: true,
+ isTSX: true,
+ },
+ ],
+ ],
+ }),
+};
diff --git a/packages/sku/config/storybook/start/main.js b/packages/sku/config/storybook/start/main.js
deleted file mode 100644
index 5686f9864..000000000
--- a/packages/sku/config/storybook/start/main.js
+++ /dev/null
@@ -1 +0,0 @@
-module.exports = require('../config');
diff --git a/packages/sku/config/storybook/start/middleware.js b/packages/sku/config/storybook/start/middleware.js
deleted file mode 100644
index c48e34d7d..000000000
--- a/packages/sku/config/storybook/start/middleware.js
+++ /dev/null
@@ -1,10 +0,0 @@
-const { paths, useDevServerMiddleware } = require('../../../context');
-
-const dummyMiddleware = (app) => app;
-let middleware = dummyMiddleware;
-
-if (useDevServerMiddleware) {
- middleware = require(paths.devServerMiddleware);
-}
-
-module.exports = middleware;
diff --git a/packages/sku/config/storybook/start/webpack.config.js b/packages/sku/config/storybook/start/webpack.config.js
deleted file mode 100644
index c26d286be..000000000
--- a/packages/sku/config/storybook/start/webpack.config.js
+++ /dev/null
@@ -1,4 +0,0 @@
-const storybookWebpackConfig = require('../storybookWebpackConfig');
-
-module.exports = (storybookConfig) =>
- storybookWebpackConfig(storybookConfig, { isDevServer: true });
diff --git a/packages/sku/config/storybook/storybookWebpackConfig.js b/packages/sku/config/storybook/storybookWebpackConfig.js
index 6ddf57604..b6546be4e 100644
--- a/packages/sku/config/storybook/storybookWebpackConfig.js
+++ b/packages/sku/config/storybook/storybookWebpackConfig.js
@@ -6,7 +6,11 @@ const { resolvePackage } = require('../webpack/utils/resolvePackage');
const hot = process.env.SKU_HOT !== 'false';
-module.exports = ({ config }, { isDevServer }) => {
+/**
+ * @param {import("webpack").Configuration} config
+ * @param {{isDevServer: boolean}}
+ */
+module.exports = (config, { isDevServer }) => {
const clientWebpackConfig = find(
makeWebpackConfig({
isIntegration: true,
diff --git a/packages/sku/lib/configure.js b/packages/sku/lib/configure.js
index 4c0539af3..2d064e99f 100755
--- a/packages/sku/lib/configure.js
+++ b/packages/sku/lib/configure.js
@@ -1,4 +1,5 @@
#!/usr/bin/env node
+
const { writeFile, rm } = require('fs/promises');
const path = require('path');
@@ -13,12 +14,14 @@ const prettierConfig = require('../config/prettier/prettierConfig');
const eslintConfig = require('../config/eslint/eslintConfig');
const createTSConfig = require('../config/typescript/tsconfig.js');
const getCertificate = require('./certificate');
+const { storybookMainConfigPath } = require('./storybook');
+const managedConfigBanner = require('./managedConfigBanner.js');
+
const coverageFolder = 'coverage';
const convertToForwardSlashPaths = (pathStr) => pathStr.replace(/\\/g, '/');
const addSep = (p) => `${p}${path.sep}`;
-const prependBanner = (str) =>
- `/** THIS FILE IS GENERATED BY SKU, MANUAL CHANGES WILL BE DISCARDED **/\n${str}`;
+const prependBanner = (str) => `${managedConfigBanner}\n${str}`;
const writeFileToCWD = async (fileName, content, { banner = true } = {}) => {
const outPath = getPathFromCwd(fileName);
@@ -33,11 +36,13 @@ module.exports = async () => {
const gitIgnorePatterns = [
addSep(bundleReportFolder),
addSep(coverageFolder),
+ storybookMainConfigPath,
];
const lintIgnorePatterns = [
addSep(bundleReportFolder),
addSep(coverageFolder),
'*.less.d.ts',
+ storybookMainConfigPath,
];
// Ignore webpack target directories
diff --git a/packages/sku/lib/managedConfigBanner.js b/packages/sku/lib/managedConfigBanner.js
new file mode 100644
index 000000000..a5e8e157b
--- /dev/null
+++ b/packages/sku/lib/managedConfigBanner.js
@@ -0,0 +1 @@
+module.exports = `/** THIS FILE IS GENERATED BY SKU, MANUAL CHANGES WILL BE DISCARDED **/`;
diff --git a/packages/sku/lib/storybook.js b/packages/sku/lib/storybook.js
index cdc8ac1fe..f3fe7816c 100644
--- a/packages/sku/lib/storybook.js
+++ b/packages/sku/lib/storybook.js
@@ -1,70 +1,35 @@
const path = require('path');
-
-const { paths } = require('../context');
const fs = require('fs/promises');
const debug = require('debug');
-const glob = require('fast-glob');
const log = debug('sku:storybook');
-const previewFileName = 'preview.{js,ts,tsx}';
-
-const previewFileAbsolutePath = path.join(
- path.dirname(paths.appSkuConfigPath),
- '.storybook',
- previewFileName,
-);
-
-/**
- * This function first cleans up any existing preview.{js,ts,tsx} files in the provided storybook config directory.
- * This includes any potentially dangling symlinks.
- * Then it looks for a `.storybook/preview.{js,ts,tsx}` file relative to the sku config.
- * If 1 file is found, a symlink pointing to it is created in the provided storybook config directory.
- * Does nothing if 0 or >1 files are found.
- *
- * @param {string} storybookConfigDirectory The path to the storybook config directory
- */
-const setUpStorybookPreviewFile = async (storybookConfigDirectory) => {
- const symlinkFileAsbolutePath = path.join(
- storybookConfigDirectory,
- previewFileName,
- );
- const symlinkFiles = await glob(symlinkFileAsbolutePath, {
- dot: true,
- onlyFiles: false, // Required to find dangling symlinks
- });
-
- // Clean up any existing files in the storybook config folder so we have a clean slate
- for (const symlinkFile of symlinkFiles) {
- await fs.unlink(symlinkFile);
- log(`Cleaning up exising file ${symlinkFile}.`);
- }
+const managedConfigBanner = require('./managedConfigBanner');
- const previewFiles = await glob(previewFileAbsolutePath);
+// Since this config will be in the user's project, we can use ESM
+// Spread `storybookConfig` to prevent warning
+// https://github.com/storybookjs/storybook/issues/23675
+const mainConfigFileContents = `${managedConfigBanner}
+import storybookConfig from 'sku/config/storybook';
- if (previewFiles.length > 1) {
- console.error(
- 'Multiple storybook preview files found. Please only define a single preview file.',
- );
- console.error(previewFiles);
+export default { ...storybookConfig };
+`;
- return;
- }
+const storybookMainConfigPath = '.storybook/main.js';
+const storybookConfigDirectory = path.dirname(storybookMainConfigPath);
- const previewFile = previewFiles?.[0];
-
- if (previewFile) {
- const previewFileExtension = path.extname(previewFile);
- const symlinkFile = path.join(
+const setUpStorybookConfigDirectory = async () => {
+ await fs.mkdir(storybookConfigDirectory, { recursive: true });
+ log(
+ `Created '${path.resolve(
storybookConfigDirectory,
- `preview${previewFileExtension}`,
- );
-
- log(`Found preview file at ${previewFile}`);
- log(`Creating symlink from ${symlinkFile} to ${previewFile}`);
+ )}' directory if it didn't exist`,
+ );
- await fs.symlink(previewFile, symlinkFile);
- }
+ await fs.writeFile(storybookMainConfigPath, mainConfigFileContents);
+ log(
+ `Wrote storybook config file to '${path.resolve(storybookMainConfigPath)}'`,
+ );
};
-module.exports = { setUpStorybookPreviewFile };
+module.exports = { setUpStorybookConfigDirectory, storybookMainConfigPath };
diff --git a/packages/sku/scripts/build-storybook.js b/packages/sku/scripts/build-storybook.js
index 5952879b1..d7ccabb1a 100644
--- a/packages/sku/scripts/build-storybook.js
+++ b/packages/sku/scripts/build-storybook.js
@@ -1,23 +1,20 @@
// First, ensure the build is running in production mode
process.env.NODE_ENV = 'production';
-const path = require('path');
const { rimraf } = require('rimraf');
const { argv, config } = require('../config/args');
const gracefulSpawn = require('../lib/gracefulSpawn');
const { storybookTarget } = require('../context');
const buildStorybookPath = require.resolve('@storybook/cli/bin/index');
-const configDir = path.resolve(__dirname, '../config/storybook/build');
const { runVocabCompile } = require('../lib/runVocab');
-const { setUpStorybookPreviewFile } = require('../lib/storybook');
+const { setUpStorybookConfigDirectory } = require('../lib/storybook');
(async () => {
await runVocabCompile();
await rimraf(storybookTarget);
- await setUpStorybookPreviewFile(configDir);
+ await setUpStorybookConfigDirectory();
argv.push('build');
- argv.push('--config-dir', configDir);
argv.push('--output-dir', storybookTarget);
argv.push('--quiet');
diff --git a/packages/sku/scripts/storybook.js b/packages/sku/scripts/storybook.js
index c82cb7d2b..0f9783022 100644
--- a/packages/sku/scripts/storybook.js
+++ b/packages/sku/scripts/storybook.js
@@ -1,21 +1,18 @@
-const path = require('path');
const { argv, config } = require('../config/args');
const gracefulSpawn = require('../lib/gracefulSpawn');
const { storybookPort } = require('../context');
const startStorybookPath = require.resolve('@storybook/cli/bin/index');
-const configDir = path.resolve(__dirname, '../config/storybook/start');
const { watchVocabCompile } = require('../lib/runVocab');
-const { setUpStorybookPreviewFile } = require('../lib/storybook');
+const { setUpStorybookConfigDirectory } = require('../lib/storybook');
// Unshift args to allow pushing --ci as an arg during storybook-config tests
argv.unshift('--quiet');
-argv.unshift('--config-dir', configDir);
argv.unshift('--port', storybookPort);
argv.unshift('dev');
(async () => {
await watchVocabCompile();
- await setUpStorybookPreviewFile(configDir);
+ await setUpStorybookConfigDirectory();
const storybookProcess = gracefulSpawn(startStorybookPath, argv, {
stdio: 'inherit',
diff --git a/tests/configure.test.ts b/tests/configure.test.ts
index 53b5ff3a7..12bb29fa6 100644
--- a/tests/configure.test.ts
+++ b/tests/configure.test.ts
@@ -77,9 +77,10 @@ describe('configure', () => {
it(`should generate \`.gitignore\``, async () => {
const ignoreContents = await readIgnore(appFolder, '.gitignore');
- expect(ignoreContents.length).toEqual(7);
+ expect(ignoreContents.length).toEqual(8);
expect(ignoreContents).toContain(`.eslintrc`);
expect(ignoreContents).toContain(`.prettierrc`);
+ expect(ignoreContents).toContain(`.storybook/main.js`);
expect(ignoreContents).toContain(`${defaultTargetDir}/`);
expect(ignoreContents).toContain(`${defaultStorybookTargetDir}/`);
expect(ignoreContents).toContain(`${bundleReportFolder}/`);
@@ -90,8 +91,9 @@ describe('configure', () => {
['.eslintignore', '.prettierignore'].forEach((ignore) =>
it(`should generate \`${ignore}\``, async () => {
const ignoreContents = await readIgnore(appFolder, ignore);
- expect(ignoreContents.length).toEqual(5);
+ expect(ignoreContents.length).toEqual(6);
expect(ignoreContents).toContain('*.less.d.ts');
+ expect(ignoreContents).toContain(`.storybook/main.js`);
expect(ignoreContents).toContain(`${defaultTargetDir}/`);
expect(ignoreContents).toContain(`${bundleReportFolder}/`);
expect(ignoreContents).toContain(`${coverageFolder}/`);
@@ -137,10 +139,11 @@ describe('configure', () => {
it(`should generate \`.gitignore\``, async () => {
const ignoreContents = await readIgnore(appFolderTS, '.gitignore');
- expect(ignoreContents.length).toEqual(7);
+ expect(ignoreContents.length).toEqual(8);
expect(ignoreContents).toContain(`.eslintrc`);
expect(ignoreContents).toContain(`.prettierrc`);
expect(ignoreContents).toContain(`tsconfig.json`);
+ expect(ignoreContents).toContain(`.storybook/main.js`);
expect(ignoreContents).toContain(`${skuConfig.target}/`);
expect(ignoreContents).toContain(`${skuConfig.storybookTarget}/`);
expect(ignoreContents).toContain(`${bundleReportFolder}/`);
@@ -150,8 +153,9 @@ describe('configure', () => {
['.eslintignore', '.prettierignore'].forEach((ignore) =>
it(`should generate \`${ignore}\``, async () => {
const ignoreContents = await readIgnore(appFolderTS, ignore);
- expect(ignoreContents.length).toEqual(5);
+ expect(ignoreContents.length).toEqual(6);
expect(ignoreContents).toContain('*.less.d.ts');
+ expect(ignoreContents).toContain(`.storybook/main.js`);
expect(ignoreContents).toContain(`${skuConfig.target}/`);
expect(ignoreContents).toContain(`${skuConfig.storybookTarget}/`);
expect(ignoreContents).toContain(`${bundleReportFolder}/`);