简体   繁体   English

在 shadow-root 内部注入 CSS styles 而不是 head 标签 | Vue.js & Webpack

[英]Inject CSS styles inside of the shadow-root instead of the head tag | Vue.js & Webpack

I'm making an embeddable widget for websites using Vue.js and vue-custom-element .我正在使用 Vue.js 和vue-custom-element为网站制作一个可嵌入的小部件。 Everything was going smoothly until I ran into a problem.一切都很顺利,直到我遇到问题。

When I'm trying to use a component (with css) from a package.当我尝试使用 package 中的组件(带有 css)时。 Like vue-number-input for example.例如像vue-number-input一样。 The css gets injected in the head of the webpage even though it should be added inside the shadow root. css 被注入到网页的头部,即使它应该被添加到影子根中。

As you can see here you see that the css from the number input package is injected inside the head while the other stylings are in the shadow root like they should.正如您在此处看到的,您看到来自数字输入 package 的 css 被注入到头部内部,而其他样式则像应有的那样位于阴影根中。

As far as I know I changed all of the settings needed to make the application work inside a shadow root.据我所知,我更改了使应用程序在影子根中工作所需的所有设置。

This is my vue.config.js , my main.js (where I register the custom element) and my component (where I import the component from the package).这是我的vue.config.js 、我的main.js (我注册自定义元素的地方)和我的组件(我从包中导入组件的地方)。

Does anyone know how I can do this or is this even possible?有谁知道我怎么能做到这一点,或者这甚至可能吗?

If the library is itself embedding the styles to the head of the page, then there is nothing you can do other than to write some script to manually copy it into the shadow dom after initialization.如果库本身将 styles 嵌入到页面的头部,那么除了编写一些脚本在初始化后手动将其复制到 shadow dom 之外,您无能为力。 I ran into the same issue for Font Awesome icons.我在 Font Awesome 图标上遇到了同样的问题。 Luckily, they provided a fix for this.幸运的是,他们为此提供了解决方案。 ( https://github.com/FortAwesome/vue-fontawesome#web-components-with-vue-web-component-wrapper ) https://github.com/FortAwesome/vue-fontawesome#web-components-with-vue-web-component-wrapper

After a lot of research for a solution which actually lazy-loaded our styles into the shadow-root, we didn't find one.在对实际上将我们的 styles 延迟加载到 shadow-root 中的解决方案进行了大量研究之后,我们没有找到。 We went with suboptimal solution which is loading all the styles on first load.我们采用了次优解决方案,即在第一次加载时加载所有 styles。

Note: This makes it work for QA and production environments.注意:这使它适用于 QA 和生产环境。 When developing, the styles will still be loaded inside of the head of the page.开发时,styles 仍然会加载到页面头部的内部。 So you have to make sure no other styles conflict with that.所以你必须确保没有其他 styles 与此冲突。

This was our way of accomplishing this:这是我们实现这一目标的方式:

// vue.config.js

const webpack = require('webpack');

module.exports = {
  configureWebpack: {
    // ...
    plugins: [
      new webpack.optimize.LimitChunkCountPlugin({
        maxChunks: 1,
      }),
    ],
  },
  chainWebpack: (config) => {
    config.optimization.delete('splitChunks');
  },
};
// main.js

import createStyleLink from '@/helpers/createStyleLink';

// ...

const options = {};

// Enable shadow root for production build
if (process.env.NODE_ENV === 'production') {
  options.shadow = true;
  options.beforeCreateVueInstance = (root) => {
    const rootNode = root.el.getRootNode();
    if (rootNode instanceof ShadowRoot) {
      root.shadowRoot = rootNode;
    } else {
      root.shadowRoot = document.head;
    }
    // After deployment, this will create a style link and put it inside the shadow root. 
    // Preferably, you would use a CDN for this.
    createStyleLink(rootNode, `${process.env.VUE_APP_URL}/css/app.css`);
    return root;
  };
}

// ...

Vue.customElement('widget', App, options);
// createStyleLink.js

export default function (node, url) {
  const link = document.createElement('link');
  link.href = url;
  link.type = 'text/css';
  link.rel = 'stylesheet';
  node.appendChild(link);
}

I'll not mark this as a solution as this is more like a suboptimal workaround.我不会将此标记为解决方案,因为这更像是一种次优的解决方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM