vuejs / vue-component-compiler

Compile a single file Vue component into a CommonJS module.
MIT License
342 stars 52 forks source link

How to distribute the runtime (`normalizeComponent` and style injection code)? #36

Closed znck closed 6 years ago

znck commented 6 years ago

I think this is tricky since it involves how the bundler can locate the packages, and in some cases, the runtime may need to be directly inlined (related to #33). –– Evan

znck commented 6 years ago

/ping @eddyerburgh @chrisvfritz @LinusBorg

chrisvfritz commented 6 years ago

I'm not sure I have enough experience in the problem domain in this case. 😕 Or maybe I just don't fully understand the problem. @znck If you think it might also be helpful for other people, could you go into more detail on the problem, potential solutions, and their pros and cons as you understand them?

yyx990803 commented 6 years ago

Great job @znck , this seems to be the only thing left on the list! I'm at ScriptConf in Austria this week but will try to give this some proper thinking once I'm back.

znck commented 6 years ago

The assemble step combines various parts of an SFC at runtime. For this normalize-component module is used. Until now we used to add an import (import __vue_normalize_component__ from 'normalize-component') to the assembled script but with the requirement of inline assemble this won't be possible. For inline assemble, we can't assume the presence of any module bundler.

A similar problem is faced inlining <script> and render functions generated for <template>. The javascript module generated from <template> have a fixed format, so I am converting it to an IIFE. Inlining <script> gets trickier as there are so many ways to write that. What comes to the rescue is there would always be a default export, so I am replacing export default with var __vue_script__ =. The method mentioned above would work with the assumption that there won't be any variables or functions named like __vue_xxxx__.

But inlining other runtime modules like normalize-component or inject-script gets even trickier, there are so many places to go wrong; as modules may import something and then we have to inline those too.

If we rewrite runtime modules to have no imports and only default export, then converting them to IIFE would work.

yyx990803 commented 6 years ago

Some thoughts: when users use this compiler in inline mode, they likely want to handle the styles in a more flexible way... for example, in Jest transformer we don't really care about the styles.

So instead of built-in style injection, in inline mode the user will be responsible for deciding what to do with the styles, maybe with an API like:

{
  handleStyles: styles => {
    // do something with the compiled styles
    // or return code that injects the styles (used in assemble)
  }
}

By default in inline mode styles will be ignored if this function is not provided.

With styles out of the question, normalizeComponent should be straightforward to inline.

znck commented 6 years ago

https://github.com/vuejs/vue-component-compiler/blob/7024fb841aaa36a42128084c0dad639fa6b016d6/src/assemble.js#L14-L27

For inlining CSS, it assumes style.code is CSS string and uses style injection script (depending upon server or client env). By handleStyles do you mean that style.code would be javascript?

znck commented 6 years ago

Not required anymore. The provided assemble method inlines everything.