-
-
Notifications
You must be signed in to change notification settings - Fork 95
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: create nuxt instance more reliable (#619)
Fixes storybook-vue/storybook-nuxt#97 ``` Error: [nuxt] instance unavailable ```
- Loading branch information
1 parent
d1bd15a
commit 4f97749
Showing
7 changed files
with
118 additions
and
101 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import type { Meta, StoryObj } from '@storybook/vue3' | ||
|
||
import UseComposable from './UseComposable.vue' | ||
|
||
// More on how to set up stories at: https://storybook.js.org/docs/vue/writing-stories/introduction | ||
|
||
/** | ||
* Shows how to use a composable in a component | ||
*/ | ||
const meta = { | ||
title: 'Features/Use Composable', | ||
component: UseComposable, | ||
// This component will have an automatically generated docsPage entry: https://storybook.js.org/docs/vue/writing-docs/autodocs | ||
tags: ['autodocs'], | ||
} satisfies Meta<typeof UseComposable> | ||
|
||
export default meta | ||
type Story = StoryObj<typeof meta> | ||
/* | ||
*👇 Render functions are a framework specific feature to allow you control on how the component renders. | ||
* See https://storybook.js.org/docs/vue/api/csf | ||
* to learn how to use render functions. | ||
*/ | ||
|
||
export const UseComposableStory: Story = { | ||
args: {}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<script setup lang="ts"> | ||
const { config } = useMyComposable() | ||
</script> | ||
|
||
<template> | ||
<h1>Using composable</h1> | ||
<h5>runtime config :</h5> | ||
<pre>{{ config }}</pre> | ||
</template> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
export function useMyComposable() { | ||
// Because your composable is called in the right place in the lifecycle, | ||
// useRuntimeConfig will also work | ||
const config = useRuntimeConfig() | ||
// console.log('useMyComposable config', config) | ||
return { config } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,63 @@ | ||
const vueAppRootContainer = document.createElement('div') | ||
vueAppRootContainer.id = '__nuxt' | ||
vueAppRootContainer.setAttribute('hidden', 'true') | ||
document.body.appendChild(vueAppRootContainer) | ||
/** | ||
* This is loaded by the Storybook canvas preview iframe and applies to all stories. | ||
* https://github.com/storybookjs/storybook/blob/main/docs/contribute/framework.md#4-author-the-framework-itself | ||
* https://github.com/storybookjs/storybook/blob/main/docs/configure/index.md#configure-story-rendering | ||
* | ||
* We use it to load the Nuxt app in the preview iframe. | ||
* This should contain the same setup as the what Nuxt does in the background. | ||
* https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/entry.ts | ||
*/ | ||
|
||
// entry() | ||
const logger = console | ||
async function nuxtAppEntry() { | ||
const nuxtApp = () => import('#app/entry').then((m) => m.default) | ||
return nuxtApp() | ||
} | ||
import { setup } from '@storybook/vue3' | ||
import type { ObjectPlugin, Plugin } from 'nuxt/app' | ||
import { applyPlugins, createNuxtApp } from 'nuxt/app' | ||
import { getContext } from 'unctx' | ||
|
||
nuxtAppEntry().then((app) => { | ||
logger.log('nuxtAppEntry done', app) | ||
app() | ||
.then(() => { | ||
logger.log('nuxtAppEntry app done') | ||
}) | ||
.catch(() => { | ||
logger.log('nuxtAppEntry app error') | ||
}) | ||
// app() | ||
}) | ||
// This is used to overwrite the fetch function, not sure if it's necessary for Storybook | ||
// It doesn't work with the current setup | ||
// import '#build/fetch.mjs' | ||
import '#build/css' | ||
// @ts-expect-error virtual file | ||
import plugins from '#build/plugins' | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const pluginsTyped: Array<Plugin & ObjectPlugin<any>> = plugins | ||
|
||
setup(async (vueApp, storyContext) => { | ||
// We key the Nuxt apps to the id of the story | ||
// This is not totally correct, since the storybook vue renderer actually uses the canvas element | ||
// Also this doesn't allow to "forceRemount" | ||
// TODO: Improve this (needs PR to storybook to pass the necessary infos to this function) | ||
const key = storyContext?.id | ||
if (!key) { | ||
throw new Error('StoryContext is not provided') | ||
} | ||
const nuxtAppName = `nuxt-app-${key}` | ||
const nuxtCtx = getContext(nuxtAppName) | ||
if (nuxtCtx.tryUse()) { | ||
// Nothing to do, the Nuxt app is already created | ||
return | ||
} | ||
|
||
export default nuxtAppEntry | ||
const nuxt = createNuxtApp({ | ||
vueApp, | ||
globalName: nuxtAppName, | ||
}) | ||
await applyPlugins( | ||
nuxt, | ||
// The revive plugin deletes the nuxt context (window.__NUXT__) | ||
// which leads to problems down the line | ||
// So we don't apply it here, although that's probably not the best solution | ||
// https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/plugins/revive-payload.client.ts | ||
pluginsTyped.filter( | ||
(plugin) => plugin.name === 'nuxt:revive-payload:client', | ||
), | ||
) | ||
await nuxt.hooks.callHook('app:created', vueApp) | ||
await nuxt.hooks.callHook('app:beforeMount', vueApp) | ||
nuxtCtx.set(nuxt, true) | ||
|
||
// TODO: The following are usually called after the app is mounted | ||
// but currently storybook doesn't provide a hook to do that | ||
// await nuxt.hooks.callHook('app:mounted', vueApp) | ||
// await nextTick() | ||
}) |
This file was deleted.
Oops, something went wrong.