Open ThornWalli opened 2 years ago
do you have any idea when the nuxt 3 version will be available ?
Excuse me, when will nuxt-custom-elements support nuxt3? Is there a tutorial?
+1
I created an issue (https://github.com/nuxt/nuxt/issues/15584) to request native support by nuxt
Hello All (@maximepvrt @pperzyna )
On the beta
branch or package (nuxt-custom-elements@beta
) is now a build that works with nuxt@3
(bridge
is not supported and nuxt@2
is dropped).
Very fresh, so still experimental.
@nuxt/vite-builder
, @nuxt/webpack-builder
)Basically the state already produces an expected result. But now I have to work off some more todos.
Hey, Thank you very much for all the hard work.
I gave it a shot and installed on a fresh nuxt 3(3.2.2) installation and after i npm install --save nuxt-custom-elements@beta
and include it in the nuxt-config.ts in the modules array i get:
Nuxi 3.2.2 14:41:21
WARN Changing NODE_ENV from development to production, to avoid unintended behavior. 14:41:21
Nuxt 3.2.2 with Nitro 2.2.2 14:41:21
ERROR Error while requiring module nuxt-custom-elements: Error: Cannot find module './module.json' 14:41:21
Require stack:
- /Users/tudorfilipovici/workspace/pocmonorepo/v1/node_modules/nuxt-custom-elements/dist/module.cjs
ERROR Cannot find module './module.json' 14:41:21
Require stack:
- /Users/xxx/workspace/pocmonorepo/v1/node_modules/nuxt-custom-elements/dist/module.cjs
Require stack:
- /Users/xxxxx/workspace/pocmonorepo/v1/node_modules/nuxt-custom-elements/dist/module.cjs
at Module._resolveFilename (node:internal/modules/cjs/loader:1060:15)
at Function.resolve (node:internal/modules/helpers:118:19)
at _resolve (/Users/xxxx/workspace/pocmonorepo/v1/node_modules/jiti/dist/jiti.js:1:240719)
at jiti (/Users/xxxx/workspace/pocmonorepo/v1/node_modules/jiti/dist/jiti.js:1:242883)
at /Users/xxx/workspace/pocmonorepo/v1/node_modules/nuxt-custom-elements/dist/module.cjs:4:37
at jiti (/Users/xxx/workspace/pocmonorepo/v1/node_modules/jiti/dist/jiti.js:1:245150)
at requireModule (/Users/xxxx/workspace/pocmonorepo/v1/node_modules/@nuxt/kit/dist/index.mjs:286:26)
at normalizeModule (/Users/xxx/workspace/pocmonorepo/v1/node_modules/@nuxt/kit/dist/index.mjs:454:55)
at installModule (/Users/xxx/workspace/pocmonorepo/v1/node_modules/@nuxt/kit/dist/index.mjs:434:47)
at initNuxt (/Users/xxxx/workspace/pocmonorepo/v1/node_modules/nuxt/dist/index.mjs:2253:13)
at async loadNuxt (/Users/xxxx/workspace/pocmonorepo/v1/node_modules/nuxt/dist/index.mjs:2286:5)
at async loadNuxt (/Users/xxxx/workspace/pocmonorepo/v1/node_modules/@nuxt/kit/dist/index.mjs:522:19)
at async Object.invoke (/Users/xxxx/workspace/pocmonorepo/v1/node_modules/nuxi/dist/chunks/build.mjs:34:18)
at async _main (/Users/xxxx/workspace/pocmonorepo/v1/node_modules/nuxi/dist/cli.mjs:51:20)
npm ERR! Lifecycle script `build` failed with error:
npm ERR! Error: command failed
npm ERR! in workspace: v1-ted-shared-frontend@0.0.0
npm ERR! at location: /Users/xxxx/workspace/pocmonorepo/v1/packages/shared/frontend
Any help or pointers would be greatly appreciated.
Hello @Techbinator,
can try again, for whatever reason @nuxt/module-builder
per npx installed had no JSON files...
Now the release is generated with the project dependencies.
Before:
After:
Hello @Techbinator,
can try again, for whatever reason
@nuxt/module-builder
per npx installed had no JSON files...Now the release is generated with the project dependencies.
Before:
After:
works great now. Thanks a lot for the quick fix
impossible to run the nuxt application with default builder (@nuxt/vite-builder
) if the webpack dependencie is not added (@nuxt/webpack-builder
)
[16:40:42] ERROR Cannot restart nuxt: Cannot find package 'webpack' imported from /Users/maxime/Repos/benevolt-front-nuxt/node_modules/nuxt-custom-elements/dist/module.mjs
nuxt 3.4.2
How to test custom element on dev ?
If I build the project, the generated client for the custom element is correct (but not exposed in the public path)
@ThornWalli π
Hello @maximepvrt,
dist
later.@nuxt/webpack-builder
is out now, import this dynamically.vue@3
yet. Main problem here is the CSS in the shadow component is missing, this would be a vite setting I make during build, but would be negative for a Nuxt project.Import via entry definition
@maximepvrt The generated files are now also in the public path with a build or generate.
https://www.npmjs.com/package/nuxt-custom-elements/v/2.0.0-beta.12
Perfect ! but an error is generated if I build the project with a dev import via entry definition
@maximepvrt Did you take this over?
Is a placeholder from the IDE, if so best remove again. Would be the place of the error.
Alternatively you could share the nuxt.config
π
Hey @ThornWalli, I'm a bit stuck and hoping you could help.
Everything seems to be working except for styles not being included with the web component. I'm not sure if this is a bug or if I'm missing something with my setup.
Styles are missing in two instances
local development with nuxt dev
in app.vue
nuxt generate
then serving the generated HTML file with the web component
npm i -g serve
serve dist/nuxt-custom-elements/example
For a bit of background we're not necessarily building a full scale app with Nuxt and then using certain components as web components. More so using Nuxt as an opinionated framework to build Vue based web components that will be used in a legacy non-Vue website. I say this as I saw your comment of
Main problem here is the CSS in the shadow component is missing, this would be a vite setting I make during build, but would be negative for a Nuxt project.
and was wondering what setting this would be. As it could be the potential solution to my issue.
My project file snippets are below.
Thank you in advance π
package.json
{
"name": "nuxt-app",
"private": true,
"scripts": {
"build": "nuxt build",
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview",
"postinstall": "nuxt prepare"
},
"devDependencies": {
"@nuxtjs/tailwindcss": "^6.7.0",
"@types/node": "^18",
"nuxt": "^3.5.0"
},
"dependencies": {
"@pinia/nuxt": "^0.4.10",
"nuxt-custom-elements": "^2.0.0-beta.12",
"pinia": "^2.0.36"
},
"overrides": {
"vue": "latest"
}
}
nuxt.config.ts
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
ssr: false,
target: 'static',
devServer: {
port: 4321,
},
modules: [
'@nuxtjs/tailwindcss',
'@pinia/nuxt',
'nuxt-custom-elements',
],
customElements: {
entries: [
{
name: 'Example',
tags: [
{
name: 'CustomElementExample',
path: '@/components/Example',
options: {
props: {
exampleTitle: 'Nuxt Config Prop Title',
},
},
slotContent: 'Hello from the Nuxt Config!',
},
],
},
],
},
});
Example.vue
<script lang="ts" setup>
export interface Props {
exampleTitle?: string
}
withDefaults(defineProps<Props>(), {
exampleTitle: 'Default example title',
});
console.log('hello world 00');
onBeforeMount(() => {
console.log('hello world 01');
});
</script>
<template>
<div class="text-white bg-zinc-700 flex flex-col p-4 rounded-lg">
<div class="italic">
{{ exampleTitle }}
</div>
<div class="text-zinc-200">
<slot>Default Content</slot>
</div>
</div>
</template>
app.vue
using for development purposes
<script lang="ts" setup>
const nuxtApp = useNuxtApp();
onBeforeMount(() => {
nuxtApp.$customElements.registerEntry('example');
});
</script>
<template>
<div>
<client-only>
<div class="grid grid-cols-3 gap-6 p-6">
<Example example-title="Vue Component">
Vue component slot content
</Example>
<custom-element-example example-title="Web component title">
Web component slot content
</custom-element-example>
</div>
</client-only>
</div>
</template>
Hello @zackspear,
Case 1
tailwindCSS
is not taken over because shadow component does not take over the global css.
currently the components in dev mode have no styling as they are included as shadow component and the vite or vue-loader
configuration is not changed in nuxt mode.
Therefore the components can only be used in dev mode if they are imported correctly.
You could try to make an import with .ce.vue
, so the CSS should be there in dev mode in the shadow.
https://vuejs.org/guide/extras/web-components.html#sfc-as-custom-element
But then you can't import this component normally.
Case 2
You need to import tailwindCSS
in your component.
See example of Nuxt 2 variant https://github.com/GrabarzUndPartner/nuxt-custom-elements-example/blob/87e72fd17f12a14d0247c606113851b866dd9794/examples/tailwind-css/entries/TailwindCssShadow.vue#L8
It must always be remembered that the entries are standalone vue component builds that do not take anything from nuxt.
And please consider this case: https://github.com/vuejs/core/issues/4662
If a style tag is included in the entry, it will also be included in the generate.
https://github.com/GrabarzUndPartner/nuxt-custom-elements/blob/main/example/components/Example.vue
@ThornWalli thank you so much! π I have a working example web component with styles.
I changed Example.vue
to Example.ce.vue
and updated it's path in nuxt.config.ts
to include .ce
.
Then for Example.ce.vue
within <script lang="ts" setup>
I added import 'tailwindcss/tailwind.css';
and also added to the style tags with the following:
<style lang="postcss">
@tailwind base;
@tailwind components;
@tailwind utilities;
</style>
Then within app.vue
I had to update the Vue component from <Example />
to <ExampleCe />
. Didn't have to manually import the component.
Really appreciate the tips. I knew I was close.
Here's my full files for those that may find this later.
nuxt.config.ts
export default defineNuxtConfig({
ssr: false,
target: 'static',
devServer: {
port: 4321,
},
modules: [
'@nuxtjs/tailwindcss',
'@pinia/nuxt',
'nuxt-custom-elements',
],
customElements: {
entries: [
{
name: 'Example',
tags: [
{
name: 'CustomElementExample',
path: '@/components/Example.ce',
options: {
props: {
exampleTitle: 'Nuxt Config Prop Title',
},
},
slotContent: 'Hello from the Nuxt Config!',
},
],
},
],
},
});
Example.ce.vue
<script lang="ts" setup>
import 'tailwindcss/tailwind.css';
export interface Props {
exampleTitle?: string
}
withDefaults(defineProps<Props>(), {
exampleTitle: 'Default example title',
});
console.log('hello world 00');
onBeforeMount(() => {
console.log('hello world 01');
});
</script>
<template>
<div class="text-white bg-zinc-700 flex flex-col p-4 rounded-lg">
<h1 class="italic">
{{ exampleTitle }}
</h1>
<div class="text-zinc-200">
<slot>Default Content</slot>
</div>
</div>
</template>
<style lang="postcss">
@tailwind base;
@tailwind components;
@tailwind utilities;
</style>
app.vue
<script lang="ts" setup>
const nuxtApp = useNuxtApp();
onBeforeMount(() => {
nuxtApp.$customElements.registerEntry('example');
});
</script>
<template>
<div class="bg-gray-200">
<client-only>
<div class="grid grid-cols-3 gap-6 p-6">
<ExampleCe example-title="Vue Component">
Vue component slot content
</ExampleCe>
<custom-element-example example-title="Web component title">
Web component slot content
</custom-element-example>
</div>
</client-only>
</div>
</template>
@zackspear Very good π
I consider times whether one does not need the .ce.vue
as a user in the Dev mode.
Good would be a container with .ce.vue
, which imports the specified components.
Would be conceivable on the basis of the configuration.
It is important that this issue about child style is clarified. As long as it is not really usable for more complex projects.
@ThornWalli unfortunately having a different, unrelated issue now. Not sure if it's a bug or something that I'm doing wrong.
I created another component which is intended to be a web component. But in both development and in the generated Nuxt output the second web component is rendering as the first web component.
I made my second test component, Tester.ce
, have a red background and slightly different content β different prop and no <slot>
. But as you can see in the screenshot the web component version of Tester
is showing as the first web component called Example
.
Screenshot of nuxt dev
And a screenshot of nuxt generate
and viewing it with serve dist/nuxt-custom-elements/connect-components
nuxt.config.ts
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
ssr: false,
target: 'static',
devServer: {
port: 4321,
},
modules: [
'@vueuse/nuxt',
'@pinia/nuxt',
'@nuxtjs/tailwindcss',
'nuxt-custom-elements',
],
customElements: {
entries: [
{
name: 'ConnectComponents',
tags: [
{
name: 'ConnectExample',
path: '@/components/Example.ce',
options: {
props: {
heading: 'Example Nuxt Config Prop Title',
},
},
slotContent: 'Hello Example from the Nuxt Config!',
},
{
name: 'ConnectTester',
path: '@/components/Tester.ce',
options: {
props: {
copy: 'Tester copy from Nuxt config',
},
},
},
],
},
],
},
});
Example.ce.vue
<script lang="ts" setup>
import 'tailwindcss/tailwind.css';
export interface Props {
heading?: string
}
withDefaults(defineProps<Props>(), {
heading: 'Default example heading',
});
const { x, y } = useMouse();
</script>
<template>
<div class="text-white bg-zinc-700 flex flex-col p-4 rounded-lg">
<h1 class="italic">
{{ heading }}
</h1>
<p>Mouse coordinates: {{ x }}, {{ y }}</p>
<div class="text-zinc-200">
<slot>Default example content</slot>
</div>
</div>
</template>
<style lang="postcss">
@tailwind base;
@tailwind components;
@tailwind utilities;
</style>
Tester.ce.vue
<script lang="ts" setup>
import 'tailwindcss/tailwind.css';
export interface Props {
copy?: string
}
withDefaults(defineProps<Props>(), {
copy: 'Default tester copy',
});
const { x, y } = useMouse();
</script>
<template>
<div class="text-white bg-red-700 flex flex-col p-4 rounded-lg">
<h1 class="italic">Tester component</h1>
<h2>Mouse coordinates: {{ x }}, {{ y }}</h2>
<p class="text-gray-300">
{{ copy }}
</p>
</div>
</template>
<style lang="postcss">
@tailwind base;
@tailwind components;
@tailwind utilities;
</style>
app.vue
<script lang="ts" setup>
const nuxtApp = useNuxtApp();
onBeforeMount(() => {
nuxtApp.$customElements.registerEntry('ConnectComponents');
});
</script>
<template>
<div class="max-w-3xl mx-auto bg-gray-200">
<client-only>
<div class="grid grid-cols-2 gap-6 p-6">
<ExampleCe heading="Example Vue Component">
Example Vue component slot content
</ExampleCe>
<connect-example heading="Example web component title">
Example web component slot content
</connect-example>
<TesterCe heading="Tester Vue Component" />
<connect-tester copy="Tester web component title"></connect-tester>
</div>
</client-only>
</div>
</template>
Now if I switch the order of the tag objects in nuxt.config.ts
it results in the same thing but now with the Tester
component being in place of Example
.
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
ssr: false,
target: 'static',
devServer: {
port: 4321,
},
modules: [
'@vueuse/nuxt',
'@pinia/nuxt',
'@nuxtjs/tailwindcss',
'nuxt-custom-elements',
],
customElements: {
entries: [
{
name: 'ConnectComponents',
tags: [
{
name: 'ConnectTester',
path: '@/components/Tester.ce',
options: {
props: {
copy: 'Tester copy from Nuxt config',
},
},
},
{
name: 'ConnectExample',
path: '@/components/Example.ce',
options: {
props: {
heading: 'Example Nuxt Config Prop Title',
},
},
slotContent: 'Hello Example from the Nuxt Config!',
},
],
},
],
},
});
Thanks again in advance.
Edit: It looks like defineTags
in your src/runtime/tmpl/entry.mjs
file does not loop and iterate properly.
I was looking through my-example-project/.nuxt/nuxt-custom-elements/entries/connect-components.client.mjs
after running nuxt generate
and see this
import { defineAsyncComponent, defineCustomElement } from 'vue'
import Component0 from '@/components/Example.ce';
import Component1 from '@/components/Tester.ce';
const defineTags = () => {
const elements = [
['connect-example', (typeof Component0 === 'function' ? (new Component0).$options : Component0)],
['connect-tester', (typeof Component0 === 'function' ? (new Component0).$options : Component0)]
].forEach(([name, component]) => {
const CustomElement = defineCustomElement(component);
window.customElements.define(name, CustomElement);
})
};
const setup = () => {
defineTags();
};
setup();
Component1
is never used. Instead Component0
is used for each tag.
Edit2: I created a separate issue for this #521 and was able to figure out the fix in #522
@ThornWalli After running nuxt build
what is the path to my entry?
This is what I got. And I can reference the
Forms
entry only on a path: http://localhost:3000/_nuxt/forms.client.755bccec.js. ~Moreover, the server doesn't return CORS headers, so when I include this script on a website that will use these components I'm getting a CORS error.~ I used nuxt routeRules to configure cors
Hi @ThornWalli,
I'm looking to embed my entire Nuxt project as a Web Component on an external site, I've achieved this in a standard Vue 3 project using custom elements by bundling a single app.js
file and adding <my-custom-element></my-custom-element>
to the page.
However, when using Nuxt features (e.g. layouts, links, routes) in a custom element component using the above examples I run into an error:
example.client-c6046f55.js:1 TypeError: Cannot read properties of null (reading '$nuxt')
The below code works when removing the route
snippets:
// Example.vue
<template>
<div class="flex flex-col p-4 text-white rounded-lg bg-zinc-700">
<div class="italic">
{{ exampleTitle }}
</div>
<div class="text-zinc-200">
<slot>Default Content</slot>
</div>
<div>
{{ route }}
</div>
</div>
</template>
<script lang="ts" setup>
const route = useRoute();
export interface Props {
exampleTitle?: string;
}
withDefaults(defineProps<Props>(), {
exampleTitle: "Default example title",
});
console.log("hello world 00");
onBeforeMount(() => {
console.log("hello world 01");
});
</script>
Is this possible with Nuxt? Any help is much appreciated.
Hello @GarethBeddis-VoxlyDigital ,
You can't apply nuxt
internal things in the created custom elements.
Each entry is a separate Vue app.
If you want to use a router or pinia (store), you have to register it in the entry (custom element).
Example from nuxt@2
version: https://github.com/GrabarzUndPartner/nuxt-custom-elements-example/tree/main/examples
And very important, keep this issue in mind: https://github.com/vuejs/core/issues/4662
Hi @ThornWalli, I just updated to beta17
and it seems like this introduced a bug.
If options
is not set for each custom element in nuxt.config.ts
the build will not work.
I believe the else statement there is causing this.
As this then doesn't allow the OR operator to work here: https://github.com/GrabarzUndPartner/nuxt-custom-elements/commit/94f2d5d4bee451685e95b935934919f8d2e6e34f#diff-90ec0da933dd5a8e979aebf86e0c9a67e3947fd122915053432dd14935b935afR19
This config worked with beta16 but not beta17
export default defineNuxtConfig({
// β¦ rest of config
customElements: {
entries: [
{
name: 'OurComponents',
tags: [
// β¦ removed other components for brevity
{
name: 'OurWanIpCheck',
path: '@/components/WanIpCheck.ce',
},
],
},
],
},
});
as the build output looks like
// 2.0.0-beta.17
import { defineAsyncComponent, defineCustomElement } from "/_nuxt/node_modules/.cache/vite/client/deps/vue.js?v=304f2311"
import Component0 from "/_nuxt/components/WanIpCheck.ce.vue";
const defineTags = () => {
const elements = [
['our-wan-ip-check', (typeof Component0 === 'function' ? (new Component0).$options : Component0), [object Object]]
].forEach(([name, component, options]) => {
const CustomElement = defineCustomElement(component, options);
window.customElements.define(name, CustomElement);
})
};
const setup = () => {
defineTags();
};
setup();
You'll notice [object Object]
at the end of the element.
Adding options
to make the build work in the browser.
export default defineNuxtConfig({
// β¦ rest of config
customElements: {
entries: [
{
name: 'OurComponents',
tags: [
// β¦ removed other components for brevity
{
name: 'OurWanIpCheck',
path: '@/components/WanIpCheck.ce',
options: {},
},
],
},
],
},
});
@zackspear Very big sorry!
Just publish a working version π
The version 2.0.0-beta.18
should work.
Thank you for the super quick fix @ThornWalli π
@zackspear I'm updating again, only in the Vite build this plugin is now built in. https://github.com/baiwusanyu-c/unplugin-vue-ce
With this also nested styles should work now.
I'm still working on webpack
...
I also removed the plugin this.$registryEntry
, registryEntry
is now only possible via Composable.
https://nuxt-custom-elements.grabarzundpartner.dev/migration/v2#plugin
If you use the file extensions .ce.vue, this is not necessary. In dev the components are imported normally. In the build itself they will be CustomElements.
Background: That for nested stylesvite
would have to be changed to CustomElements in general, and this can only happen in the build.
Shadow CSS of child components in webpack
and vite
are now possible.
Workaround plugin: https://github.com/baiwusanyu-c/unplugin-vue-ce
@ThornWalli, this is fantastic news! Unfortunately I have been sick with covid-19 for about a week. I should be able to test this next week. Thank you for the updates.
The latest version 2.0.0-beta.25 breaks on install because of the updated plugin @unplugin-vue-ce/sub-style
error An unexpected error occurred: "expected hoisted manifest for \"@unplugin-vue-ce/sub-style#vue#@vue/server-renderer#@vue/compiler-ssr\"".
Hello @kahl-dev ,
unfortunately I cannot reproduce this.
It seems that @unplugin-vue-ce/sub-style
is causing problems...
Can you provide a small example to reproduce?
@ThornWalli, I have updated to the latest version of Nuxt and it is now working perfectly. I believe the problem with @unplugin-vue-ce/sub-style
was only present in older versions of Nuxt.
@kahl-dev Thanks good to know π
@ThornWalli if set the option shadow
in my NUXT configuration but nothing changed. It still has a shadow Dom. Is there a way to deactivate that?
export default defineNuxtConfig({
customElements: {
entries: [
{
name: 'XXX',
shadow: false,
//...
}
]
}
})
@kahl-dev Unfortunately, the behaviour we knew from vue@2
with both no longer exists.
In vue@3
something was rebuilt and provides for a custom element integration only shadow.
There is also a reason why there is this package @unplugin-vue-ce/sub-style
;)
The use of child components is not considered in custom elements with their own styling...
Hello @ThornWalli , I hope you are doing well. I am using your product and encountered an issue, and you are my last hope!) So, the problem is that in our Nuxt application that we are developing, we need to implement web components for the possibility of integrating them into external sites, and for this, I want to use your solution. It's worth noting that the components are implemented using Vuetify, and this is where the issues arise. I followed all the documentation provided at this link link and this example However, after running the "nuxt build" command and launching the built web component, I'm not getting styles from Vuetify components; I only receive the layout components and styles that do not belong to the Vuetify library. When I try to create a simple component using plain HTML and CSS, everything works properly. Please advise if it's possible to solve this problem so that Vuetify library elements are displayed in the web component with styles. Below, I will provide some screenshots for better understanding. Thank you in advance for your work and time!
nuxt.config.ts
import { resolve } from 'path'
import type { NuxtConfig } from '@nuxt/types'
const config: NuxtConfig = {
ssr: false,
server: {
hmr: {
protocol: 'ws',
host: 'localhost'
}
},
runtimeConfig: {
public: {
DNS_SENTRY: process.env.DNS_SENTRY,
CURRENT_ENV: process.env.CURRENT_ENV,
GALENE_DOMAIN: process.env.GALENE_DOMAIN
}
},
buildModules: ['@nuxt/typescript-build', '@nuxtjs/vuetify'],
devtools: process.env.DEVTOOLS === 'true' ? { enabled: true } : false,
modules: ['nuxt-lodash', '@pinia/nuxt', 'nuxt-custom-elements'],
build: {
transpile: ['vuetify', 'trpc-nuxt']
},
layouts: {
adminLayout: '@/layouts/AdminLayout.vue',
createLessonLayout: '@/layouts/createLesson.vue'
},
css: ['@/assets/styles/main.scss'],
app: {
head: {
charset: 'utf-8',
viewport: 'width=device-width, initial-scale=1, minimum-scale=1'
}
},
customElements: {
analyzer: false,
entries: [
{
name: 'web-component',
tags: [
{
async: true,
name: 'LessonList',
path: '@/custom-elements/lessonList.ce',
}
]
}
]
},
vite: {
server: {
cors: {
preflightContinue: true
}
},
vue: {
customElement: true
}
},
routeRules: {
'*': { cors: true },
'_nuxt/*': { cors: true }
}
}
export default config
vuetify.ts
from plugins
import '@mdi/font/css/materialdesignicons.css'
import { createVuetify } from 'vuetify'
import * as components from 'vuetify/components'
import * as directives from 'vuetify/directives'
import 'vuetify/styles'
const componentsList = { ...components }
export default defineNuxtPlugin((nuxtApp) => {
const vuetify = createVuetify({
ssr: true,
components: componentsList,
directives
})
nuxtApp.vueApp.use(vuetify)
})
lessonList.ce.vue
<template>
<Suspense>
<ChooseLesson />
</Suspense>
</template>
<script setup lang="ts">
import ChooseLesson from '../components/chooseLesson/ChooseLesson.vue'
</script>
<style>
@import 'vuetify/dist/vuetify.min.css';
</style>
<style lang="scss">
@import '@/assets/styles/main.scss';
@import '@/assets/styles/LessonList.scss';
</style>
package.json
"devDependencies": {
"@mdi/font": "^7.2.96",
"@nuxt/devtools": "latest",
"@nuxt/types": "^2.17.0",
"@nuxt/typescript-build": "^3.0.1",
"@nuxtjs/eslint-config-typescript": "^12.0.0",
"@nuxtjs/style-resources": "^1.2.1",
"@types/bcryptjs": "^2.4.2",
"@types/jsonwebtoken": "^9.0.2",
"@types/node": "^18.17.1",
"@types/nodemailer": "^6.4.9",
"@typescript-eslint/eslint-plugin": "^5.61.0",
"@typescript-eslint/parser": "^5.61.0",
"eslint": "^8.44.0",
"eslint-config-prettier": "^8.10.0",
"eslint-plugin-nuxt": "^4.0.0",
"eslint-plugin-prettier": "^4.2.1",
"nuxt": "^3.8.2",
"prettier": "^2.8.8",
"prisma": "^5.1.1",
"sass": "^1.63.6",
"ts-node": "^10.9.1",
"typescript": "^5.1.6",
"vue-i18n": "^9.2.2"
},
"dependencies": {
"@aws-sdk/client-s3": "^3.391.0",
"@fullcalendar/core": "^6.1.9",
"@fullcalendar/daygrid": "^6.1.9",
"@fullcalendar/interaction": "^6.1.9",
"@fullcalendar/timegrid": "^6.1.9",
"@fullcalendar/vue": "^6.1.9",
"@fullcalendar/vue3": "^6.1.9",
"@nuxtjs/vuetify": "^1.12.3",
"@pinia/nuxt": "^0.4.11",
"@prisma/client": "^5.1.1",
"@sentry/browser": "^7.63.0",
"@sentry/node": "^7.63.0",
"@sentry/tracing": "^7.63.0",
"@sentry/vite-plugin": "^2.6.2",
"@sentry/vue": "^7.63.0",
"@trpc/client": "^10.35.0",
"@trpc/server": "^10.35.0",
"bcryptjs": "^2.4.3",
"get-youtube-id": "^1.0.1",
"joi": "^17.9.2",
"jsonwebtoken": "^9.0.1",
"nodemailer": "^6.9.4",
"nuxt-custom-elements": "2.0.0-beta.16",
"nuxt-lodash": "^2.5.0",
"pinia": "^2.1.6",
"quill": "^1.3.7",
"quill-placeholder-module": "^0.3.1",
"sharp": "^0.32.6",
"trpc-nuxt": "^0.10.6",
"uniqid": "^5.4.0",
"vue-lite-youtube-embed": "^1.2.0",
"vuedraggable": "^4.1.0",
"vuetify": "3.4.0",
"zod": "^3.22.3"
},
Hello @Stereoboi,
I also noticed this some time ago...
I was wondering how Vuetify
activates the theme and came across this:
https://github.com/vuetifyjs/vuetify/blob/7a8951ca4e49f7f350062bbbf7d8b456e3eb30f9/packages/vuetify/src/composables/theme.ts#L302
Here the theming is injected via the app, I suspect that the position is not handled in the Shadow Custom Element
.
Workaround would be to import a finished Vuetify Theme CSS, in the component.
There are discussions about this on Vuetify:
Hey @ThornWalli,
Ran into something odd here. Looks like I'm getting double style tags in the project β one's popping up at the root and the other's where it's supposed to be. It's messing with the styling and I can't figure out why it's happening.
Have you seen this kind of thing before? Any idea why there'd be a duplicate tag at the root?
If you've got some tips or know something I might be missing, that'd be awesome.
Here is the component and the result:
<template>
<div class="test">LiaDemo</div>
</template>
<style>
.test {
color: red;
}
</style>
{
// Name of the custom element
name: 'ExampleComponentGroup',
tags: [
{
// Name of the custom element use kebab-case instad of camelCase to use it in HTML
name: 'ExampleComponent',
path: '@/components/Demo/ExampleComponent',
// Define the props that can be passed to the custom element
options: {
props: ['testParameter'],
},
// Define the appContext that is passed to the custom element
// appContext: '@/components/Demo/Example.appContext.js',
},
],
},
Hello @kahl-dev,
I suspect a bug in this plugin https://github.com/unplugin/unplugin-vue-ce/tree/master/packages/sub-style
Nested styles are not officially supported in Vue3, so a workaround was created as a plugin by the community.
A small Vite-only project with this plugin for reproduction would be good to report this error directly to the plugin.
Hey @ThornWalli,
Thanks for the quick response! I'm going to put together a demo that replicates this issue and report the bug to the plugin devs. Really appreciate your help in pinpointing the possible cause.
if someone's trying to extend vite builder config to make output files without hashes:
viteExtend(viteConf) {
viteConf.build.rollupOptions = viteConf.build.rollupOptions || {}
viteConf.build.rollupOptions.output = viteConf.build.rollupOptions.output || {}
const target = viteConf.build.rollupOptions.output
const assetsDir = 'assets'
target.entryFileNames = `${ assetsDir }/[name].js`
target.chunkFileNames = `${ assetsDir }/[name].js`
target.assetFileNames = `${ assetsDir }/[name].[ext]`
return viteConf
}
@dselivanovvv Do you have the config in the right place? π
Your configuration works!
Before
After
{
customElements: {
analyzer: !isTest,
entries: [
{
name: 'Example',
viteExtend(config) {
config.build.rollupOptions = config.build.rollupOptions || {};
config.build.rollupOptions.output =
config.build.rollupOptions.output || {};
const target = config.build.rollupOptions.output;
const assetsDir = 'assets';
target.entryFileNames = `${assetsDir}/[name].js`;
target.chunkFileNames = `${assetsDir}/[name].js`;
target.assetFileNames = `${assetsDir}/[name].[ext]`;
return config;
},
tags: [
{
async: false,
name: 'CustomElementExample',
path: '@/components/customElements/Example.vue',
options: {
props: {
title: 'Live Example'
}
},
appContext: '@/components/customElements/Example.appContext.js',
slotContent: '<div>Live Example Content</div>'
}
]
}
]
}
}
Hello. I've been trying out this project for a while now, and so far I feel like I'm just banging my head on a brick wall. I'm trying to export some very rudimentary nuxt 3 components using the composition API. I've been able to generate a custom element that creates a shadow dom and displays the component. However, none of the nuxt-specific features seem to work in these components, or at least no auto-imports seem to be working. So I'm having to import things like computed or the components that I'm trying to use. So this means that none of my actual components will work, since they naturally use these things.
Is this supposed to be the case or am I doing something wrong?
Hello @MarkoTukiainen
Macros are not supported π
Try to import the things. e.g. import { ... } from '#imports';
All global functions are announced under .nuxt/imports.d.ts
and can be imported via #imports
.
Try to import the things. e.g.
import { ... } from '#imports';
Thanks for replying so quickly. So, in order to use my existing nuxt components I'd have to modify all of them to use manual imports?
Yes, that's right.
Trying the import { ... } from '#imports'
yields the following error:
[vite:load-fallback] Could not load D:/path/.nuxt/imports (imported by components/Widget.ce.vue?vue&type=script&setup=true&lang.ts): ENOENT: no such file or directory, open 'D:\path\.nuxt\imports'
Which, I suppose, is correct since the file imports
does not exist in the .nuxt
folder, but imports.d.ts
does.
Sorry for my mistake.
You can forget #imports
.
Try it with the original imports, the imports is just a summary of all global imports.
You can forget
#imports
.Try it with the original imports, the imports is just a summary of all global imports.
Yes, indeed that was my original question - I was wondering if I in fact had to refactor all my components to use manual imports. Interestingly enough, the #imports syntax works fine in nuxt, but just not when building custom elements. Could this be a Windows-specific issue, if the path resolution of the #imports alias somehow goes wrong or something?
I'll have to see how big of an effort this will be, sadly the auto-imports was one of the best things I thought Vue 3 brought to the table.
Auto imports are good as long as you stay in Nuxt ;)
Example: Mono repo with component library for reuse in different projects (without Nuxt). That's where it gets a bit difficult.
You could extend the Vite configuration for the auto-imports. https://nuxt-custom-elements.grabarzundpartner.dev/guide/options.html#more-about-viteextend
Here you would have to see if a pure alias #imports
on the file is sufficient.
The custom elements are each created in Vite/Webpack with their own entry builds, so Nuxt-specific properties are missing here.
Nuxt 3 version is available π
Install
Todos
vue-web-component-wrapper
for usagei18n
,pinia
,vuetify
β οΈ Not really usable until now https://github.com/vuejs/core/issues/4662unplugin-vue-ce
webpack
Build (@nuxt/webpack-builder
)build
orgenerate
.publicPath
integration? (https://webpack.js.org/guides/public-path/#automatic-publicpath)webpack
configvite
Build (@nuxt/vite-builder
)build
orgenerate
.publicPath
integration? (https://www.npmjs.com/package/vite-plugin-dynamic-base)vite
configvitest
Tests update@nuxt/vite-builder
@nuxt/webpack-builder
nuxt
backward compatibility (nuxt-bridge
)Features
Problems?