While developing a Vue web component, the style
is not applied to the web component, but added to the head
of the document. This means that the style is ignored in the shadow DOM. Here is how I wrap the web component in main.js:
import Vue from 'vue'; import wrap from '@vue/web-component-wrapper'; import MyWebComponent from './components/MyWebComponent'; const WrappedElement = wrap(Vue, MyWebComponent); window.customElements.define('my-web-component', WrappedElement);
Again, any CSS rules inside the style tags do not take effect.
When I build for production, the styles are added to the web component. I use the following command to do the wrapping:
vue-cli-service build --target wc --name my-web-component ./src/components/MyWebComponent.vue
Is there a way to achieve the same thing with vue-cli-service serve
?
edit: example repo here: https://github.com/snirp/vue-web-component
edit2: I have the feeling my problem is closely related to this issue. I cannot make much sense of the workarounds, and I would value a more basic solution.
Based on the GitHub issue you linked, the solution is to set the shadowMode
option in vue-loader
and vue-style-loader
. shadowMode
is false
by default in a Vue CLI project, but we can tweak that in vue.config.js
.
First, we'd inspect the Webpack config to determine which loaders to change:
# run at project root vue inspect
The command output reveals several loader configs with shadowMode: false
:
/* config.module.rule('css') */ { test: /\.css$/, oneOf: [ /* config.module.rule('css').oneOf('vue-modules') */ { resourceQuery: /module/, use: [ /* config.module.rule('css').oneOf('vue-modules').use('vue-style-loader') */ { loader: 'vue-style-loader', options: { sourceMap: false, shadowMode: false // <--- } }, /* ... */ ] }, /* ... */
full list of Webpack loader configs with shadowMode: false
:
config.module.rule('vue').use('vue-loader') config.module.rule('css').oneOf('vue-modules').use('vue-style-loader') config.module.rule('css').oneOf('vue').use('vue-style-loader') config.module.rule('css').oneOf('normal-modules').use('vue-style-loader') config.module.rule('css').oneOf('normal').use('vue-style-loader') config.module.rule('postcss').oneOf('vue-modules').use('vue-style-loader') config.module.rule('postcss').oneOf('vue').use('vue-style-loader') config.module.rule('postcss').oneOf('normal-modules').use('vue-style-loader') config.module.rule('postcss').oneOf('normal').use('vue-style-loader') config.module.rule('scss').oneOf('vue-modules').use('vue-style-loader') config.module.rule('scss').oneOf('vue').use('vue-style-loader') config.module.rule('scss').oneOf('normal-modules').use('vue-style-loader') config.module.rule('scss').oneOf('normal').use('vue-style-loader') config.module.rule('sass').oneOf('vue-modules').use('vue-style-loader') config.module.rule('sass').oneOf('vue').use('vue-style-loader') config.module.rule('sass').oneOf('normal-modules').use('vue-style-loader') config.module.rule('sass').oneOf('normal').use('vue-style-loader') config.module.rule('less').oneOf('vue-modules').use('vue-style-loader') config.module.rule('less').oneOf('vue').use('vue-style-loader') config.module.rule('less').oneOf('normal-modules').use('vue-style-loader') config.module.rule('less').oneOf('normal').use('vue-style-loader') config.module.rule('stylus').oneOf('vue-modules').use('vue-style-loader') config.module.rule('stylus').oneOf('vue').use('vue-style-loader') config.module.rule('stylus').oneOf('normal-modules').use('vue-style-loader') config.module.rule('stylus').oneOf('normal').use('vue-style-loader')
So, we can set shadowMode: true
for those configs in vue.config.js
with this snippet:
function enableShadowCss(config) { const configs = [ config.module.rule('vue').use('vue-loader'), config.module.rule('css').oneOf('vue-modules').use('vue-style-loader'), config.module.rule('css').oneOf('vue').use('vue-style-loader'), config.module.rule('css').oneOf('normal-modules').use('vue-style-loader'), config.module.rule('css').oneOf('normal').use('vue-style-loader'), config.module.rule('postcss').oneOf('vue-modules').use('vue-style-loader'), config.module.rule('postcss').oneOf('vue').use('vue-style-loader'), config.module.rule('postcss').oneOf('normal-modules').use('vue-style-loader'), config.module.rule('postcss').oneOf('normal').use('vue-style-loader'), config.module.rule('scss').oneOf('vue-modules').use('vue-style-loader'), config.module.rule('scss').oneOf('vue').use('vue-style-loader'), config.module.rule('scss').oneOf('normal-modules').use('vue-style-loader'), config.module.rule('scss').oneOf('normal').use('vue-style-loader'), config.module.rule('sass').oneOf('vue-modules').use('vue-style-loader'), config.module.rule('sass').oneOf('vue').use('vue-style-loader'), config.module.rule('sass').oneOf('normal-modules').use('vue-style-loader'), config.module.rule('sass').oneOf('normal').use('vue-style-loader'), config.module.rule('less').oneOf('vue-modules').use('vue-style-loader'), config.module.rule('less').oneOf('vue').use('vue-style-loader'), config.module.rule('less').oneOf('normal-modules').use('vue-style-loader'), config.module.rule('less').oneOf('normal').use('vue-style-loader'), config.module.rule('stylus').oneOf('vue-modules').use('vue-style-loader'), config.module.rule('stylus').oneOf('vue').use('vue-style-loader'), config.module.rule('stylus').oneOf('normal-modules').use('vue-style-loader'), config.module.rule('stylus').oneOf('normal').use('vue-style-loader'), ]; configs.forEach(c => c.tap(options => { options.shadowMode = true; return options; })); } module.exports = { // https://cli.vuejs.org/guide/webpack.html#chaining-advanced chainWebpack: config => { enableShadowCss(config); } }
Creating <projectroot>/vue.config.js
with the snippet above enables Shadow CSS in development mode in your project. See https://github.com/snirp/vue-web-component/pull/1.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With