TheLarkInn / unity-component-specification

This is a WIP draft of the Unity (Single File Web Component) Specification
Apache License 2.0
217 stars 2 forks source link

unity-component-specification

This is a WIP draft of the Unity (Single File Web Component) Specification

Abstract

Unity Component Specification describes a new hypertext-like file format for creating Single-File Web Components (SFWC).

Goals

Scenario:

Giant company (A) is silo'd and has a variety of different frameworks that they use in house, and they all love the workflows that they have, however there is massive amounts of overlap because they cannot write components that both teams can use.

With "unity components" (Single File Components) this could be possible: Team A using Preact (Figure 1), could use this component in the same way that Team B using 'Vue' (Figure 2) does.

Figure 1: Using Button.sfc in .js file and consumed with preact render() fn

import {Button} from "material-unity" // returns a SFC "module" .sfc or .vue, etc whatever

render(
    <Button someProp="whatever" />,
    document.body
);

Figure 2: Using same Button.sfc inside of a Vue single file component

<template>
    <div>
        <button some-prop="whatever"></button>
    </div>
</template>
<script>
import {Button} from "material-unity" // returns a SFC "module" .sfc or .vue, etc whatever
export default {
  components: {
    Button
  }
}
</script>
<style>
  /* ... */
</style>

The point is that the framework-specific implementation details of how this "meta information" represented in the Single File Component are hidden through the compiler toolchains.

So although you might see data(){} function that returns state for the component, it may instead compile to state in react/preact, or @tracked in GlimmerJS.

How this relates to the platform (the long term idea if frameworks buy in @first)

Although this statement may be opinionated, it is observed that the number one problem with web components currently is that it is a write only target, not something a framework could consume and then use (like their own systems components) without potentially substantial changes to their respective api's, renders, etc. This poses a huge challenge for adoption.

In addition, until there is cross-platform adoption for Web Components completely, there is really no interest for a majority of users or framework teams to start integrating with this system.

Abstraction not only for Frameworks, but also the Platform

The magic behind what makes Vue's single file component structure so flexible and powerful, is that everything inside of their respective tags, is only a "likeness" to some extent.

For example:

<template>
  <div>I look and smell like HTML, but I'm not HTML. I'm HTML-like</div>
</template>
<style>
.div {
  likeness: to-css;
}
</style>
<script>
export default {
  data() {
    maybe: "Interpreted through the context of the component, but technically this could _not_ really be JavaScript, just a state machine's instructions"
  }
}
</script>

In the same way that:

render(
   <JSX>I look and smell like HTML, but I'm not html, I'm JSX, I'm html-like</JSX>,
   document.body
)

So in the same way that a loader, compiler, etc. statically analyzes a .vue file to create a JavaScript implementation of that components Dom API functionality (via VDOM), we can apply the same principle for the platform to accomplish the same thing.

In a real index.html file

<head>
<module type="unity" name="unity-button" src="https://github.com/TheLarkInn/unity-component-specification/raw/master/unity-components/button.sfc" />
<head>

<body>
  <unity-button some-prop="whatever">Click Me</unity-button>
</body>

We have fed a single component to the browser, which consumes the SFC module, and instead of creating render functions, vdom, JSX, javascript, or anything else, it is interpreted and compiled to native instructions for the lifecycle, state, and the visual representation and behavior for that element on the DOM.

Side Notes:

Here's some things I want to clarify before they get mentioned

Template "Directives"

A huge motivation for the use of these universal directives, is the same reason why they are great in VueJs. Although at any time, in a single-file .vue component, a user can drop <template></template> and instead opt-in to using render(<JSX/>, document.body) instead.

But in the end (for vue):

<template>
  <div v-for="item of 1000000items">{{item}}</div>
</template>

is just an abstraction that compiles to VDOM/Render functions to perform that ginormous scrolling list. The benefit of the platform consuming this, is that it can read that directive as an instruction to perform the same results, but in a far more, Ken Wheeler-defying-90fps-fashion (because its not DOM, or JS, its native instructions interpreted from the file).

JSX inside of <script>

In the same way that <template></template> can be statically analyzed and compiled, you can take this a step further and say the use of JSX inside of <script></script> could have a similar outcome.

Pros:

Cons:

Use Cases

Currently there are multiple JavaScript web frameworks that use an interoperable Single-File Web Component format. Not only are they a unifying formate between frameworks, but should aim to be a native platform implementation.

Unity Component Module

hello-world.ucm

<template>
    <h1>Hello {{world}}!</h1>
</template>

<style>
    h1 {
        background: "red";
    };
</style>

<script>
  export default {
    data() {
      return {
        world: "world"
      }
    }
  }
</script>

Interface

This file format will support a strict subset of hypertext markup tags that will delimit and distinguish the use of JavaScript, HTML, and CSS in the single file.

<template></template> tags

Syntax

Data Binding

Directives

<style></style> tags

Syntax

Scoped? 😬

<script></script> tags

Syntax

UCM Options Object