Without authorization, shall not be reproduced, original address: github.com/axuebin/art…

Writing in the front

Especially big Beijing time in the afternoon of September 18, when the post a micro blog, people ruthless words are not much. By that look, everyone knew something big was about to happen. Sure enough, while writing this post, I was on GitHub for a look, and I came across this post:

The release of open source software is the final release.

Today we are proud to announce the official release of Vue.js 3.0 “One Piece”.

More information about this release can be found at github.com/vuejs/vue-n…

On top of that, I found another thing called Vue-lit on Uvu’s GitHub, and my gut told me it was another futuristic next-generation XXX, so I clicked in to see what it was.

Hello World

Proof of concept mini custom elements framework powered by @vue/reactivity and lit-html.

In what looks like a big validation attempt, see Custom Element and lit-HTML, a tool that renders Vue written Web Components directly in the browser.

Lit-html is mentioned here and will be covered later.

Let’s try Hello World as shown in the Demo:

<! DOCTYPEhtml>
<html lang="en">
  <head>
    <script type="module">
      import {
        defineComponent,
        reactive,
        html,
        onMounted
      } from 'https://unpkg.com/@vue/[email protected]';
  
      defineComponent('my-component'.() = > {
        const state = reactive({
          text: 'Hello World'});function onClick() {
          alert('cliked! ');
        }
  
        onMounted(() = > {
          console.log('mounted');
        });
  
        return () = > html`
          <p>
            <button @click=${onClick}>Click me</button>
            ${state.text}
          </p>
        `;
      })
    </script>
  </head>
  <body>
    <my-component />
  </body>
</html>
Copy the code

Open the index. HTML without any compiler tools, and it looks fine:

!

As you can see, a Web Component is rendered and the Mounted life cycle is triggered.

About lit-HTML and Lit-Element

Before we look at Vue-lit, let’s have a look at lit-HTML and lit-ement. These two things have been out for a long time and may not be understood by everyone.

lit-html

Lit-html may not be familiar to many people, or even seen before.

So what is it? The answer is an HTML template engine.

If there is no somatosensation, let me ask you a question: what are the core things in React? JSX, virtual-DOM, diff, yes, these are the things that make up the React UI = f(data).

Look at the syntax of JSX:

function App() {
  const msg = 'Hello World';
  return <div>{msg}</div>;
}
Copy the code

Look again at the syntax of lit-html:

function App() {
  const msg = 'Hello World';
  return html`
    <div>${msg}</div>
  `;
}
Copy the code

We know that JSX needs to be compiled and the bottom layer of it ends up being createElement…. . Lit-html, on the other hand, is based on tagged Template, which allows it to run in the browser without compiling. It can also be used with HTML template as much as you want.

Of course, both JSX and Lint-HTML require the App to render to the real DOM.

Lint-html implements a Button component

Go straight to the code (omit the style code) :

<! DOCTYPEhtml>
<html lang="en">
<head>
  <script type="module">
    import { html, render } from 'https://unpkg.com/lit-html?module';

    const Button = (text, props = {
      type: 'default',
      borderRadius: '2px'
    }, onClick) = > {
      // Click the event
      const clickHandler = {
        handleEvent(e) { 
          alert('inner clicked! ');
          if(onClick) { onClick(); }},capture: true};return html`
        <div class="btn btn-${props.type}" @click=${clickHandler}>
          ${text}
        </div>
      `
    };
    render(Button('Defualt'), document.getElementById('button1'));
    render(Button('Primary', { type: 'primary' }, () = > alert('outer clicked! ')), document.getElementById('button2'));
    render(Button('Error', { type: 'error' }), document.getElementById('button3'));
  </script>
</head>
<body>
  <div id="button1"></div>
  <div id="button2"></div>
  <div id="button3"></div>
</body>
</html>
Copy the code

Effect:

performance

Will lit-HTML perform better than React? Here I have not carefully read the source code, also did not carry out the relevant experiment, can not be determined.

