Closed alvarosabu closed 2 years ago
I might find why. Using the app coming from '@storybook/vue3' , its ssrContext
is undefined, which causes the issue.
const installQuasar = __QUASAR_SSR_SERVER__
? function (app, opts = {}, ssrContext) {
const $q = {
version: __QUASAR_VERSION__,
config: Object.freeze(opts.config || {})
}
ssrContext.$q = $q
Possible fix, adding a default value for ssrContext as an empty obj.
const installQuasar = __QUASAR_SSR_SERVER__
? function (app, opts = {}, ssrContext = {})
For some reason is treating Storybook as SSR. __QUASAR_SSR_SERVER__
is set to true
any updates on this ? same thing happens in jest.
took a look into the source code and built code, looks like the built code is only for SSR mode: https://github.com/quasarframework/quasar/blob/2.0.0-beta.11/ui/src/install-quasar.js#L70 this code is built into:
maybe the ssr option should be a run time config, something like:
app.use(Quasar, { ssr: true });
for now I have to use the umd version in jest:
moduleNameMapper: {
"^quasar$": "quasar/dist/quasar.umd.prod.js",
},
For anyone coming across this issue while trying to set up Storybook + Vue 3 + Quasar 2 as a Vue CLI plugin, this is how I got it working:
Create a Vue CLI app, install the Quasar plugin and npx sb init --type=vue3
as usual. Then tell the Vue instance running in Storybook to use Quasar just like you would in your app's main.ts
by adding the following to your .storybook/preview.js
file:
import { app } from "@storybook/vue3";
import { Quasar } from "quasar";
import quasarUserOptions from "../src/quasar-user-options";
app.use(Quasar, quasarUserOptions);
By default, Storybook doesn't know how to handle the scss
files imported in quasar-user-options
and also won't be able to resolve the Quasar variable paths. I fixed this by adding the following config in .storybook/webpack.config.js
:
module.exports = ({ config }) => {
config.resolve.alias = {
...config.resolve.alias,
"quasar-variables": "quasar/src/styles/quasar.variables.scss",
"quasar-variables-styl": "quasar/src/css/variables.sass",
"quasar-styl": "quasar/dist/quasar.sass",
"quasar-addon-styl": "quasar/src/css/flex-addon.sass",
};
config.module.rules.push({
test: /\.(scss|sass)$/,
use: ["style-loader", "css-loader", "sass-loader"],
include: path.resolve(__dirname, "../"),
});
return config;
};
I discovered the file paths by inspecting Vue's webpack config (vue-cli-service inspect
). Apparently the CLI plugin adds some aliases so we can import cleaner file names. Only tested it with small components so far but it seems to work just fine. Hope that helps.
Thanks @alvarosaburido, your descriptions pointed me in the right direction!
Hey @andreasphil . Eventually, I was able to make it work exactly as you did. Thanks for sharing
Ran into this issue when attempting to run unit tests on components using Quasar with vue-test-utils.
It thinks it is running in SSR mode, which I guess is kind of correct, but not, since that is not intended. I end up getting Cannot set property $q of undefined
when it tries to app.use
the plugin.
unfortunately using the workaround mentioned, for me, ends up with:
console.warn node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:40
[Vue warn]: A plugin must either be a function or an object with an "install" function.
console.warn node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:40
[Vue warn]: Failed to resolve component: q-page
at <HelloWorld ref="VTU_COMPONENT" >
at <VTUROOT>
because it is expecting import {Quasar} from 'quasar'
to be in cjs format, not umd format.
for reference, this is the workaround attempted:
for now I have to use the umd version in jest:
moduleNameMapper: { "^quasar$": "quasar/dist/quasar.umd.prod.js", },
for anyone coming to this with the same issue I had (unit testing with jest), I was able to make it work as follows:
in jest.config.js
:
moduleNameMapper: {
'^quasar$': 'quasar/dist/quasar.esm.prod.js'
},
then i created a Quasar helper file, quasarSetup.ts
:
import {config} from '@vue/test-utils'
import quasarUserOptions from '@/quasar-user-options.js'
import {Quasar} from 'quasar'
import {DefineComponent} from 'vue'
config.global.plugins.push([
Quasar,
quasarUserOptions
])
export function wrapInLayout<C extends DefineComponent<{}, {}, any>>(component: C) {
return {
template: `
<q-layout view="lHh Lpr lFf">
<UnderTest v-bind="$attrs"/>
</q-layout>
`,
components: {
UnderTest: component
}
}
}
then, usage example.spec.ts
:
import {mount} from '@vue/test-utils'
import {wrapInLayout} from '@/../tests/unit/imports/quasarSetup'
import HelloWorld from '@/components/HelloWorld.vue'
describe('HelloWorld.vue', () => {
it('renders', () => {
const wrapper = mount(wrapInLayout(HelloWorld))
const img = wrapper.find('img')
expect(img.attributes('alt')).toMatch('Quasar logo')
})
})
if you're using an icon set, you may have to jest.mock
any css files from those icon sets, but this got me going. Hope it helps!
I was able to get quasar-beta14 to run on my custom SSR setup with this:
// app.ts
import { SSRContext } from '@vue/server-renderer'
import { createSSRApp } from 'vue'
import App from './client/components/App.vue'
export type AppContext = SSRContext & {
// Needed by quasar
// Must match https://github.com/quasarframework/quasar/blob/c5a527b80de03fc40e03ab66f0a7afe3651a8fa7/ssr-helpers/create-renderer.js#L152-L158
_modules: Set<unknown>
_meta: Record<string, unknown>
onRendered: (fn: unknown) => void
}
export function createApp(ssrContext?: AppContext) {
const app = createSSRApp(App)
app.use(Quasar, {}, ssrContext) // Key part is this 3rd arg
return { app }
}
// www.ts
express.use('*', (req, res, next) => {
const onRenderedList: Array<unknown> = []
const ssrContext: AppContext = {
_modules: new Set(),
_meta: {},
onRendered: (fn) => { onRenderedList.push(fn) }, // No idea what this is used for
}
const { app } = createApp(ssrContext)
})
For anyone looking for Vue2/Quasar1 solution:
// app.ts
import App from './client/components/App.vue'
export function createApp(ssrContext?: AppContext) {
const router = createRouter()
const store = createStore()
const appOptions: ComponentOptions<Vue> = {
router: router,
store: store,
render: (createElement: CreateElement) => {
return createElement(App)
},
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
Quasar.ssrUpdate({
app: appOptions,
ssr: ssrContext,
})
const app = new Vue(appOptions)
return { app, router, store }
}
I personally think it's annoying that Quasar has so many undocumented global side effects and requires digging through their source code to fix these niche use cases
I can fixed it following @andreasphil solution https://github.com/quasarframework/quasar/issues/8607#issuecomment-813328197 whit some changes.
I have my project created with vue add quasar and vue add storybook (recent versions at 200-09-28) and keep failing with this solution.
As there have been several workarounds to everyone's issues, I am closing this issue. Feel free to re-open if there are still concerns.
Here is my Storybook + Quasar v2 configuration that worked with .sass variables:
// preview.js
import "@quasar/extras/roboto-font/roboto-font.css";
import "@quasar/extras/material-icons/material-icons.css";
import "@quasar/extras/animate/fadeInUp.css";
import "@quasar/extras/animate/fadeOutDown.css";
import "@quasar/extras/animate/fadeInRight.css";
import "@quasar/extras/animate/fadeOutRight.css";
import "quasar/dist/quasar.sass";
import "../src/assets/css/global.scss";
import { app } from "@storybook/vue3";
import { Quasar } from "quasar";
app.use(Quasar, {});
export const parameters = {
actions: { argTypesRegex: "^on[A-Z].*" },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
};
// main.js
const path = require("path");
module.exports = {
stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
addons: ["@storybook/addon-links", "@storybook/addon-essentials"],
framework: "@storybook/vue3",
webpackFinal: async (config, { configType }) => {
config.module.rules.push({
test: /\.scss$/,
use: [
"style-loader",
"css-loader",
{
loader: "sass-loader",
options: {
additionalData: `
@import './src/assets/css/imported/_variables.scss';
`,
},
},
],
});
config.module.rules.push({
test: /\.sass$/,
use: [
"style-loader",
"css-loader",
{
loader: "sass-loader",
options: {
additionalData: `
@import './src/assets/css/quasar-variables.sass'
@import 'quasar/src/css/variables.sass'
`,
},
},
],
});
// Return the altered config
return config;
},
};
Describe the bug
Cannot set property '$q' of undefined
error onObject.installQuasar
when trying to use Storybook/vue3Codepen/jsFiddle/Codesandbox (required) https://github.com/alvarosaburido/quasar-v2-storyook-demo
To Reproduce Steps to reproduce the behavior:
git clone https://github.com/alvarosaburido/quasar-v2-storyook-demo
yarn storybook
Expected behavior The standalone version of Quasar v2 using
app.use(Quasar)
works with Storybook and webpackScreenshots
Platform (please complete the following information): Quasar Version:
2.0.0-beta.9
@quasar/app Version: N/A Quasar mode: [ ] SPA [ ] SSR [ ] PWA [ ] Electron [ ] Cordova [ ] Capacitor [ ] BEX Tested on: [x ] SPA [ ] SSR [ ] PWA [ ] Electron [ ] Cordova [ ] Capacitor [ ] BEX OS: Node: NPM: Yarn: Browsers: iOS: Android: Electron:Additional context Not sure if it's an issue with Quasar or with
@storybook/vue3
. If it's not a Quasar thing let me know to open a ticket on the proper place