After a lot of research for a solution which actually lazy-loaded our styles into the shadow-root, we didn't find one. We went with suboptimal solution which is loading all the styles on first load.
Note: This makes it work for QA and production environments. When developing, the styles will still be loaded inside of the head of the page. So you have to make sure no other styles conflict with that.
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.