Coder Social home page Coder Social logo

haxine / omi Goto Github PK

View Code? Open in Web Editor NEW

This project forked from tencent/omi

0.0 2.0 0.0 6.94 MB

Next generation web framework in 4KB javascript(Webcomponents + JSX + Proxy + Path Updating)

Home Page: http://omijs.org

License: Other

HTML 2.33% JavaScript 97.67%

omi's Introduction

English | 简体中文

Omi

Next generation web framework in 4KB javascript(Merge JSX, Webcomponents, Proxy, Path Updating together).

omi

Why Omi?

  • Tiny size(4KB gzip)
  • Support TypeScript
  • Reactive data-binding
  • Compliance with browser trend and API design
  • Merge JSX and Webcomponents into One Framework
  • Webcomponents can also be a data-driven view, UI = fn(data)
  • JSX is the best development experience (code intelligent completion and tip) UI Expression with least grammatical noise
  • The original Path Updating system. Proxy-based automatic accurate update, low power consumption, high degree of freedom, excellent performance, easy integration of requestIdleCallback
  • Say goodbye to this.update method when using store system! It will update partial UI automatically when data changed.
  • Look at Facebook React VS Webcomponents,Omi combines their advantages and gives developers the freedom to choose the way they like.
  • Shadom DOM merges with Virtual DOM, Omi uses both virtual DOM and real Shadom DOM to make view updates more accurate and faster
  • With a Store system, 99.9% of projects don't need time travel, and not only Redux can travel, please don't come up on redux, Omi store system can meet all projects
  • Scoped CSS's best solution is Shadow DOM, the community churning out frameworks and libraries for Scoped CSS (using JS or JSON writing styles such as Radium, jsxstyle, react-style; binding to webpack using generated unique className `filename-classname-hash', such as CSS Modules, Vue), are hack technologies; and Shadow DOM Style is the perfect solution.

Compare TodoApp by Omi and React, Omi and React rendering DOM structure:

On the left is Omi, the right side is React, and Omi uses Shadow DOM isolation style and semantic structure.


Add Omi in One Minute

This page demonstrates using Omi with no build tooling.

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8" />
  <title>Add Omi in One Minute</title>
</head>

<body>
  <script src="https://unpkg.com/omi"></script>
  <script>
    const { WeElement, h, render, define } = Omi

    class LikeButton extends WeElement {
      install() {
        this.data = { liked: false }
      }

      render() {
        if (this.data.liked) {
          return 'You liked this.'
        }

        return h(
          'button',
          {
            onClick: () => {
              this.data.liked = true
              this.update()
            }
          },
          'Like'
        )
      }
    }

    define('like-button', LikeButton)

    render(h('like-button'), 'body')
  </script>
</body>

</html>

Getting Started

Install

$ npm i omi-cli -g               # install cli
$ omi init your_project_name     # init project, you can also exec 'omi init' in an empty folder
$ cd your_project_name           # please ignore this command if you executed 'omi init' in an empty folder
$ npm start                      # develop
$ npm run build                  # release

Hello Element

Define a custom element:

import { tag, WeElement, render } from 'omi'

@tag('hello-element')
class HelloElement extends WeElement {

    onClick = (evt) => {
        //trigger CustomEvent
        this.fire('abc', { name : 'dntzhang', age: 12 })
        evt.stopPropagation()
    }

    css() {
        return `
         div{
             color: red;
             cursor: pointer;
         }`
    }

    render(props) {
        return (
            <div onClick={this.onClick}>
                Hello {props.msg} {props.propFromParent}
                <div>Click Me!</div>
            </div>
        )
    }   
}

Using hello-element:

import { tag, WeElement, render } from 'omi'
import './hello-element'

@tag('my-app')
class MyApp extends WeElement {
    static get data() {
        return { abc: '', passToChild: '' }
    }

    //bind CustomEvent 
    onAbc = (evt) => {
        // get evt data by evt.detail
        this.data.abc = ' by ' + evt.detail.name
        this.update() 
    }

    css() {
        return `
         div{
             color: green;
         }`
    }

    render(props, data) {
        return (
            <div>
                Hello {props.name} {data.abc}
                <hello-element onAbc={this.onAbc} prop-from-parent={data.passToChild} msg="WeElement"></hello-element>
            </div>
        )
    }
}

render(<my-app name='Omi v4.0'></my-app>, 'body')

Tell Babel to transform JSX into Omi.h () call:

{
    "presets": ["env", "omi"]
}

The following two NPM packages need to be installed to support the above configuration:

"babel-preset-env": "^1.6.0",
"babel-preset-omi": "^0.1.1",

If you don't want to write CSS in js, you can use to-string-loader, For example, the following configuration:

