storybook icon indicating copy to clipboard operation
storybook copied to clipboard

[Bug]: Storybook 7 + builder-vite doesn't support deploy to subpath

Open akronb opened this issue 1 year ago • 3 comments

Describe the bug

I tried to configure and deploy my storybook to subpath /storybook. For that, I added new base path to vite config

  async viteFinal(config) {
    return mergeConfig(config, {
      base: "/storybook/",
    });
  },

After deploying the new build, I found that only some of the paths had changed to '/storybook', the rest remained unchanged.

To Reproduce

https://github.com/akronb/storybook7-vite-subpath-example

The generated build is already in the directory storybook-static

System

Environment Info:

  System:
    OS: macOS 13.1
    CPU: (8) arm64 Apple M1
  Binaries:
    Node: 16.15.1 - /opt/homebrew/opt/node@16/bin/node
    Yarn: 1.22.19 - /opt/homebrew/opt/node@16/bin/yarn
    npm: 8.11.0 - /opt/homebrew/opt/node@16/bin/npm
  Browsers:
    Chrome: 111.0.5563.64
    Safari: 16.2
  npmPackages:
    @storybook/addon-essentials: ^7.0.0-rc.3 => 7.0.0-rc.3
    @storybook/addon-interactions: ^7.0.0-rc.3 => 7.0.0-rc.3
    @storybook/addon-links: ^7.0.0-rc.3 => 7.0.0-rc.3
    @storybook/blocks: ^7.0.0-rc.3 => 7.0.0-rc.3
    @storybook/react: ^7.0.0-rc.3 => 7.0.0-rc.3
    @storybook/react-vite: ^7.0.0-rc.3 => 7.0.0-rc.3
    @storybook/testing-library: ^0.0.14-next.1 => 0.0.14-next.1

Additional context

No response

akronb avatar Mar 16 '23 09:03 akronb

The default base is relative should allow for deploying in a subpath, for example in github pages. Can you explain a bit more about how you are deploying the storybook?

IanVS avatar Mar 17 '23 13:03 IanVS

Can you explain a bit more about how you are deploying the storybook?

The Storybook is put into a docker container with nginx, and the container distributes it to http://mysite.io/storybook.

After your comment, I looked into nginx behavior and stackoverflow, and it turned out that the problem was a lack of trailing slash.

For the URL http://mysite.io/storybook, the browser converts <link href="./sb-preview/runtime.mjs" rel="preload" as="script" /> to http://mysite.io/sb-preview/runtime.mjs, because the relative path is built from the last / in the URL.

I still have a question about the base path in vite config. It was added to some of the paths (like /assets/iframe.js), the rest remain relative. Shouldn't the behavior be consistent?

akronb avatar Mar 17 '23 17:03 akronb

Shouldn't the behavior be consistent?

Yes, but I think some of those paths are created by parts of storybook that are not part of the preview / vite builder. I haven't dug into it, but that's my guess as to what is happening.

IanVS avatar Mar 17 '23 18:03 IanVS

Any update on this?

Stunext avatar Apr 20 '23 02:04 Stunext

@Stunext are you having issues? Can you describe what they are? Storybook can be deployed to a subpath so long as you don't set a base config. As far as I know, nobody has done any further work on this to support setting the base explicitly. Is that something you need to do?

IanVS avatar Apr 20 '23 11:04 IanVS

Maybe it's my mistake... I've created a component library in React that I install in other projects via Git. The library is implemented on top of storybook and a static version of the storybook is also included in the library installation. At the same time the library exports a plugin for Vite that implemented redirects the path that starts with "/storybook" to the folder in node_modules of the storybook build. So that during "vite dev" you can access the library documentation directly in a project path.

The problem is that the paths in the storybook build ignore this additional "/storybook/" path and try to access from the "/" root even by adding base: "/storybook/", in viteFinal. Due to not being able to solve the problem I am left with this monstrosity in the plugin.