A wild guess, however, is that rather than using the diff algorithm, lit- HTML is based directly on the same template update, which seems to be a bit lighter.

However, one of the questions we often ask is “What’s the key for when rendering lists?” This is not solved in lit-HTML. If I delete one of the items in the long list, the entire list will be updated once as per the lit-HTML update based on the same template, which is much worse.

// TODO: bury a hole, see later

lit-element

What is a lit element?

Key words: Web Components.

Example:

import { LitElement, html } from 'lit-element';

class MyElement extends LitElement {
  static get properties() {
    return {
      msg: { type: String}}; }constructor() {
    super(a);this.msg = 'Hello World';
  }
  render() {
    return html`
      <p>The ${this.msg}</p>
    `;
  }
}

customElements.define('my-element', MyElement);
Copy the code

Effect:

Conclusion: You can write the Web Component using the React syntax.

So, lit-Element is a base class for creating Web Components. In the Demo above, let’s take a look at what Lit-Element does:

  1. static get propertiesMay:setterstate
  2. constructorInitialization:state
  3. renderThrough:lit-htmlRender elements and createShadowDOM

Overall, lit-Element adheres to the Web Components standard, which is a class on which you can quickly create Web Components.

More on how to develop with Lit-Element will not be explained here.

Web Components

Does browser native capability smell good?

Before I talk about Web Components, I want to ask you, do you remember jQuery, its handy selectors. But then the Document. querySelector API came along and became widely used, and jQuery seemed to fade away.

The browser native API is good enough; you don’t need to use jQuery to manipulate the DOM.

You Dont Need jQuery

And then, has it been a while since you’ve worked directly with the DOM?

Yes, thanks to frameworks (libraries) like React/Vue, which do a lot of things for us, we can no longer manipulate the DOM through complicated DOM apis.

What I’m trying to say is, will React and so on be replaced by browser native capabilities one day when the browser native capabilities are good enough, like jQuery?

componentization

Frameworks like React/Vue do the same thing that the browser’s native capabilities didn’t do before, such as creating a reusable component that can render anywhere in the DOM.

How about now? We seem to be able to create reusable Components without using arbitrary frameworks and libraries, or even packaging and compiling them, just using the browser’s native capabilities like Web Components. Will we someday abandon the frameworks and libraries that we have today? Using native apis directly or using frameworks and libraries based on Web Components standards?

Of course, the future is unknowable

I’m not a Web Components blowhard, but we need to program for the future.

Take a look at some of the main features of Web Components.

Custom Elements: Custom elements

A custom element, as the name implies, allows the user to define a custom HTML element using the Define of CustomElementRegistry. For example:

window.customElements.define('my-element', MyElement);
Copy the code

It can then be used directly from
.

According to the specification, there are two kinds of Custom elements:

  • Autonomous custom elements: a separate element that inherits nothingHTMLElement can be used directly<my-element />
  • Customized buld-in elements: inherited fromHTMLElement, such as by{ extends: 'p' }To identify the inheritance frompElement is required when using<p is="my-element"></p>

The two Custom Elements are implemented differently:

// Autonomous custom elements
class MyElement extends HTMLElement {
  constructor() {
    super();
  }
}

// Customized -d In Elements: inherits from the P element
class MyElement extends HTMLParagraphElement {
  constructor() {
    super();
  }
}
Copy the code

More on Custom Elements

Life cycle function

In the constructor for Custom Elements, you can specify multiple callbacks that will be called at different times in the life of the element.

  • connectedCallbackThe element is inserted into the document for the first timeDOM
  • disconnectedCallback: element from the documentDOMTo remove the
  • AdoptedCallback: When an element is moved to a new document
  • AttributeChangedCallback: element to add, delete, modify its properties

Take a look at the attributeChangedCallback, which is executed every time an element’s attributes change and gets information about the element:

attributeChangedCallback(name, oldValue, newValue) {
  // TODO
}
Copy the code

