Skip to content
This repository has been archived by the owner on Jan 18, 2022. It is now read-only.

How to define style within a web component? #284

Closed
elvisqi opened this issue May 20, 2019 · 3 comments
Closed

How to define style within a web component? #284

elvisqi opened this issue May 20, 2019 · 3 comments

Comments

@elvisqi
Copy link

elvisqi commented May 20, 2019

What problem does this feature solve?

I tried to use this plugin to write a UI library, but I found that the styles defined in the component did not take effect, and the template tag in the .vue file could not write style in it, and how to handle it more elegantly.

What does the proposed API look like?

the same solution with webpack:
vuejs/vue-web-component-wrapper#12 (comment)

{
shadowMode: true
}

@TomCaserta
Copy link

TomCaserta commented Jun 5, 2019

If you're only building web components in this library you can create a custom normalize-component.js that injects into the shadow dom and reference it in the normalizer option of the plugin.

Eg. normalize-component.js taken from the webpack version with shadow dom compatibility:

'use strict';
function createInjectorShadow(shadow) {
    return (inject, { source, map, media }) => {
        const style = document.createElement('style');
        style.appendChild(document.createTextNode(source));
        shadow.appendChild(style);
    };
}

function normalizeComponent(
    template,
    style,
    script,
    scopeId,
    isFunctionalTemplate,
) {
    var options = typeof script === 'function' ? script.options : script; // render functions

    if (template && template.render) {
        options.render = template.render;
        options.staticRenderFns = template.staticRenderFns;
        options._compiled = true; // functional template

        if (isFunctionalTemplate) {
            options.functional = true;
        }
    } // scopedId

    if (scopeId) {
        options._scopeId = scopeId;
    }

    var hook;

    if (style) {
        hook = function() {
            style.call(
                this,
                createInjectorShadow(this.$root.$options.shadowRoot),
            );
        };
    }

    if (hook) {
        if (options.functional) {
            // register for functional component in vue file
            var originalRender = options.render;

            options.render = function renderWithStyleInjection(h, context) {
                hook.call(context);
                return originalRender(h, context);
            };
        } else {
            // inject component registration as beforeCreate hook
            var existing = options.beforeCreate;
            options.beforeCreate = existing
                ? [].concat(existing, hook)
                : [hook];
        }
    }

    return script;
}

module.exports = normalizeComponent;

As with most workarounds though this should 100% be possible inside of the plugin itself without needing a custom normalizer.

@elvisqi elvisqi closed this as completed Jun 26, 2019
@hikaruna
Copy link

It does not work.

Please full example.
or Document.

https://rollup-plugin-vue.vuejs.org/options.html#normalizer
I think we should provide a hoge option

(relative from entryfile) filePath?

I tried {normalizer: './normalize-component.js'} , it does not work.(normalize-component.js put same entryfile directory)


But, I think that should provide a shadow:true option, because easy.

@zhuoqi-chen
Copy link

it works for me!

plugins:[
    vue({
      css: true,
      template: {
        isProduction: true,
      },
      isWebComponent: true // important
  })
]

source code:

isWebComponent?: boolean

opts.styleInjectorShadow =

https://github.com/vuejs/vue-component-compiler/blob/8f30d7e7e02d559b020f51da8586f4262cfc2e6b/src/assembler.ts#L399

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

No branches or pull requests

4 participants