Стайлинг не применяется к веб-компоненту vue во время разработки
При разработке веб-компонента Vue style
не применяется к веб-компоненту, но добавляется в head
документа. Это означает, что стиль игнорируется в тени DOM. Вот как я обертываю веб-компонент в 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);
Опять же, любые правила CSS внутри тегов стиля не вступают в силу.
Когда я создаю для производства, стили добавляются в веб-компонент. Я использую следующую команду для переноса:
vue-cli-service build --target wc --name my-web-component ./src/components/MyWebComponent.vue
Есть ли способ достичь того же, что и vue-cli-service serve
?
edit: example repo здесь: https://github.com/snirp/vue-web-component
edit2: У меня такое чувство, что моя проблема тесно связана с этой проблемой. Я не могу разобраться в обходных решениях, и я бы оценил более базовое решение.
Ответы
Ответ 1
Я не использую VUE, но этот код должен работать в любом месте и помещать ваш CSS в нужное место.
Я делаю некоторые предположения в этом коде, вы передаете свой пользовательский элемент (если вы не используете shadowDOM) или ваш shadowRoot
(если вы используете shadowDOM) в качестве первого параметра, и вы передаете элемент <style>
в качестве второго параметра, Также <style>
должен включать атрибут с именем component="<your component name>"
чтобы код не вставлял стиль более одного раза.
// Check to see if 'el' has been placed into a shadow root.
// If it has then add our CSS into that shadow root.
// Otherwise place the CSS into the '<head>' element.
function setCss(el, styleEl) {
let comp = (styleEl instanceof DocumentFragment ? styleEl.querySelector('style') : styleEl);
comp = comp.getAttribute('component');
if (!comp) {
throw new Error('Your '<style>' tag must set the attribute 'component' to the component name. (Like: '<style component="my-element">')');
}
let doc;
// istanbul ignore else
if (el.getRootNode) {
doc = el.getRootNode();
// istanbul ignore else
if (doc === document) {
doc = document.head;
}
}
else {
doc = document.head; // Shadow DOM isn't supported so place it in '<head>'
}
// istanbul ignore else
if (!doc.querySelector('style[component="${comp}"]')) {
doc.appendChild(styleEl.cloneNode(true));
}
}
export default setCss;
Ответ 2
Основываясь на проблеме GitHub, которую вы связали, решение заключается в установке опции shadowMode
в vue-loader
и vue-style-loader
. shadowMode
по умолчанию является false
в проекте Vue CLI, но мы можем настроить его в vue.config.js
.
Во-первых, мы проверили конфигурацию Webpack, чтобы определить, какие загрузчики должны измениться:
# run at project root
vue inspect
Вывод команды показывает несколько shadowMode: false
загрузчика с 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 // <---
}
},
/* ... */
]
},
/* ... */
полный список конфигураций загрузчика Webpack с 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')
Таким образом, мы можем установить shadowMode: true
для этих vue.config.js
в vue.config.js
с помощью этого фрагмента:
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);
}
}
Создание <projectroot>/vue.config.js
с приведенным выше фрагментом позволяет использовать Shadow CSS в вашем проекте. См. Https://github.com/snirp/vue-web-component/pull/1.