From e6e202ac622eb6eaddd2c9ddb72b6038c24a978b Mon Sep 17 00:00:00 2001 From: Eran Grinberg Date: Mon, 14 Oct 2024 10:03:31 +0200 Subject: [PATCH] refactor: Update createWebComponent function and add replaceRootWithHost option --- CHANGELOG.md | 4 + README.md | 189 +++++++++++++++++++----------- docs/index.md | 16 ++- docs/usage.md | 4 +- package/index.js | 6 +- package/src/web-component-util.js | 85 ++++++++------ package/types.d.ts | 1 + 7 files changed, 194 insertions(+), 111 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 04d5bba..7d5e01c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format ## [Unreleased] +## [1.6.4] - 14.10.2024 +### Added +- Added support for replaceRootWithHost option + ## [1.6.3] - 12.07.2024 ### Added - Fixed issue with style tag injection order SFC diff --git a/README.md b/README.md index e458dbb..5c31554 100644 --- a/README.md +++ b/README.md @@ -17,11 +17,12 @@ `vue-web-component-wrapper` is a powerful Vue 3 plugin designed for transforming full-fledged Vue applications into reusable web components (custom elements). These web components can be integrated into any website, enhancing flexibility and reusability. ## Why use `vue-web-component-wrapper`? -As of now, Vue 3 does not support the creation of full aplication as web components out of the box. This plugin aims to solve this problem by providing a simple and easy-to-use solution for creating web components from Vue applications. It also provides support for Vue ecosystem plugins such as [Vuex](https://vuex.vuejs.org/) or [Pinia](https://pinia.vuejs.org/), [Vue Router](https://router.vuejs.org/), [Vue I18n](https://vue-i18n.intlify.dev/) and [VeeValidate](https://vee-validate.logaretm.com/v4/). +As of now, Vue 3 does not support the creation of full applications as web components out of the box. This plugin aims to solve this problem by providing a simple and easy-to-use solution for creating web components from Vue applications. It also provides support for Vue ecosystem plugins such as [Vuex](https://vuex.vuejs.org/), [Pinia](https://pinia.vuejs.org/), [Vue Router](https://router.vuejs.org/), [Vue I18n](https://vue-i18n.intlify.dev/), and [VeeValidate](https://vee-validate.logaretm.com/v4/). + ## Demo Check out these demo projects to see `vue-web-component-wrapper` in action: -- **Webpack implentaion**: Check out this [Webpack Demo Project](https://stackblitz.com/edit/vue-web-component-wrapper?file=README.md&startScript=webpack-demo) -- **Vite.js implentaion**: Check out this [Vite Demo Project](https://stackblitz.com/edit/vue-web-component-wrapper?file=README.md&startScript=vite-demo) +- **Webpack implementation**: Check out this [Webpack Demo Project](https://stackblitz.com/edit/vue-web-component-wrapper?file=README.md&startScript=webpack-demo) +- **Vite.js implementation**: Check out this [Vite Demo Project](https://stackblitz.com/edit/vue-web-component-wrapper?file=README.md&startScript=vite-demo) @@ -30,24 +31,27 @@ See [Docs](https://erangrin.github.io/vue-web-component-wrapper) ## Key Features: - **Vue Plugins Compatibility**: Seamlessly integrates with Vue ecosystem plugins such as Vuex, Vue Router, and Vue I18n. -- **CSS Framework Support**: Works with popular CSS frameworks like Tailwind CSS, Bootstrap. +- **CSS Framework Support**: Works with popular CSS frameworks like Tailwind CSS, Bootstrap, Vuetify, Element Plus, and more. - **CSS Preprocessor Support**: Allows you to use CSS preprocessors like SCSS and LESS. -- **Scoped CSS**: Allows you to use scoped css in your components. +- **Scoped CSS**: Allows you to use scoped CSS in your components. - **Shadow DOM Support**: Facilitates the encapsulation of styles and scripts for your components, preventing clashes with the rest of your application. - **VUE Devtool Support**: Supports the Vue DevTools browser extension. - **Slot and Named Slot Support**: Define and use slots and named slots within web components. - **v-model Support**: Improved support for two-way data binding using `v-model` architecture. - **Event Emitting Support**: Emit and handle custom events from web components. - **Provide/Inject Support**: Pass data from parent to child components using `provide` and `inject`. -- **Disable Removal of Styles on Unmount**: Control the removal of styles upon component unmount which can solve issue with css transition. -- **Disable Shadow DOM**: Disable shadow DOM for web components. - +- **Disable Removal of Styles on Unmount**: Control the removal of styles upon component unmount, which can solve issues with CSS transitions. +- **Disable Shadow DOM**: Disable Shadow DOM for web components. +- **Replace `:root` with `:host`**: Optionally replace `:root` selectors with `:host` in your CSS to ensure styles are correctly scoped within the Shadow DOM. ## CSS Frameworks Examples - **Tailwind CSS** - [Demo](https://stackblitz.com/edit/vue-web-component-wrapper?file=README.md&startScript=tailwind-demo) - **UnoCSS** - [Demo](https://stackblitz.com/~/github.com/EranGrin/element-plus-unocss-web-component?file=src/style.css:L1-L2) - **Vuetify** - [Demo](https://stackblitz.com/~/github.com/EranGrin/vuetify-web-component-wrapper) - **Element Plus** - [Demo](https://stackblitz.com/~/github.com/EranGrin/element-plus-unocss-web-component?file=src/style.css:L1-L2) +- **Bootstrap** - [Demo](https://stackblitz.com/~/github.com/EranGrin/bootstrap-demo-webcomponent) + + See documentation for more details [Docs](https://erangrin.github.io/vue-web-component-wrapper) @@ -66,49 +70,54 @@ pnpm add vue-web-component-wrapper To create a web component using `vue-web-component-wrapper`, follow the steps below: 1. **Import the necessary modules** in your entry file: + ```javascript import App from './App.vue'; import tailwindStyles from './assets/tailwind.css?raw'; -import { createWebHashHistory, createRouter } from "vue-router"; +import { createWebHashHistory, createRouter } from 'vue-router'; import { createI18n } from 'vue-i18n'; -import { createStore } from 'vuex' -import { createPinia } from 'pinia' -import { defaultRoutes } from './main.routes.js' -import { store } from './store/index.js' +import { createStore } from 'vuex'; +import { createPinia } from 'pinia'; +import { defaultRoutes } from './main.routes.js'; +import { store } from './store/index.js'; import { defineCustomElement as VueDefineCustomElement, h, createApp, getCurrentInstance } from 'vue'; import { createWebComponent } from 'vue-web-component-wrapper'; ``` -2. **Set up the instances** and use your plugins. This is where you configure your Vuex/Pinia store, Vue router, and other Vue plugins. + +2. **Set up the instances** and use your plugins. This is where you configure your Vuex/Pinia store, Vue Router, and other Vue plugins. + ```javascript export const pluginsWrapper = { - install(GivenVue: any) { - const Vue = GivenVue + install(GivenVue) { + const Vue = GivenVue; - //Vuex - const createdStore = createStore(store) - Vue.use(createdStore) + // Vuex + const createdStore = createStore(store); + Vue.use(createdStore); - //or Pinia - const pinia = createPinia() - Vue.use(pinia) + // or Pinia + const pinia = createPinia(); + Vue.use(pinia); - //Vue Router + // Vue Router const router = createRouter({ history: createWebHashHistory(), routes: defaultRoutes, - }) - Vue.use(router) + }); + Vue.use(router); - //Vue I18n + // Vue I18n const i18n = createI18n({ locale: 'en', fallbackLocale: 'en', - }) - Vue.use(i18n) + }); + Vue.use(i18n); }, -} +}; ``` + 3. **Create your web component** using `createWebComponent`. It takes an options object where you specify your root Vue component, the element name for your custom element, any plugins you want to use, and any CSS framework styles. + ```javascript createWebComponent({ rootComponent: App, @@ -119,11 +128,14 @@ createWebComponent({ h, createApp, getCurrentInstance, - disableStyleRemoval: false, //default is false - disableShadowDOM: false, //default is false + disableStyleRemoval: false, // default is false + disableShadowDOM: false, // default is false + replaceRootWithHost: false, // default is false }); ``` + Each option in the `createWebComponent` function has a specific purpose: + - `rootComponent`: The root component of your Vue application. - `elementName`: The tag name for your custom web component. It must contain a hyphen and be lowercase. - `plugins`: Any Vue plugins you want to use in your application. @@ -132,25 +144,52 @@ Each option in the `createWebComponent` function has a specific purpose: - `h`: The `h` function from Vue. - `createApp`: The `createApp` function from Vue. - `getCurrentInstance`: The `getCurrentInstance` function from Vue. -- `disableStyleRemoval`: Boolean to disable removal of styles on unmount. -- `disableShadowDOM`: Boolean to disable shadow DOM. +- `disableStyleRemoval`: Boolean to disable removal of styles on unmount, which can solve issues with CSS transitions. +- `disableShadowDOM`: Boolean to disable Shadow DOM for web components. +- `replaceRootWithHost`: **New Feature** (default `false`). Boolean to replace `:root` selectors with `:host` in your CSS styles. + +### replaceRootWithHost + +The `replaceRootWithHost` option allows you to replace all occurrences of `:root` with `:host` in your `cssFrameworkStyles`. This is particularly useful when working with CSS variables defined on `:root`, ensuring they are properly scoped within the Shadow DOM of your web component. + +#### Example Usage: + +```javascript +createWebComponent({ + rootComponent: App, + elementName: 'my-web-component', + plugins: pluginsWrapper, + cssFrameworkStyles: tailwindStyles, + VueDefineCustomElement, + h, + createApp, + getCurrentInstance, + replaceRootWithHost: true, +}); +``` ### cssFrameworkStyles -The `cssFrameworkStyles` option is used to import the CSS of your CSS framework or any other css style that your application needs to have globally, this option can also handle css vars that define on a `:root` selector. + +The `cssFrameworkStyles` option is used to import the CSS of your CSS framework or any other CSS styles that your application needs to have globally. This option can also handle CSS variables that are defined on a `:root` selector. + +By setting `replaceRootWithHost` to `true`, any `:root` selectors in your CSS framework styles will be replaced with `:host`. This ensures that styles and CSS variables are correctly scoped to the web component, preventing unintended style leakage or conflicts with the parent document. + +In some cases, you might want to use CSS variables defined in `:root` that penetrate the Shadow DOM. To achieve this, you need to import the CSS variables to the host of the web component. 4. **Build your application**. Tested bundler to build the web-component application. + ## Bundlers Configuration
Vite Configuration -## Vite.js Configuration +### Vite.js Configuration -Here's a sample Vite configuration. Comparing with Webpack, Vite.js is able to handle assets files like .css and .scss, and media files, importing them as you do regularly. Vue files will be parsed using oficial [@vitejs/plugin-vue](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue) depending of config. If you would like to add plugins for Vite, just install them with your favorite Node package manager. +Here's a sample Vite configuration. Comparing with Webpack, Vite.js is able to handle asset files like `.css` and `.scss`, and media files, importing them as you do regularly. Vue files will be parsed using the official [@vitejs/plugin-vue](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue) depending on config. If you would like to add plugins for Vite, just install them with your favorite Node package manager. ```javascript -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' +import { defineConfig } from 'vite'; +import vue from '@vitejs/plugin-vue'; export default defineConfig({ build: { @@ -161,19 +200,26 @@ export default defineConfig({ customElement: true, }), ], -}) +}); ``` -In your main.js/ts file, you will have to import the css framework in slightly different way then webpack with ```?inline``` at the end of the import statement. -This leads to a new iusse with fonts, which are not loaded when using ```?inline```. To fix this, you can import the font css in the App.vue file. -### main.js/ts + +In your `main.js/ts` file, you will have to import the CSS framework in a slightly different way than Webpack with `?inline` at the end of the import statement. This leads to a new issue with fonts, which are not loaded when using `?inline`. To fix this, you can import the font CSS in the `App.vue` file. + +#### main.js/ts + ```javascript -// ?inline can not handle import url() in css therefore fonts are not loaded, workaround is to add font css to the App.vue -import style from './style.css?inline' +// ?inline cannot handle import url() in CSS; therefore, fonts are not loaded. Workaround is to add font CSS to the App.vue +import style from './style.css?inline'; ``` + Workaround for fonts: -### App.vue -```css + +#### App.vue + +```html ``` -
- +
Webpack Configuration -## Webpack Configuration +### Webpack Configuration -Here's a sample webpack configuration that helps webpack understand how to load and process .vue, .css, and .scss files. It also sets up an HTML plugin for webpack. +Here's a sample webpack configuration that helps webpack understand how to load and process `.vue`, `.css`, and `.scss` files. It also sets up an HTML plugin for webpack. ```javascript const path = require('path'); @@ -212,7 +257,7 @@ module.exports = { test: /\.(vue|ce\.vue)$/, loader: 'vue-loader', options: { - customElement: true, + customElement: true, }, }, { @@ -273,47 +318,55 @@ module.exports = { extensions: ['.js', '.vue', '.json'], }, }; - ``` -With webpack you will have to import the css framework in slightly different way then vite with ```?raw``` at the end of the import statement. -### main.js/ts + +With webpack, you will have to import the CSS framework in a slightly different way than Vite with `?raw` at the end of the import statement. + +#### main.js/ts + ```javascript -import style from './style.css?raw' +import style from './style.css?raw'; ``` +
## Web Component without Shadow DOM -If you want to create a web component without shadow DOM, you can set the `disableShadowDOM` option to `true` in the `createWebComponent` function. This will create a web component without shadow DOM encapsulation. + +If you want to create a web component without Shadow DOM, you can set the `disableShadowDOM` option to `true` in the `createWebComponent` function. This will create a web component without Shadow DOM encapsulation. + This feature uses a patch to the Vue source code, which could lead to some issues with future versions of Vue. If you encounter any issues, please report them in the issues section of this repository. + ### Demo without Shadow DOM -[Demo Link](https://stackblitz.com/~/github.com/EranGrin/web-component-no-shadow-dom-demo) +[Demo Link](https://stackblitz.com/~/github.com/EranGrin/web-component-no-shadow-dom-demo) ## SFC as Custom Element -enhance the core functionality of SFC as Custom Element [defineCustomElement](https://vuejs.org/guide/extras/web-components#sfc-as-custom-element) with 2 new features: -1. **Nested Components**: You can use nested components with styles and for example share base components between multiple custom elements. -2. **Shadow DOM option**: You can disable shadow DOM for the SFC custom element. + +Enhance the core functionality of Single File Components (SFC) as Custom Elements [defineCustomElement](https://vuejs.org/guide/extras/web-components#sfc-as-custom-element) with two new features: + +1. **Nested Components**: You can use nested components with styles and, for example, share base components between multiple custom elements. +2. **Shadow DOM Option**: You can disable Shadow DOM for the SFC custom element. ### Usage + ```javascript // main.js import { defineCustomElementSFC } from 'vue-web-component-wrapper'; -const MyComponentElement = defineCustomElementSFC(MyComponent, {shadowRoot: false}) -customElements.define('my-component', MyComponentElement) +const MyComponentElement = defineCustomElementSFC(MyComponent, { shadowRoot: false }); +customElements.define('my-component', MyComponentElement); ``` ### Demo SFC Custom Element -[Demo Link](https://stackblitz.com/edit/vue-web-component-wrapper?file=README.md&startScript=SFC-demo) +[Demo Link](https://stackblitz.com/edit/vue-web-component-wrapper?file=README.md&startScript=SFC-demo) ## Tips -- **Testing Production Build**: the easiest way to test your production build is to run a local server in the `dist` folder. I use [valet](https://laravel.com/docs/10.x/valet) for this, but any local server should work. +- **Testing Production Build**: The easiest way to test your production build is to run a local server in the `dist` folder. You can use [valet](https://laravel.com/docs/10.x/valet) for this, but any local server should work. + ## Future Plans 1. **TypeScript Support**: Adding proper strict types. - - ## Contributing Contributions are welcome! To contribute to the project, please follow these steps: - Fork the repository @@ -323,8 +376,8 @@ Contributions are welcome! To contribute to the project, please follow these ste - Submit a pull request to the main repository Please make sure to follow the code style and conventions used in the project. + If you find a bug or have a feature request, please open an issue on the repository. ## License -This project is licensed under the MIT License - +This project is licensed under the MIT License. \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index 84ea65d..6f9545c 100644 --- a/docs/index.md +++ b/docs/index.md @@ -4,14 +4,15 @@ `vue-web-component-wrapper` is a powerful Vue 3 plugin designed for transforming full-fledged Vue applications into reusable web components (custom elements). These web components can be integrated into any website, enhancing flexibility and reusability. ## Why use `vue-web-component-wrapper`? -As of now, Vue 3 does not support the creation of full aplication as web components out of the box. This plugin aims to solve this problem by providing a simple and easy-to-use solution for creating web components from Vue applications. It also provides support for Vue ecosystem plugins such as Vuex, Vue Router, and Vue I18n. +As of now, Vue 3 does not support the creation of full applications as web components out of the box. This plugin aims to solve this problem by providing a simple and easy-to-use solution for creating web components from Vue applications. It also provides support for Vue ecosystem plugins such as Vuex, Vue Router, and Vue I18n. + ## Demo Check out these demo projects to see `vue-web-component-wrapper` in action: -- **Webpack implentaion**: Check out this [Webpack Demo Project](https://stackblitz.com/edit/vue-web-component-wrapper?file=README.md&startScript=webpack-demo) -- **Vite.js implentaion**: Check out this [Vite Demo Project](https://stackblitz.com/edit/vue-web-component-wrapper?file=README.md&startScript=vite-demo) +- **Webpack implementation**: Check out this [Webpack Demo Project](https://stackblitz.com/edit/vue-web-component-wrapper?file=README.md&startScript=webpack-demo) +- **Vite.js implementation**: Check out this [Vite Demo Project](https://stackblitz.com/edit/vue-web-component-wrapper?file=README.md&startScript=vite-demo) ## Key Features -- **Vue Plugins Compatibility**: Integrates seamlessly with key Vue ecosystem plugins. +- **Vue Plugins Compatibility**: Seamlessly integrates with key Vue ecosystem plugins. - **CSS Framework Support**: Compatible with major CSS frameworks like Tailwind CSS and Bootstrap. - **CSS Preprocessor Support**: Supports CSS preprocessors including SCSS and LESS. - **Scoped CSS**: Enables the use of scoped CSS in your components. @@ -22,7 +23,12 @@ Check out these demo projects to see `vue-web-component-wrapper` in action: - **Event Emitting Capability**: Enables the emission and handling of custom events from web components. - **Disable Style Removal on Unmount**: Option to control the removal of styles upon component unmount, addressing issues with CSS transition. - **Disable Shadow DOM**: Option to disable the Shadow DOM, rendering content in the light DOM. +- **Replace `:root` with `:host`**: New feature to replace `:root` selectors with `:host` in your CSS, ensuring proper style scoping within the Shadow DOM. + +## New Feature Highlight: Replace `:root` with `:host` +Our latest feature allows you to automatically replace `:root` selectors with `:host` in your CSS styles. This is particularly useful when working with CSS frameworks or custom styles that define variables or styles on the `:root` selector. By replacing `:root` with `:host`, these styles are correctly scoped within your web component's Shadow DOM. +[Learn more about the Replace `:root` with `:host` feature](./guide/replace-root-with-host.md) ## Tips -- **Testing Production Build**: the easiest way to test your production build is to run a local server in the `dist` folder. I use [valet](https://laravel.com/docs/10.x/valet) for this, but any local server should work. \ No newline at end of file +- **Testing Production Build**: The easiest way to test your production build is to run a local server in the `dist` folder. You can use [valet](https://laravel.com/docs/10.x/valet) for this, but any local server should work. diff --git a/docs/usage.md b/docs/usage.md index 24f7add..76a5261 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -58,6 +58,7 @@ createWebComponent({ getCurrentInstance, disableStyleRemoval: false, disableShadowDOM: false, + replaceRootWithHost: false, }); ``` Each option in the `createWebComponent` function has a specific purpose: @@ -70,4 +71,5 @@ Each option in the `createWebComponent` function has a specific purpose: - `createApp`: The `createApp` function from Vue. - `getCurrentInstance`: The `getCurrentInstance` function from Vue. - `disableStyleRemoval`: A boolean value that determines whether or not to remove styles on unmount. This is useful for CSS transitions. -- `disableShadowDOM`: A boolean value that determines whether or not to use Shadow DOM for the web component. \ No newline at end of file +- `disableShadowDOM`: A boolean value that determines whether or not to use Shadow DOM for the web component. +- `replaceRootWithHost`: A boolean value that determines whether or not to replace `:root` with `:host` in your CSS framework styles. This is useful for CSS variables that penetrate the Shadow DOM. diff --git a/package/index.js b/package/index.js index 43cb926..51fd9d7 100644 --- a/package/index.js +++ b/package/index.js @@ -12,7 +12,8 @@ export const createWebComponent = ({ createApp, getCurrentInstance, disableRemoveStylesOnUnmount = false, - disableShadowDOM = false + disableShadowDOM = false, + replaceRootWithHostInCssFramework = false }) => { if (!rootComponent) { console.warn('No root component provided. Please provide a root component to create a web component.') @@ -51,7 +52,8 @@ export const createWebComponent = ({ getCurrentInstance, elementName, disableRemoveStylesOnUnmount, - disableShadowDOM + disableShadowDOM, + replaceRootWithHostInCssFramework }, ) diff --git a/package/src/web-component-util.js b/package/src/web-component-util.js index 57250bf..5c8d9ce 100644 --- a/package/src/web-component-util.js +++ b/package/src/web-component-util.js @@ -16,6 +16,17 @@ function convertToOnEventName(eventName) { return 'on' + eventName.charAt(0).toUpperCase() + eventName.slice(1); } +// Function to replace ':root' with ':host' in CSS +function replaceRootWithHost(styles) { + if (typeof styles === 'string') { + return styles.replace(/:root/g, ':host'); + } else if (Array.isArray(styles)) { + return styles.map(style => style.replace(/:root/g, ':host')); + } else { + return styles; + } +} + export const defineCustomElement = ({ rootComponent, plugins, @@ -26,84 +37,87 @@ export const defineCustomElement = ({ getCurrentInstance, elementName, disableRemoveStylesOnUnmount, - disableShadowDOM -}) => - { - const customElementDefiner = disableShadowDOM ? VueDefineCustomElementPatch : VueDefineCustomElement - return customElementDefiner({ + disableShadowDOM, + replaceRootWithHostInCssFramework, +}) => { + const customElementDefiner = disableShadowDOM ? VueDefineCustomElementPatch : VueDefineCustomElement; + + const modifiedCssFrameworkStyles = replaceRootWithHostInCssFramework + ? replaceRootWithHost(cssFrameworkStyles) + : cssFrameworkStyles; + + return customElementDefiner({ name: 'vue-custom-element-root-component', - styles: [cssFrameworkStyles], + styles: [modifiedCssFrameworkStyles], props: { ...rootComponent.props, modelValue: { type: [String, Number, Boolean, Array, Object] } // v-model support - }, + }, emits: rootComponent?.emits, - + setup(props, { slots }) { - const emitsList = [...(rootComponent?.emits || []), 'update:modelValue'] - const app = createApp() - app.component('app-root', rootComponent) + const emitsList = [...(rootComponent?.emits || []), 'update:modelValue']; + const app = createApp(); + app.component('app-root', rootComponent); if (rootComponent.provide) { const provide = typeof rootComponent.provide === 'function' - ? rootComponent.provide() + ? rootComponent.provide() : rootComponent.provide; - + // Setup provide Object.keys(provide).forEach(key => { app.provide(key, provide[key]); }); } - - app.mixin({ + app.mixin({ mounted() { - if (this.$?.type?.name === 'vue-custom-element-root-component') { - return + return; } const insertStyles = (styles) => { if (styles?.length) { - this.__style = document.createElement('style') - this.__style.innerText = styles.join().replace(/\n/g, '') - nearestElement(this.$el).append(this.__style) + this.__style = document.createElement('style'); + this.__style.innerText = styles.join().replace(/\n/g, ''); + nearestElement(this.$el).append(this.__style); } - } + }; - insertStyles(this.$?.type.styles) + insertStyles(this.$?.type.styles); if (this.$options.components) { for (const comp of Object.values(this.$options.components)) { - insertStyles(comp.styles) + insertStyles(comp.styles); } } }, unmounted() { - if(!disableRemoveStylesOnUnmount) { - this.__style?.remove() + if (!disableRemoveStylesOnUnmount) { + this.__style?.remove(); } }, - }) + }); - app.use(plugins) - - const inst = getCurrentInstance() - Object.assign(inst.appContext, app._context) - Object.assign(inst.provides, app._context.provides) + app.use(plugins); + + const inst = getCurrentInstance(); + Object.assign(inst.appContext, app._context); + Object.assign(inst.provides, app._context.provides); // Add support for Vue Devtools if (process.env.NODE_ENV === 'development' && window.__VUE_DEVTOOLS_GLOBAL_HOOK__) { const root = document.querySelector(elementName); app._container = root; app._instance = inst; - + const types = { Comment: Symbol('v-cmt'), Fragment: Symbol('v-fgt'), Static: Symbol('v-stc'), Text: Symbol('v-txt'), }; - + window.__VUE_DEVTOOLS_GLOBAL_HOOK__.emit('app:init', app, app.version, types); window.__VUE_DEVTOOLS_GLOBAL_HOOK__.Vue = app; } @@ -117,7 +131,7 @@ export const defineCustomElement = ({ // Establish named slots const namedSlots = rootComponent?.namedSlots?.reduce((acc, slotsName) => { - acc[slotsName] = () => h('slot',{ name: slotsName}); + acc[slotsName] = () => h('slot', { name: slotsName }); return acc; }, {}); @@ -134,4 +148,5 @@ export const defineCustomElement = ({ } ); }, - }, disableShadowDOM && { shadowRoot: false })} + }, disableShadowDOM && { shadowRoot: false }); +} diff --git a/package/types.d.ts b/package/types.d.ts index b80d4de..226ff76 100644 --- a/package/types.d.ts +++ b/package/types.d.ts @@ -18,6 +18,7 @@ export interface CreateWebComponentOptions { } export function createWebComponent(options: CreateWebComponentOptions): void +export default createWebComponent interface defineCustomElementSFCOptions {