DEV Community

Cover image for How to show your Storybook in Azure DevOps without hosting it
Ken
Ken

Posted on Edited on

How to show your Storybook in Azure DevOps without hosting it

This post covers why I made it ans how it works. It's my own project, not affiliated with Microsoft or the Storybook team.

The problem: the component library lives somewhere else

Storybook is a good place to build, document and review UI components in isolation. But in many teams that use Azure DevOps, the Storybook doesn't live where the team works.

It tends to end up in one of two places. Either it only runs on a developer's laptop, so designers, testers and product owners never see it. Or someone hosts it: a static site, a storage account, a separate deployment pipeline.

Hosting works, but it brings its own chores. The hosted copy drifts from the code whenever someone forgets to deploy. It's another place to manage who has access, apart from the permissions you already set in Azure DevOps. And it's another link for people to find, bookmark and lose.

I wanted the component library to sit where the work already happens. Versioned with the code, and visible to the people who can already see that code.

What the extension does

The extension adds a Designs hub to the navigation of every project. Open it and you see the project's Storybook, running inside Azure DevOps.

There's no hosting and no extra sign-in. The hub reads the built Storybook (the storybook-static folder) straight from Azure Repos, at the latest commit of its branch, as the signed-in user. A service worker in your browser passes the files to the page without keeping copies. The extension has no server of its own, uploads nothing and collects no analytics.

A few things follow from that:

  • It's versioned with your code. There's no separate deployment to drift. Push a new build and the hub shows it the next time someone opens or refreshes Designs.
  • It uses your permissions. People who can't read the repository don't see the Storybook.
  • Each project has one Storybook, so everyone looks at the same component library.

A team workflow around one Storybook

From left to right: Plan in Azure Boards, Design in the project Storybook, Build in Azure Repos, Test in Azure Test Plans, Review in a pull request, Deploy with Azure Pipelines, and Run in production

The extension only adds Designs; Boards, Repos, Test Plans and Pipelines are the Azure DevOps you already have. With one Storybook per project, work items, test cases and pull requests can all refer to the same components. The hub shows the Storybook's own branch, though, so there's no preview per pull request.

What's in the project Storybook

I didn't want Create project Storybook to hand you a blank page. It gives the team what a component library needs on day one: a design system, components and guidelines.

The project Storybook's Design System, Components and Guidelines sections

  • Design system. Colour, typography, iconography and layouts. All values live in src/design-system/tokens.ts. theme.ts turns them into --ds-* CSS custom properties, with a light and a dark value for text, background and border colours, and the components use only those variables. To rebrand, edit tokens.ts, check the live contrast ratios on the Accessibility guideline, preview with npm run storybook, then build and commit. The example values are Storybook's own design system.
  • Components. Ten essentials: Alert, Avatar, Badge, Button, Card, Checkbox, RadioGroup, Select, Switch and TextField. They're built on native HTML, with labels, hints and errors wired up for screen readers, and every state has its own story.
  • Guidelines. Five pages, each with do and don't boxes and live examples built from the project's own components: Accessibility (WCAG 2.2 AA, with contrast ratios calculated live from your tokens), Content Design, Design Tokens, Onboarding (empty states, starter content and help) and Waiting (loading, progress and errors).

It's a starting point, not a finished product or an accessibility guarantee. The starter files are under the MIT licence, so they're yours to change (third-party parts, such as the npm packages and bundled fonts, keep their own licences).

Get started in a minute

Opening Designs in an Azure DevOps project, creating the project Storybook and seeing it load

  1. Install it. An organisation administrator selects Get it free on the Marketplace page. A Designs hub then appears in every project.
  2. Open Designs in your project. If the project has no Storybook yet, you see a start page with two buttons.
  3. Add the project's Storybook, in one of two ways:
    • Create project Storybook creates a <project>.Storybook repository and pushes a ready-built Storybook (React, Vite and TypeScript, on Storybook 10) to its main branch. You need permission to create repositories in the project.
    • Publish code as Storybook uses a Storybook that's already in one of your repositories. Just like Publish code as wiki, you pick the repository, branch and folder. Pick the Storybook project folder (the one with package.json and .storybook/; the hub looks for <folder>/storybook-static/iframe.html), or any folder that contains iframe.html. Commit its storybook-static build too (more on that below).
  4. Browse your components in the Designs hub. A created Storybook is already built, so it shows straight away.
  5. Protect the Storybook's branch. In Repos > Branches, pick the Storybook's repository, open the branch's More options > Branch policies and turn on Require a minimum number of reviewers. For a created Storybook that's main in <project>.Storybook. The build runs with each viewer's access; see Permissions and security below.