In particular, if you want to trigger the attributeChangedCallback() callback after an attribute of an element has changed, you must listen for this attribute:

class MyElement extends HTMLElement {
  static get observedAttributes() {
    return ['my-name'];
  }
  constructor() {
    super();
  }
}
Copy the code

The callback method is triggered when the my-name attribute of the element changes.

Shadow DOM

A very important feature of Web Components that encapsulates structure and style within a component, isolated from the rest of the code on the page, is the Shadow DOM feature.

With respect to Shadow DOM, the main thing I want to talk about here is the style isolation feature of CSS. The selector in and out of the Shadow DOM is not retrievable from each other, so there is no way to use an externally defined style inside the Shadow DOM, and of course there is no way to retrieve an internally defined style outside the Shadow DOM.

What good would that do? Using local HTML and CSS, it solves some of the styling problems. It’s similar to vue’s scope. Inside the element, you don’t have to worry about whether the selector and CSS rule will be overwritten by others. If you accidentally overwrite someone else’s style. So, element selectors are very simple: title/item, etc., without any tools or naming constraints.

More on Shadow DOM

Templates, template

You can add HTML content to the Shadow DOM of a Web Component using

<body>
  <template id="my-paragraph">
    <style>
      p {
        color: white;
        background-color: # 666;
        padding: 5px;
      }
    </style>
    <p>My paragraph</p>
  </template>
  <script>
    customElements.define('my-paragraph'.class extends HTMLElement {
        constructor() {
          super(a);let template = document.getElementById('my-paragraph');
          let templateContent = template.content;

          const shadowRoot = this.attachShadow({mode: 'open'}).appendChild(templateContent.cloneNode(true)); }})</script>
  <my-paragraph></my-paragraph>
</body>
Copy the code

Effect:

We know that

More on Templates

vue-lit

Having introduced lit-HTML/Element and Web Components, we return to vue-lit.

The first thing we see in the Vue 3.0 Release is this:

The @vue/reactivity module exports functions that provide direct access to Vue’s reactivity system, and can be used as a standalone package. It can be used to pair with other templating solutions (e.g. lit-html) or even in non-UI scenarios.

The @vue/ ReActivity module, in conjunction with a lit-HTML like solution, can also be designed to provide direct access to the VUE responsive system.

Oh, no, that’s right. Isn’t it vue-lit?

The source code parsing

import { render } from 'https://unpkg.com/lit-html?module'
import {
  shallowReactive,
  effect
} from 'https://unpkg.com/@vue/reactivity/dist/reactivity.esm-browser.js'
Copy the code
  • lit-htmlProvide a corerenderAbility to
  • @vue/reactiityprovideVueCapability of responsive systems

ShallowReactive and effect

ShallowReactive: It’s just the first layer of response data

const state = shallowReactive({
  a: 1.b: {
    c: 2,
  },
})

state.a++ / / response type
state.b.c++ // Non-responsive
Copy the code

Effect: Watcher

const state = reactive({
  name: "Front end trial"});console.log(state); // Return the object after the Proxy
effect(() = > {
  console.log(state.name); // Effect will be reexecuted whenever the name data changes
});
Copy the code

Here we go:

