Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added shadowRoot for vue-style-loader #238

Closed
wants to merge 2 commits into from
Closed

added shadowRoot for vue-style-loader #238

wants to merge 2 commits into from

Conversation

SergkeiM
Copy link

Hi, vue-style-loader can inject css into shadowDom, what is missing from vue-custom-element is reference to this shadowDom.

this PR fixes it.

Usage:

import Vue from 'vue';
import vueCustomElement from "vue-custom-element";

Vue.use(vueCustomElement);

Vue.customElement('test-component', () => import("./components/TestComponent").then(c => c.default), {
	shadow: true
});

//component
//
<template>
	<div class="myClass">This is red color</div>
</template>
<style lang="scss">
	.myClass{
		color: red;
	}
</style>


//Webpack
{
    test: /\.vue$/,
    use: [
        {
            loader: 'vue-loader',
            options: {
            	shadowMode: true
            }
        }
    ]
},
{
    test: /\.scss$/, //as example I used scss
    use: [
        {
            loader: 'vue-style-loader',
            options: {
                shadowMode: true
            }
        }
    ]
}

Fixes: #214 #191 #156

@SergkeiM
Copy link
Author

Hi @karol-f

I think I've rushed wil pull-request, we could do this in:

beforeCreateVueInstance(root){

	const rootNode = root.el.getRootNode();
	
	if(rootNode instanceof ShadowRoot){

		root.shadowRoot = rootNode

	}else{

		root.shadowRoot = document.head;
	}

	return root;

}		

I use document.head in case shadow dom is not available.

@bryanvaz
Copy link

bryanvaz commented Jan 2, 2021

@Froxz do you have an example project demonstrating how the fix works?

I'm trying to extrapolate how to use it for VueCLI 3 users, but webpack refuses to attach the styles to the shadowDOM. It seems that the shadowDOM does not exist yet when webpack tries to inject the styles

@SergkeiM
Copy link
Author

SergkeiM commented Jan 2, 2021

Hi @bryanvaz ,

I use laravel-mix, but a fork because laravel-mix doesn't support yet vue-style-loader

Also becuase css-loader 4+ uses esModule loader and is not yet implemented in vue-style-loader

As you can see there are a lot "but". But here is working code sample:

  • You need laravel mix with same changes as my fork (or use webpack directly)
  • You need css-loader version ^3
  • Attach shadowDom on vue-custom-element beforeCreateVueInstance callback
// src/index.js
import Vue from "vue";
import vueCustomElement from "vue-custom-element";
import myComponent from "./components/myComponent";

Vue.customElement('my-component', myComponent, {
	shadow: true,
	beforeCreateVueInstance(root){

		const rootNode = root.el.getRootNode();
		
		if(rootNode instanceof ShadowRoot){

			root.shadowRoot = rootNode

		}else{

			root.shadowRoot = document.head;
		}

		return root;

	}
});

Full list of devDependencies Note: you don't need to install vue-style-loader it is included in vue-loader.

"devDependencies": {
  "postcss": "^8.2.2",
  "vue-loader": "^15.9.6",
  "vue-template-compiler": "^2.6.12",
  "css-loader": "^3.6.0",
  "laravel-mix": "https://github.com/Froxz/laravel-mix.git#custom-latest",
  "sass": "^1.32.0",
  "sass-loader": "^10.1.0",
  "vue": "^2.6.12",
  "vue-custom-element": "^3.2.14"
}

laravel-mix config

const mix = require('laravel-mix');

mix.js('src/index.js', 'dist/webcomponents.js').vue({
	version: 2,
	options: {
		shadowMode: true
	}
});

let me know if you need anything else.

Full example repo: https://github.com/Froxz/webcomponents

P.S. I think if you use Vue CLI it will not work espicially if you target wc

@bryanvaz
Copy link

bryanvaz commented Jan 3, 2021

Hi @Froxz,

Ok I think I get it now, your PR isn't necessarily required if you use the beforeCreateVueInstance.
Theoretically all the pieces are there. Your custom laravel-mix should just be the same and adding the shadowMode:true directly to vue-loader and vue-style-loader's vue.config.js

Oh target wc tells vue cli to use the old "official" wc wrapper, which is just barely maintained. A straight target lib works fine when using karol's library.

@SergkeiM
Copy link
Author

SergkeiM commented Jan 4, 2021

Hi @bryanvaz yeap closing the PR, as using beforeCreateVueInstance does the job.

@SergkeiM SergkeiM closed this Jan 4, 2021
@bryanvaz
Copy link

