I have vue3+vite+quasar project with pages, components, etc. and I want individual components to be able to be turned into web components so that they can be used in any other places, I already had a little experience with this but now because of third-party libraries I have problems that I can't solve if you can help please
vite.config.ts
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import { quasar } from '@quasar/vite-plugin';
export default defineConfig({
plugins: [
vue(),
quasar({
autoImportComponentCase: 'pascal',
}),
],
define: {
'process.env': {},
},
build: {
target: 'esnext',
rollupOptions: {
output: {
globals: {
vue: 'Vue',
quasar: 'Quasar',
},
assetFileNames: (assetInfo) => {
if (assetInfo.name.endsWith('.css')) {
return 'web.css';
}
return 'assets/[name]-[hash][extname]';
},
format: 'es',
manualChunks: null,
inlineDynamicImports: true,
},
external: [],
},
lib: {
entry: 'src/main.ts',
name: 'web',
fileName: (format) => `web.${format}.js`,
formats: ['es', 'umd', 'iife'],
},
},
});
main.ts
import 'quasar/dist/quasar.css';
import { createApp, defineCustomElement } from 'vue';
import { Quasar, QCard } from 'quasar';
import HelloWorld from './components/HelloWorld.vue';
const app = createApp(HelloWorld);
app.use(Quasar, {
config: {
dark: false,
},
components: {
QCard,
},
plugins: [],
});
const createInstantGameElement = defineCustomElement(HelloWorld);
customElements.define('my-web-component', createInstantGameElement);
app.mount('#app');
HelloWorld.vue
<script setup lang="ts">
import { QCard } from 'quasar'
</script>
<template>
test1
<QCard class="q-pa-lg">
test2
</QCard>
</template>
<style scoped>
</style>
Try index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="../dist/web.css">
<script type="module" src="../dist/web.es.js"></script>
</head>
<body>
<my-web-component/>
</body>
</html>
at the exit I see string 'test1' and warn with error
[Vue warn]: Unhandled error during execution of render function at <QCard class="q-pa-lg" > at <VueElement >
and
Uncaught TypeError: Cannot read properties of undefined (reading 'dark')
I have vue3+vite+quasar project with pages, components, etc. and I want individual components to be able to be turned into web components so that they can be used in any other places, I already had a little experience with this but now because of third-party libraries I have problems that I can't solve if you can help please
vite.config.ts
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import { quasar } from '@quasar/vite-plugin';
export default defineConfig({
plugins: [
vue(),
quasar({
autoImportComponentCase: 'pascal',
}),
],
define: {
'process.env': {},
},
build: {
target: 'esnext',
rollupOptions: {
output: {
globals: {
vue: 'Vue',
quasar: 'Quasar',
},
assetFileNames: (assetInfo) => {
if (assetInfo.name.endsWith('.css')) {
return 'web.css';
}
return 'assets/[name]-[hash][extname]';
},
format: 'es',
manualChunks: null,
inlineDynamicImports: true,
},
external: [],
},
lib: {
entry: 'src/main.ts',
name: 'web',
fileName: (format) => `web.${format}.js`,
formats: ['es', 'umd', 'iife'],
},
},
});
main.ts
import 'quasar/dist/quasar.css';
import { createApp, defineCustomElement } from 'vue';
import { Quasar, QCard } from 'quasar';
import HelloWorld from './components/HelloWorld.vue';
const app = createApp(HelloWorld);
app.use(Quasar, {
config: {
dark: false,
},
components: {
QCard,
},
plugins: [],
});
const createInstantGameElement = defineCustomElement(HelloWorld);
customElements.define('my-web-component', createInstantGameElement);
app.mount('#app');
HelloWorld.vue
<script setup lang="ts">
import { QCard } from 'quasar'
</script>
<template>
test1
<QCard class="q-pa-lg">
test2
</QCard>
</template>
<style scoped>
</style>
Try index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="../dist/web.css">
<script type="module" src="../dist/web.es.js"></script>
</head>
<body>
<my-web-component/>
</body>
</html>
at the exit I see string 'test1' and warn with error
[Vue warn]: Unhandled error during execution of render function at <QCard class="q-pa-lg" > at <VueElement >
and
Uncaught TypeError: Cannot read properties of undefined (reading 'dark')
1 Answer
Reset to default 0app.use(Quasar)
can't affect Quasar components, while they are expected to rely on framework-specific configuration. Web components are rendered in isolation from the rest of Vue application, even if they are implemented with Vue components. The documentation mentions provide
/inject
, but this is a special case of the mentioned problem.
This requires to be aware of framework components in use and their implementation. It can be seen that QCard
relies on $q
global component property that is normally provided with app.use(Quasar)
and uses props as a fallback.
So it could be fixed with:
...
<QCard class="q-pa-lg" :dark="false">
...
Or by installing Quasar plugin to application instance that web component uses with configureApp option:
defineCustomElement(HelloWorld, {
configureApp(app) {
app.use(Quasar, {
config: {
dark: false,
}
});
},
});
No components
is necessary because QCard
is imported locally. app.use(Quasar)
for main application instance isn't needed.