export function defineComponent(name, propDefs, factory) {
  // propDefs
  // If it is a function, it is directly treated as a factory function
  // If they are arrays, listen to them and fire the attributeChangedCallback
  if (typeof propDefs === 'function') {
    factory = propDefs
    propDefs = []
  }
  // Call the Web Components function to create Custom Elements
  customElements.define(
    name,
    class extends HTMLElement {
      / / to monitor propDefs
      static get observedAttributes() {
        return propDefs
      }
      constructor() {
        super(a)// Create a shallow response
        const props = (this._props = shallowReactive({}))
        currentInstance = this
        const template = factory.call(this, props)
        currentInstance = null
        // beforeMount Life cycle
        this._bm && this._bm.forEach((cb) = > cb())
        // Define a Shadow root, and the internal implementation cannot be accessed or modified by JavaScript, similar to the 
      
        const root = this.attachShadow({ mode: 'closed' })
        let isMounted = false
        // watcher
        effect(() = > {
          if(! isMounted) {// beforeUpdate Life cycle
            this._bu && this._bu.forEach((cb) = > cb())
          }
          // Invoke the core rendering capabilities of lit-HTML. See the lit-HTML Demo above
          render(template(), root)
          if (isMounted) {
            // Update the lifecycle
            this._u && this._u.forEach((cb) = > cb())
          } else {
            // Set isMounted to true
            isMounted = true}})}connectedCallback() {
        // Mounted Life cycle
        this._m && this._m.forEach((cb) = > cb())
      }
      disconnectedCallback() {
        // unMounted Lifecycle
        this._um && this._um.forEach((cb) = > cb())
      }
      attributeChangedCallback(name, oldValue, newValue) {
        // This is triggered every time a parameter in propDefs is changed
        this._props[name] = newValue
      }
    }
  )
}

// Mount life cycle
function createLifecycleMethod(name) {
  return (cb) = > {
    if(currentInstance) { ; (currentInstance[name] || (currentInstance[name] = [])).push(cb) } } }// Export the life cycle
export const onBeforeMount = createLifecycleMethod('_bm')
export const onMounted = createLifecycleMethod('_m')
export const onBeforeUpdate = createLifecycleMethod('_bu')
export const onUpdated = createLifecycleMethod('_u')
export const onUnmounted = createLifecycleMethod('_um')

// Export all apis for lit-hteml and @vue/reactivity
export * from 'https://unpkg.com/lit-html?module'
export * from 'https://unpkg.com/@vue/reactivity/dist/reactivity.esm-browser.js'

Copy the code

A simplified version will help you understand

Taking a look at the overall picture, let’s simplify it a little bit for the sake of understanding without considering the life cycle:

import { render } from 'https://unpkg.com/lit-html?module'
import {
  shallowReactive,
  effect
} from 'https://unpkg.com/@vue/reactivity/dist/reactivity.esm-browser.js'

export function defineComponent(name, factory) {
  customElements.define(
    name,
    class extends HTMLElement {
      constructor() {
        super(a)const root = this.attachShadow({ mode: 'closed' })
        effect(() = > {
          render(factory(), root)
        })
      }
    }
  )
}
Copy the code

There are only a few processes:

  1. createWeb ComponentsCustom Elements
  2. To create aShadow DOMShadowRootnode
  3. Will the incomingfactoryAnd internally createdShadowRootThe node tolit-htmlrenderrenders

Back to your DEMO:

import {
  defineComponent,
  reactive,
  html,
} from 'https://unpkg.com/@vue/lit'

defineComponent('my-component'.() = > {
  const msg = 'Hello World'
  const state = reactive({
    show: true
  })
  const toggle = () = >{ state.show = ! state.show }return () = > html`
    <button @click=${toggle}>toggle child</button>
    ${state.show ? html`<my-child msg=${msg}></my-child>` : ` `}
  `
})
Copy the code

The my-component is the name passed in. The second function is the factory passed in as the first argument to lit-html, but it introduces the reactive ability of @vue/reactivity to make the state reactive.

Vue/Reactivity can be combined with lit-HTML, making Vue and Web Components work together.

Write in the last

Maybe Youda wrote this little toy on the spur of the moment, but it could be a real trend.

Guess it will be bundled for a burst of keywords in the near future: Unbundled/ES Modules/Web Components/Custom Elements/Shadow DOM…

Is it something to look forward to?

Thinking may also be relatively shallow, limited writing, shortcomings are welcome to point out.

recruitment

Alibaba International Team infrastructure Group recruitment front-end P6/P7, Base Hangzhou, infrastructure construction, business enablement… Lots of things can be done.

Familiar with engineering/Node/ React… Resume can be sent directly to [email protected].