bryanvaz commented Jan 4, 2021

Hi @bryanvaz yeap closing the PR, as using beforeCreateVueInstance does the job.

Should probably create a separate PR to add this to the docs, since running in shadow mode requires users to pass specific code into the Vue.customElement call (Without the stylings, custom components in shadow mode are pretty useless).

I'm planning on updating the docs myself since there's no clear instructions on how to properly contain a component in the shadow DOM, but I still can't find out why Vue CLI is refusing to inject the styles (both in HMR, straight prod builds, and umd/cjs builds). Theoretically all the correct pieces are there:

  • css-loader@^3
  • shadowMode: true for all vue-style-loader uses
  • Attaching the shadowDOM with beforeCreateVueInstance

I've set aside today to try to debug this. For some reason the final injection call for styles in vue-style-loader is never triggered.

If I can't figure it out, @Froxz can you take a look later this week? I saw you had some open PRs on the same topic in vue-style-loader and laravel-mix, so I'm sure you'll be able to find something I missed.

Cheers,
Bryan

@SergkeiM
Copy link
Author

SergkeiM commented Jan 4, 2021

Hi @bryanvaz Can you make a repo with full example, I will take a look.

@bryanvaz
Copy link

bryanvaz commented Jan 5, 2021

@Froxz, I managed to get it working this afternoon.
You can have a look. It was actually quite simple once I paired your beforeCreateVueInstance fix with my vue.config.js updates for shadowMode.

Haven't tested it with Vue 3 or css-modules^4, but it theoretically should work. I'll update the docs tomorrow.

Right now I'm fighting with vuetify to create an example, however I think the library might be too far gone. Do you have any Material UI or visual primitive libraries which might make a good example of how the shadow DOM isolates visual styles?

Example: https://github.com/bryanvaz/vue-custom-element-shadow-examples
(still have to clean up and doc the examples)

@FuriosoJack
Copy link

Hola @bryanvaz ,

Yo uso laravel-mix, sino un tenedor porque laravel-mezcla no apoyo aúnvue-style-loader

También porque css-loader 4+ usa esModule loader y aún no está implementado envue-style-loader

Como puede ver, hay muchos "pero". Pero aquí hay una muestra de código de trabajo:

  • Necesitas laravel mix con los mismos cambios que mi fork (o usa webpack directamente)
  • Necesitas la css-loaderversión ^ 3
  • Adjuntar shadowDomen vue-custom-element beforeCreateVueInstancedevolución de llamada
// src / index.js 
importa  Vue  desde  "vue" ; 
importar  vueCustomElement  de  "vue-custom-element" ; 
importar  myComponent  desde  "./components/myComponent" ;

Vue . customElement ( 'my-component' ,  myComponent ,  { 
	shadow : true , 
	beforeCreateVueInstance ( root ) {

		const  rootNode  =  root . el . getRootNode ( ) ;
		
		si ( rootNode  instanceof  ShadowRoot ) {

			raíz . shadowRoot  =  rootNode

		} más {

			raíz . shadowRoot  =  documento . la cabeza ; 
		}

		return  root ;

	} 
} ) ;

La lista completa de devDependenciesNota: no es necesario que la instale vue-style-loader, está incluida en vue-loader.

" devDependencies " : {
   " postcss " : " ^ 8.2.2 " ,
   " vue-loader " : " ^ 15.9.6 " ,
   " vue-template-compiler " : " ^ 2.6.12 " ,
   " css-loader " : " ^ 3.6.0 " ,
   " laravel-mix " : " https://github.com/Froxz/laravel-mix.git#custom-latest " ,
   "descaro " : "^ 1.32.0 " ,
   " sass-loader " : " ^ 10.1.0 " ,
   " vue " : " ^ 2.6.12 " ,
   " vue-custom-element " : " ^ 3.2.14 " 
}

laravel-mix config

const  mix  =  require ( 'laravel-mix' ) ;

mezclar . js ( 'src / index.js' ,  'dist / webcomponents.js' ) . vue ( { 
	versión : 2 , 
	opciones : { 
		shadowMode : true 
	} 
} ) ;

Déjame saber si necesitas algo más.

Repo de ejemplo completo: https://github.com/Froxz/webcomponents

PD: Creo que si usa Vue CLI, no funcionará especialmente si target wc

With your example you have saved my life, you should make the pull request of the changes so that laravel-mix takes them into account. Thanks a thousand thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Inline style from Vue componet
3 participants