vite_ruby
vite_ruby copied to clipboard
Allow `rollupOptions` set by other plugins to be respected
Description 📖
Storybook (builder-vite) adds an iframe.html entry into the rollupOptions when building a static build. I found that vite-plugin-ruby is overriding these options meaning that the Storybook build fails.
Background 📜
Storybook builds are failing for projects using vite-plugin-ruby or vite-plugin-rails.
Build/Rollup options without the spread:
{
emptyOutDir: false,
sourcemap: true,
target: [ 'chrome108', 'edge108', 'firefox109', 'ios15', 'safari15' ],
outDir: '<path-to-project>/storybook-static',
rollupOptions: {
external: [ './sb-preview/runtime.js', /\.\/sb-common-assets\/.*\.woff2/ ],
input: {
'entrypoints/application.ts': '<path-to-project>/app/frontend/entrypoints/application.ts',
'entrypoints/vue.ts': '<path-to-project>/app/frontend/entrypoints/vue.ts'
},
output: {
assetFileNames: [Function (anonymous)],
entryFileNames: [Function (anonymous)]
}
},
assetsDir: 'assets',
manifest: true
}
The Fix 🔨
Here I am allowing any existing rollup options + inputs to be spread into the config before the plugin returns it.
Rollup options with the spread:
build: {
emptyOutDir: false,
sourcemap: true,
target: [ 'chrome108', 'edge108', 'firefox109', 'ios15', 'safari15' ],
outDir: '<path-to-project>/storybook-static',
rollupOptions: {
external: [ './sb-preview/runtime.js', /\.\/sb-common-assets\/.*\.woff2/ ],
input: {
'<path-to-project>/node_modules/.pnpm/@[email protected][email protected]_@[email protected]_@babel_mehfrma2w74ofinzeaaidxqt6y/node_modules/@storybook/builder-vite/input/iframe.html': '<path-to-project>/node_modules/.pnpm/@[email protected][email protected]_@[email protected]_@babel_mehfrma2w74ofinzeaaidxqt6y/node_modules/@storybook/builder-vite/input/iframe.html',
'entrypoints/application.ts': '<path-to-project>/app/frontend/entrypoints/application.ts',
'entrypoints/vue.ts': '<path-to-project>/app/frontend/entrypoints/vue.ts'
},
output: {
assetFileNames: [Function (anonymous)],
entryFileNames: [Function (anonymous)]
}
},
assetsDir: 'assets',
manifest: true
},
Notes
I appreciate this may not be the correct fix for the problem. If you would like a different style / approach to solve this please let me know!
Woah! Well done figuring this one out. I've been struggling with the storybook static builds for years on my vite-ruby projects and could not understand what was going on!
@ElMassimo any chance you could have a look? I appreciate all your hard work and know that you have a lot on your plate with your suite of OSS projects so don't mean to rush you/come across as ungrateful.
This would be awesome for all of us vite_ruby using teams who use storybook as documentation for our front end. ❤️ Cheers!
Also just run into this issue and couldn't understand why the iframe was missing until I came across this discussion.
Is there a way to patch this manually until a proper fix is in place? I tried using the patched Gem:
gem 'vite_rails', github: 'blake-simpson/vite_ruby', branch: 'patch-1'
But the iframe is still missing from builds...
Thanks
@ElMassimo I've seen that this is merged now, but still not getting the iframe in the Storybook output after updating to the latest version of this gem... do I need to update something else as well?
@ElMassimo I've seen that this is merged now, but still not getting the iframe in the Storybook output after updating to the latest version of this gem... do I need to update something else as well?
Same @iamdriz, maybe it makes most sense to continue the conversation here. We might have had a different issue than @blake-simpson that's not vite_ruby related.
@eriknygren Yeah I'm seeing the same issue as mentioned in the other conversation with the iframe.html being added into /public/vite folder instead of storybook-static. The comments seem to still suggest that vite_ruby is the culprit.
@iamdriz seeing the same. @blake-simpson have you got this working on your end now?
Hi all, sorry for the late reply, I was away on a longer vacation.
First of all thank you @ElMassimo for merging + releasing this!
To the thread above, I also have the same issue. I can't quite pin down why but it seems all of the rollup options for vite-plugin-ruby ensure that the assets are built into the ./vite directory instead of of the usual static one. I think it may be related to making the Ruby on Rails asset pipeline work? I think changing this may break this library entirely though, so I've been working with the following hack:
storybook build --force-build-preview --preview-url=vite/iframe.html && \
cp -R storybook-static/sb-preview storybook-static/vite && \
cp -R storybook-static/sb-common-assets storybook-static/vite && \
cp -R storybook-static/sb-addons storybook-static/vite && \
cp storybook-static/index.json storybook-static/vite/index.json
It's ugly but the best I can figure out for now. I'd be happy to hear if someone has a better way or if @ElMassimo knows a way to make the files build into . instead of ./vite when using Storybook?
This is however working for me locally but I'm having issues with GitHub pages. If anyone has anymore input please let me know.
cc/ @eriknygren @iamdriz
Thanks @blake-simpson for getting back to us. So I don't really understand the nuances of this, my iframe.html ends up in the vite-dev folder for example (and others have reported it ending up in the vite folder), even though I'm building with both NODE_ENV and RAILS_ENV set to production 🤷
And even when I copy files over manually, loading a page from the static build results in no components, it doesn't even look like it's trying to fetch them.
I feel pretty stuck on this and don't know what to suggest. Maybe another approach is needed, maintaining a completely separate vite config for storybook for example. Would love to hear if anyone does find a solution, but personally I've sort of given up at the moment (althought I would love to have this working).
a way to make the files build into . instead of ./vite when using Storybook
Have you tried configuring publicOutputDir to .?
Maybe you could pass the VITE_RUBY_PUBLIC_OUTPUT_DIR="." environment variable when building Storybook. I haven't used Storybook, so I'm not familiar on whether it requires a separate command to build, or if it's integrated in the default Vite build.
@ElMassimo Thank you that helps with the VITE_RUBY_PUBLIC_OUTPUT_DIR var. I now have to move a lot less files around.
Interestingly though for me, in this case, the ifame.html no longer builds into the . dir (<rails-root>/storybook-static/) but instead into ../public (<rails-root>/public/)
I'm not sure why that is happening but personally I am copying that file over + the assets (also in ../public) after build. Just an FYI to others who are on this chain.
I'm returning with some good news, just got this working for me! 🎉
Running the storybook build command with these output dir vars have made sure everything ends up where expected. So in my package.json I build storybook with
"build-storybook": "VITE_RUBY_PUBLIC_OUTPUT_DIR='.' VITE_RUBY_PUBLIC_DIR='./storybook-static' storybook build"
In my storybook config (.storybook/main.js), to resolve imports to my components, I copy that over from the main vite config with:
import path from 'path';
const config = {
...
staticDirs: ['../public'],
async viteFinal(storybookConfig) {
const { mergeConfig, loadConfigFromFile } = await import('vite');
const { config: mainAppConfig } = await loadConfigFromFile(
path.resolve(__dirname, '../vite.config.ts'),
);
const pickedConfigFieldsFromMainApp = { resolve: mainAppConfig.resolve };
const mergedConfig = mergeConfig(storybookConfig, pickedConfigFieldsFromMainApp);
return mergedConfig;
},
...
};
export default config;
Without needing to copy anything over, runtime.js from storybook seems to be in the right place, and so does iframe.html
Hopefully this unblocks everyone else too! cc @blake-simpson @iamdriz
Edit: On a second review: I think the .storybook/main.js part is not needed. I hadn't realise it was clever enough to merge things in from your vite.config.ts to start with.
I ended up having to solve this too and none of the other solutions seemed to work. I'm unsure if something changed since the previous solutions were posted here. Importantly, what I noticed was that any time vite-plugin-ruby was included, the iframe.html was just not being generated what so ever. Not in storybook-static/ nor in any subdirectory in public/. I'm not sure why that is, but to resolve it I ensured that the vite-plugin-ruby was not included in the plugins for Storybook.
To note, we're using vite-plugin-rails and adding it like so
in vite.config.ts (isn't isn't everything in our file, just enough to show how we're adding a couple plugins)
import path from "node:path";
import { fileURLToPath, URL } from "node:url";
import { defineConfig } from "vite";
import Vue from "@vitejs/plugin-vue";
import ViteRails from "vite-plugin-rails";
export default defineConfig(({ mode }) => ({
define: {
"process.env.NODE_ENV": JSON.stringify(mode),
},
plugins: [
Vue(),
ViteRails(),
],
})
in .storybook/main.ts
import type { StorybookConfig } from "@storybook/vue3-vite";
const config: StorybookConfig = {
...
viteFinal(config) {
if (config.plugins) {
const newPlugins = config.plugins.filter((plugin) => {
// We're looking for the vite-plugin-ruby and its pals. They appear to come in
// as an array
if (Array.isArray(plugin)) {
// Confirm vite-plugin-ruby is in this array
const rubyExists = plugin.some(obj => {
if (obj && 'name' in obj) {
return obj.name.startsWith('vite-plugin-ruby')
} else {
return false
}
})
// If vite-plugin-ruby was found, we want to filter this array of plugins out of our Storybook build
return !rubyExists;
} else {
return true
}
})
config.plugins = newPlugins;
}
return config
}
};
export default config;
The viteFinal can be made more concise and comments removed, but this verbose version helps to explain what is going on. Hope this helps if anyone else runs into the same issue!