You can change the repository, branch or folder later with Storybook Settings, in the More actions menu above the Storybook.

Keeping it up to date

The hub doesn't build anything. It shows the storybook-static build that's committed to the repository. After changing components or stories, build it and commit the result:

npm run build-storybook
git add storybook-static
git commit -m "Build Storybook"
git push
Enter fullscreen mode Exit fullscreen mode

If your .gitignore lists storybook-static (storybook init adds it), remove that line once. The created Storybook doesn't ignore it. To check whether git ignores it, run git check-ignore -v storybook-static/index.html; no output means it isn't ignored.

If the branch has a policy (and it should, see below), the new build arrives when the pull request is completed. Refresh the hub and it shows the latest commit.

Committing build output isn't to everyone's taste. I chose it because it means no build service and no hosting. The build is just files in your repository, versioned with everything else.

Light or dark, like Azure DevOps

The Storybook follows the theme you picked in Azure DevOps. In a dark theme it's dark too. When you switch themes, it reloads in the new theme on the story you had open.

The project Storybook's introduction page in the light Azure DevOps theme and in the dark theme

Storybook's interface takes its background colour from your Azure DevOps theme, so it looks like part of Azure DevOps. That works for any Storybook in the hub, including one you publish from your own code, without changes. Docs pages need three lines in .storybook/preview.ts to go dark, and the created Storybook already has them. For your own Storybook, add them to .storybook/preview.ts, then rebuild and commit:

// .storybook/preview.ts (Storybook 9 and 10; in Storybook 8, import themes from '@storybook/theming')
import { themes } from 'storybook/theming';

const dark = window.matchMedia('(prefers-color-scheme: dark)').matches;
// in the preview's parameters:
// docs: { theme: dark ? themes.dark : themes.light },
Enter fullscreen mode Exit fullscreen mode

One caveat: the hub doesn't change CSS prefers-color-scheme media queries inside your own components.

Permissions and security

I want to be upfront about this part.

The extension asks for the Code (read, write & manage) scope. It uses it to create the project's Storybook repository and to read the built Storybook. It always acts as the signed-in user, so it can't see or change anything that person can't.

The important bit: the committed Storybook build runs inside the Designs hub with the same access as the person viewing it. So anyone who can push to the Storybook's branch can run code that acts as everyone who views it. The extension has no server of its own, so it can't serve the build from a separate origin. The only full fix would be hosting, which is exactly what I set out to avoid.

So treat a push to that branch like installing code that runs as your users:

  • Protect the Storybook's branch with a branch policy that requires at least one reviewer.
  • Keep the number of people who can bypass branch policies small.
  • Only publish a Storybook from a repository and branch where you trust everyone who can push.

Viewers need Basic access or higher, and Read permission on the Storybook's repository. Stakeholder access doesn't include Azure Repos, so Designs doesn't appear for Stakeholders at all. Make sure everyone who uses the hub can read the Storybook's repository. Someone without Read sees the start page, and if they then create or publish a Storybook, it replaces the project's Storybook for everyone.

What I'd like feedback on

The extension is new, and I'd like to hear how it holds up in real teams. Answer in the comments here. Bugs are easier to track on the Q & A tab of the Marketplace page.

  • Does building and committing storybook-static fit how your team works? If not, how do you keep your Storybook up to date today?
  • Did your existing Storybook work with Publish code as Storybook? If something broke, what was it?
  • Are the starter design system, components and guidelines a useful starting point, or would you rather start smaller?
  • If you're a designer, tester or product owner: what would make the Designs hub more useful to you?

Try it

You can install it from the Marketplace with Get it free:

Storybook on the Visual Studio Marketplace

Have a question, found a bug, or have an idea for improvement? Feel free to post it in the Q&A tab on that page. I review all feedback, but I can't promise that every requested feature or change will be added: the extension is free and comes as it is. And if it saves your team some time, there's a Buy Me a Coffee button on the same page.

Thanks for reading.

Top comments (0)