export default function ProjectLib() {
    return {
        name: 'project-lib',
        configureServer(server) {

            server.middlewares.use(async(req, res, next) => {

                try {
                    
                    let referer = req.headers.referer;
                    let url = req.url.split(/[?#]/)[0];
                    let filePath = '';
                    
                    switch (true) 
                    {
                        case url.startsWith('/storybook'):
                        {
                            filePath = resolve(__dirname, 'node_modules/project-lib/dist/docs/index.html')

                            createReadStream(filePath).pipe(res)
                        }
                        break;
                        case url.startsWith('/sb-common-assets'):
                        case url.startsWith('/sb-manager'):
                        case url.startsWith('/sb-addons'):
                        case url.startsWith('/sb-preview'):
                        case url.startsWith('/static'):
                        case url.startsWith('/assets'):
                        {
                            filePath = resolve(__dirname, 'node_modules/project-lib/dist/docs/' + url)

                            if (statSync(filePath).isDirectory()) 
                            {
                                filePath = resolve(filePath, 'index.html')
                            }
                            if (statSync(filePath).isFile()) 
                            {
                                if (filePath.endsWith('.js') || filePath.endsWith('.mjs')) 
                                {
                                    res.setHeader('Content-Type', 'application/javascript');
                                }
                                createReadStream(filePath).pipe(res)
                            }
                        }
                        break;
                        case referer.endsWith('/storybook'):
                        {
                            filePath = resolve(__dirname, 'node_modules/project-lib/dist/docs' + url)
                            if (filePath.endsWith('.js') || filePath.endsWith('.mjs')) 
                            {
                                res.setHeader('Content-Type', 'application/javascript');
                            }
                            createReadStream(filePath).pipe(res)
                        }
                        break;
                        case referer.includes('/storybook?path'):
                        case referer.includes('/iframe.html?viewMode'):
                        {
                            filePath = resolve(__dirname, 'node_modules/project-lib/dist/docs' + url)

                            if (statSync(filePath).isDirectory()) 
                            {
                                filePath = resolve(filePath, 'index.html')
                            }
                            if (statSync(filePath).isFile()) 
                            {
                                if (filePath.endsWith('.js') || filePath.endsWith('.mjs')) 
                                {
                                    res.setHeader('Content-Type', 'application/javascript');
                                }
                                createReadStream(filePath).pipe(res)
                            }
                        }
                        break;
                        default:
                        {
                            next()
                        }
                        break;
                    }

                } catch (error) {
                    next()
                }
            })
        }
    }
}

Stunext avatar Apr 22 '23 16:04 Stunext

This works for me (using with Nuxt 3 as the webserver, eg: npm run build-storybook -- -o public/storybook && nuxt build):

  managerHead: (head, { configType }) => {
    if (configType === 'PRODUCTION') {
      return (`
        ${head}
        <base href="/storybook/">
      `);
    }
  },
  async viteFinal(baseConfig, { configType }) {
    return mergeConfig(
      baseConfig,
      {
        ...(configType === 'PRODUCTION' ? { base: '/storybook/' } : {}),
        // rest of config...
       }
     )

peteromano avatar Jul 21 '23 13:07 peteromano

Hi there! Thank you for opening this issue, but it has been marked as stale because we need more information to move forward. Could you please provide us with the requested reproduction or additional information that could help us better understand the problem? We'd love to resolve this issue, but we can't do it without your help!

github-actions[bot] avatar Aug 12 '23 01:08 github-actions[bot]

I'm afraid we need to close this issue for now, since we can't take any action without the requested reproduction or additional information. But please don't hesitate to open a new issue if the problem persists – we're always happy to help. Thanks so much for your understanding.

github-actions[bot] avatar Aug 20 '23 01:08 github-actions[bot]

Any progress? This is NOT fixed as v7.5.3.

mzvast avatar Nov 10 '23 09:11 mzvast