{
    test: /[\\|\/]_[\S]*\.css$/,
    use: [
        'to-string-loader',
        'css-loader'
    ]
}

If your CSS file starts with "_", CSS will use to-string-loader., such as:

import { tag, WeElement render } from 'omi'
//typeof cssStr is string
import cssStr from './_index.css' 

@tag('my-app')
class MyApp extends WeElement {

  css() {
    return cssStr
  }
  ...
  ...
  ...

TodoApp

Here is a relatively complete example of TodoApp:

import { tag, WeElement, render } from 'omi'

@tag('todo-list')
class TodoList extends WeElement {
    render(props) {
        return (
            <ul>
                {props.items.map(item => (
                    <li key={item.id}>{item.text}</li>
                ))}
            </ul>
        );
    }
}

@tag('todo-app')
class TodoApp extends WeElement {
    static get data() {
        return { items: [], text: '' }
    }

    render() {
        return (
            <div>
                <h3>TODO</h3>
                <todo-list items={this.data.items} />
                <form onSubmit={this.handleSubmit}>
                    <input
                        id="new-todo"
                        onChange={this.handleChange}
                        value={this.data.text}
                    />
                    <button>
                        Add #{this.data.items.length + 1}
                    </button>
                </form>
            </div>
        );
    }

    handleChange = (e) => {
        this.data.text = e.target.value
    }

    handleSubmit = (e) => {
        e.preventDefault();
        if (!this.data.text.trim().length) {
            return;
        }
        this.data.items.push({
            text: this.data.text,
            id: Date.now()
        })
        this.data.text = ''
        this.update()
    }
}

render(<todo-app></todo-app>, 'body')

Store

Say goodbye to this.update method when using store system! It will update partial UI automatically when data changed. The powerful Store architecture is high-performance because all data is mounted on the store, except for components that rely on props to determine the state of the component.

export default {
  data: {
    items: [],
    text: '',
    firstName: 'dnt',
    lastName: 'zhang',
    fullName: function () {
      return this.firstName + this.lastName
    },
    globalPropTest: 'abc', //I will refresh all elements without changing the components and page declaring data dependency.
    ccc: { ddd: 1 } //I will refresh all elements without changing the components and page declaring data dependency.
  },
  globalData: ['globalPropTest', 'ccc.ddd'],
  add: function () {
    if (!this.data.text.trim().length) {
        return;
    }
    this.data.items.push({
      text: this.data.text,
      id: Date.now()
    })
    this.data.text = ''
  }
  //Default value is false, set to true will update all instances when data changing.
  //updateAll: true
}

Custom Element requires declaring dependent data so that Omi stores compute the dependency path based on the data declared on the custom component and update it locally as needed. Such as:

class TodoApp extends WeElement {
    //If you use store, the data is only used to declare dependencies.
    static get data() {
        return { items: [], text: '' }
    }
    ...
    ...
    ...
    handleChange = (e) => {
        this.store.data.text = e.target.value
    }

    handleSubmit = (e) => {
        e.preventDefault()
        this.store.add()
    }
}
  • the logic of data is encapsulated in the store definition method (such as store.add).
  • views are only responsible for passing data to store, such as calling store.add or setting store.data.text on top.

You need to inject store from the root node at render time to use this. store:

render(<todo-app></todo-app>, 'body', store)

→ Store Full Code

Summary:

  • store.data is used to list all attributes and default values (except the components of the view decided by props).
  • The data of the component and page is used to list the attributes of the dependent store.data (Omi will record path) and update on demand.
  • If there are few simple components on the page, updateAll can be set to true, and components and pages don't need to declare data, and they don't update on demand
  • The path declared in globalData refreshes all pages and components by modifying the value of the corresponding path, which can be used to list all pages or most of the public properties Path

Lifecycle

Lifecycle method When it gets called
install before the component gets mounted to the DOM
installed after the component gets mounted to the DOM
uninstall     prior to removal from the DOM                  
beforeUpdate before render()
afterUpdate after render()

Component Ecosystem

I believe you can easily convert webcomponents elements to omi elements.

Browsers Support

Omi 4.0+ works in the latest two versions of all major browsers: Safari 10+, IE 11+, and the evergreen Chrome, Firefox, and Edge.

Browsers Support

→ polyfills

Links

License

MIT © Tencent

Please contact me@dntzhang for any questions.

omi's People

Contributors

dntzhang avatar xcatliu avatar yanceyou avatar pasturn avatar xcodebuild avatar nobey avatar kahwee avatar xland avatar ritschwumm avatar winstonxie avatar zhangsanshi avatar

Watchers

James Cloos avatar 德古拉Dracula avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.