2019-03-29 15:01:45 +08:00
English | [简体中文 ](./README.CN.md ) | [한국어 ](./README.KR.md )
2018-10-20 10:59:36 +08:00
2019-04-30 10:20:12 +08:00
< p align = "right" > Omi < strong > v6.2.1< / strong > < / p >
2019-04-22 17:55:50 +08:00
< p align = "right" > Omio < strong > v2.2.1< / strong > < / p >
2019-04-21 11:28:10 +08:00
< p align = "center" > < img src = "https://tencent.github.io/omi/assets/omi-logo2019.svg" alt = "omi" width = "300" / > < / p >
2019-04-26 09:35:45 +08:00
< h2 align = "center" > Omi - Next front end framework using web components with omio(IE8+), omip(小程序) and reomi(react) fallback in tiny js.< / h2 >
2018-10-20 10:59:36 +08:00
2019-03-29 15:01:45 +08:00
## Ecosystem of Omi
2018-11-05 14:47:11 +08:00
2019-04-05 15:54:12 +08:00
#### Base
2019-04-05 15:47:55 +08:00
2019-03-29 15:01:45 +08:00
| **Project** | **Description** |
2018-11-05 14:47:11 +08:00
| ------------------------------- | ----------------------------------- |
2019-03-29 15:01:45 +08:00
| [omi-docs ](https://tencent.github.io/omi/site/docs/index.html )| Omi official documents |
2019-04-28 14:37:12 +08:00
| [omio![ ](https://raw.githubusercontent.com/dntzhang/cax/master/asset/hot.png ) ](https://github.com/Tencent/omi/tree/master/packages/omio)| Omi for old browsers with same api(IE8+ and mobile browsers)|
| [omis![ ](https://raw.githubusercontent.com/dntzhang/cax/master/asset/hot.png ) ](https://github.com/Tencent/omi/tree/master/packages/omis)| Server-side rendering(support omio only)|
| [omi-router ](https://github.com/Tencent/omi/tree/master/packages/omi-router ) |Omi official router in 1KB js|
2019-04-30 14:42:18 +08:00
| [omi-cli ](https://github.com/Tencent/omi/tree/master/packages/omi-cli )| Project scaffolding. [→ Base Templates ](https://github.com/Tencent/omi/tree/master/packages/omi-cli/template ) and [→ Other Templates ](https://github.com/omijs ) |
2019-04-05 15:47:55 +08:00
| [omi-devtools ](https://github.com/f/omi-devtools )| Browser DevTools extension |
| [omiu ](https://tencent.github.io/omi/packages/omiu/examples/build/index.html )| Omi official UI|
2019-04-29 10:18:18 +08:00
|[omil](https://github.com/Wscats/omil)|Webpack loader for Omi.js components|
2019-04-05 15:47:55 +08:00
2019-04-05 15:54:12 +08:00
#### Mini Program
2019-04-05 15:47:55 +08:00
| **Project** | **Description** |
| ------------------------------- | ----------------------------------- |
2019-04-08 11:51:25 +08:00
| [omi-cloud![ ](https://raw.githubusercontent.com/dntzhang/cax/master/asset/hot.png ) ](https://github.com/Tencent/omi/tree/master/packages/omi-cloud)| 小程序•云开发|
2019-04-05 15:53:49 +08:00
| [omip![ ](https://raw.githubusercontent.com/dntzhang/cax/master/asset/hot.png ) ](https://github.com/Tencent/omi/tree/master/packages/omip)| 直接使用 Omi 开发小程序或 H5 SPA|
2019-04-09 16:36:19 +08:00
| [mps![ ](https://raw.githubusercontent.com/dntzhang/cax/master/asset/hot.png ) ](https://github.com/Tencent/omi/tree/master/packages/mps)| 原生小程序增强框架(JSX + Less 输出 WXML + WXSS),也支持 QQ 轻应用 |
2019-04-17 21:43:12 +08:00
| [cax![ ](https://raw.githubusercontent.com/dntzhang/cax/master/asset/hot.png )](https://github.com/Tencent/omi/tree/master/packages/cax)| 小程序 Canvas 和 SVG 渲染引擎 |
2019-04-17 14:23:20 +08:00
| [omix ](https://github.com/Tencent/omi/tree/master/packages/omix )| 极小却精巧的小程序框架|
2019-04-05 15:53:49 +08:00
| [omi-mp ](https://github.com/Tencent/omi/tree/master/packages/omi-mp )| 通过微信小程序开发和生成 Web 单页应用(H5 SPA)|
2019-04-05 15:47:55 +08:00
| [comi ](https://github.com/Tencent/omi/tree/master/packages/comi )| 小程序代码高亮和 markdown 渲染组件 |
2019-04-05 17:00:22 +08:00
| [wx-touch-event ](https://github.com/qbright/wx-touch-event )| 基于 AlloyFinger/omi-finger 改造的小程序手势解决方案 |
2019-04-05 15:47:55 +08:00
2019-04-05 15:54:12 +08:00
#### Other
2019-04-05 15:47:55 +08:00
| **Project** | **Description** |
| ------------------------------- | ----------------------------------- |
2019-03-29 15:01:45 +08:00
| [omi-chart ](https://github.com/Tencent/omi/tree/master/packages/omi-chart )| Simple HTML5 Charts using chart-x tag.|
| [md2site ](https://tencent.github.io/omi/assets/md2site/ )| Static Site Generator with markdown powered by Omio.|
| [omi-mvvm ](https://github.com/Tencent/omi/blob/master/tutorial/omi-mvvm.md )| MVVM comes back bravely with [mappingjs ](https://github.com/Tencent/omi/tree/master/packages/mappingjs ) strong support.|
| [omi-30-seconds ](https://github.com/Tencent/omi/tree/master/packages/omi-30-seconds )| Useful Omi snippets that you can understand in 30 seconds.|
| [omi-canvas ](https://github.com/Tencent/omi/tree/master/packages/omi-canvas )| Perfect fusion of web components, jsx and canvas.|
2019-02-26 20:19:16 +08:00
| [omi-swiper ](https://github.com/loo41/Omi-Swiper )| Omi + Swiper |
2019-03-05 14:14:36 +08:00
| [omi-vscode ](https://github.com/ZainChen/omi-vscode )| Vscode extension for omi, [Install now! ](https://marketplace.visualstudio.com/items?itemName=ZainChen.omi ) |
2019-03-29 15:01:45 +08:00
| [omi-ex ](https://github.com/Tencent/omi/tree/master/packages/omi-ex )| Omi.js extension(TypeScript) |
| [omi-transform ](https://github.com/Tencent/omi/tree/master/packages/omi-transform )|Omi / [css3transform ](https://tencent.github.io/omi/packages/omi-transform/css3transform/ ) integration. Made css3 transform super easy in your Omi project.|
| [omi-tap ](https://github.com/Tencent/omi/releases/tag/v4.0.24 )| Native tap event support(omi v4.0.24+) |
| [omi-finger ](https://github.com/Tencent/omi/tree/master/packages/omi-finger )|Support touch and gesture events in your Omi project.|
| [omi-touch ](https://github.com/Tencent/omi/tree/master/packages/omi-touch )|Smooth scrolling, rotation, pull to refresh and any motion for the web.|
| [omi-native ](https://github.com/Tencent/omi/tree/master/packages/omi-native )|Render web components to native|
|[omi-i18n](https://github.com/i18next/omi-i18n)| Internationalization solution for omi.js using i18next ecosystem |
| [omi-page ](https://github.com/Tencent/omi/tree/master/packages/omi-page ) |Tiny client-side router by [page ](https://github.com/visionmedia/page.js )|
## Why Omi?
- One framework. Mobile & desktop & mini program.
- Tiny size
- Supports TypeScript
- Reactive data-binding
- Having official UI components - [omiu ](https://tencent.github.io/omi/packages/omiu/examples/build/index.html )
- Excellent compatibility(IE8+) with [omio ](https://github.com/Tencent/omi/tree/master/packages/omio )
2019-04-26 09:35:45 +08:00
- Supporting both grammars of omi and react with [reomi ](https://github.com/Tencent/omi/tree/master/packages/reomi )
2019-03-29 15:01:45 +08:00
- Real [MVVM ](https://github.com/Tencent/omi/blob/master/tutorial/omi-mvvm.md ) with [mappingjs ](https://github.com/Tencent/omi/tree/master/packages/mappingjs ) strong support
- Enhanced CSS, [rpx unit support ](https://github.com/Tencent/omi/releases/tag/v4.0.26 ) base on **750** screen width
- Compliance with browser trend and API design
2019-04-30 11:33:16 +08:00
- Merge [**Web Components** ](https://developers.google.com/web/fundamentals/web-components/ ), [**JSX** ](https://reactjs.org/docs/introducing-jsx.html ) and [**HTM** ](https://github.com/developit/htm ) into one framework
2019-03-29 15:01:45 +08:00
- Web Components 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 ](https://github.com/facebook/jsx#why-not-template-literals ) and it's turing complete(template engine is not, es template string is but grammatical noise is too loud)
- Look at [Facebook React vs Web Components ](https://softwareengineering.stackexchange.com/questions/225400/pros-and-cons-of-facebooks-react-vs-web-components-polymer ), Omi **combines their advantages** and gives developers the **freedom to choose the way they like**
- **Shadow DOM merges with Virtual DOM**, Omi uses both virtual DOM and real Shadow DOM to make view updates more accurate and faster
- **Scoped CSS**'s best solution is [**Shadow DOM** ](https://developers.google.com/web/fundamentals/web-components/shadowdom ), 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_ .
- The original **Path Updating** **store system** . Proxy-based automatic **accurate** update, **low power consumption** , high degree of freedom, excellent performance, easy integration of `requestIdleCallback` ,It will automatically update UI partially when data is changed
Compare TodoApp by Omi and React, Omi and React rendering DOM structure:
| **Omi** | **React** |
| ------------------------------- | ----------------------------------- |
2019-04-21 11:31:41 +08:00
| ![Omi ](https://tencent.github.io/omi/assets/omi-render.jpg ) | ![React ](https://tencent.github.io/omi/assets/react-render.jpg ) |
2019-02-26 15:49:06 +08:00
2019-03-29 15:01:45 +08:00
Omi uses Shadow DOM based style isolation and semantic structure.
2019-04-22 17:50:12 +08:00
### TypeScript Auto Complete
```jsx
import { h, WeElement, tag, classNames } from 'omi';
2019-04-23 09:34:26 +08:00
import * as styles from './_index.less';
interface ButtonProps {
href?: string,
disabled?: boolean,
type?: 'default' | 'primary' | 'danger',
htmltype?: 'submit' | 'button' | 'reset',
onClick?: (e: any) => void
}
const TAG = 'o-button'
2019-04-22 17:50:12 +08:00
declare global {
namespace JSX {
interface IntrinsicElements {
2019-04-30 10:09:41 +08:00
[TAG]: Omi.Props & ButtonProps
2019-04-22 17:50:12 +08:00
}
}
}
2019-04-23 09:34:26 +08:00
@tag (TAG)
export default class oButton extends WeElement< ButtonProps , { } > {
...
2019-04-22 17:50:12 +08:00
...
...
```
2019-04-23 09:40:15 +08:00
< img src = "./assets/ts.png" alt = "omi" width = "427" / >
2019-04-22 17:50:12 +08:00
2019-03-29 15:01:45 +08:00
## Useful Resources
| **Title Name** | **Other language** | **Related** |
| ----------------------------------------- | ------------------ |-----------------|
|[Styling We Components Using A Shared Style Sheet](https://www.smashingmagazine.com/2016/12/styling-web-components-using-a-shared-style-sheet/)|
|[Developer Tools support for Web Components in Firefox 63](https://blog.nightly.mozilla.org/2018/09/06/developer-tools-support-for-web-components-in-firefox-63/)||
|[Develop W3C Web Components with WebAssembly](https://medium.com/coinmonks/develop-w3c-web-components-with-webassembly-d65938284255)||
| [60FPS Animation In Omi ](https://github.com/Tencent/omi/blob/master/tutorial/omi-transform.md )| [简体中文 ](https://github.com/Tencent/omi/blob/master/tutorial/omi-transform.cn.md ) [한국어 ](https://github.com/Tencent/omi/blob/master/tutorial/omi-transform.kr.md )|
| [Render Web Components To Native ](https://github.com/Tencent/omi/blob/master/tutorial/render-web-components-to-native.md )|[简体中文](https://github.com/Tencent/omi/blob/master/tutorial/render-web-components-to-native.cn.md) [한국어 ](https://github.com/Tencent/omi/blob/master/tutorial/render-web-components-to-native.kr.md )|
| [Shadow Dom In Depth ](https://github.com/praveenpuglia/shadow-dom-in-depth )| [简体中文 ](https://github.com/Tencent/omi/blob/master/tutorial/shadow-dom-in-depth.cn.md )|
| [Part Theme Explainer ](https://meowni.ca/posts/part-theme-explainer/ )|求翻译|
| [Web Components MDN ](https://developer.mozilla.org/en-US/docs/Web/Web_Components )| [简体中文 ](https://developer.mozilla.org/zh-CN/docs/Web/Web_Components )|
| [Web Components Google ](https://developers.google.com/web/fundamentals/web-components/ )|
| [Web Components Org ](https://www.webcomponents.org/introduction )|
| [Web Components: the Right Way ](https://github.com/mateusortiz/webcomponents-the-right-way )|
| [Proxy MDN ](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy )|[简体中文](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy) [한국어 ](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Proxy )|
| [CSS Variables ](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables )|[简体中文](https://developer.mozilla.org/zh-CN/docs/Web/CSS/Using_CSS_variables) [한국어 ](https://developer.mozilla.org/ko-KR/docs/Web/CSS/Using_CSS_variables )|
| [CSS Shadow Parts ](https://drafts.csswg.org/css-shadow-parts-1/ )|
| [Platform HTML5 ](https://platform.html5.org/ )|
| [Using requestIdleCallback ](https://developers.google.com/web/updates/2015/08/using-requestidlecallback )|[简体中文](https://div.io/topic/1370)| [A polyfill ](https://gist.github.com/paullewis/55efe5d6f05434a96c36 )|
| [The Power Of Web Components ](https://hacks.mozilla.org/2018/11/the-power-of-web-components/ )|[简体中文](https://github.com/Tencent/omi/blob/master/tutorial/the-power-of-web-components.cn.md)|
|[ShadowRoot](https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot)|[简体中文](https://developer.mozilla.org/zh-CN/docs/Web/API/ShadowRoot)||
# Overview of the Readme
- [Ecosystem of Omi ](#ecosystem-of-omi )
- [Useful Resources ](#useful-resources )
- [Add Omi in One Minute ](#add-omi-in-one-minute )
- [Add Omi in 30 Seconds ](#add-omi-in-30-seconds )
- [Getting Started ](#getting-started )
- [Install ](#install )
- [Project Template ](#project-template )
2018-10-25 21:30:18 +08:00
- [Hello Element ](#hello-element )
- [TodoApp ](#todoapp )
- [Store ](#store )
2019-03-29 15:01:45 +08:00
- [Lifecycle ](#lifecycle )
- [Debugging ](#debugging )
- [Browsers Support ](#browsers-support )
- [Contributors ](#contributors )
- [Maintainers ](#maintainers )
- [Thanks ](#thanks )
2018-10-20 11:14:19 +08:00
- [License ](#license )
2018-10-20 10:59:36 +08:00
2019-03-29 15:01:45 +08:00
## Add Omi in One Minute
2018-10-20 10:59:36 +08:00
2019-04-21 11:47:54 +08:00
This page demonstrates using Omi **with no build tooling** , directly run in the browser.
2018-10-20 10:59:36 +08:00
2019-04-21 11:47:54 +08:00
- [→ Online Demo! ](https://tencent.github.io/omi/packages/omi/examples/no-transpiler/ )
2018-10-20 10:59:36 +08:00
```html
<!DOCTYPE html>
< html >
< head >
2019-04-21 11:50:04 +08:00
< title > Omi demo without transpiler< / title >
2018-10-20 10:59:36 +08:00
< / head >
< body >
2019-04-21 11:50:04 +08:00
< script src = "https://tencent.github.io/omi/packages/omi/dist/omi.js" > < / script >
< script >
const { define, WeElement, html, render } = Omi
define('my-counter', class extends WeElement {
install() {
this.data.count = 1
this.sub = this.sub.bind(this)
this.add = this.add.bind(this)
}
sub() {
this.data.count--
this.update()
}
add() {
this.data.count++
this.update()
}
render() {
return html`
< div >
< button onClick = ${this.sub} > -< / button >
< span > ${this.data.count}< / span >
< button onClick = ${this.add} > +< / button >
< / div >
`}
})
render(html`< my-counter / > `, 'body')
< / script >
2018-10-20 10:59:36 +08:00
< / body >
< / html >
```
2019-04-21 11:52:30 +08:00
### Using store system
```html
<!DOCTYPE html>
< html >
< head >
< meta charset = "UTF-8" / >
< title > Omi demo without transpiler< / title >
< / head >
< body >
< script src = "https://tencent.github.io/omi/packages/omi/dist/omi.js" > < / script >
< script >
const { define, WeElement, html, render } = Omi
define('my-counter', class extends WeElement {
initUse() {
return ['count']
}
install() {
this.sub = this.sub.bind(this)
this.add = this.add.bind(this)
}
sub() {
this.store.data.count--
}
add() {
this.store.data.count++
}
render() {
return html`
< div >
< button onClick = ${this.sub} > -< / button >
< span > ${this.store.data.count}< / span >
< button onClick = ${this.add} > +< / button >
< / div >
`}
})
render(html`< my-counter / > `, 'body', {
data: {
count: 1
}
})
< / script >
< / body >
< / html >
```
2019-03-29 15:01:45 +08:00
You can also use `like-button` tag directly in HTML:
2018-10-20 10:59:36 +08:00
```jsx
< body >
2019-03-29 15:01:45 +08:00
< like-button / >
2018-10-20 10:59:36 +08:00
< / body >
```
2019-03-29 15:01:45 +08:00
### Add Omi in 30 Seconds
2019-03-25 18:21:31 +08:00
2019-03-29 15:01:45 +08:00
You can also quickly build omi projects using modern JS code:
<!--
```js
2018-10-29 09:20:52 +08:00
import { render, WeElement, tag, observe } from "omi"
@observe
@tag ("my-counter")
2018-10-30 06:13:12 +08:00
class MyCounter extends WeElement {
2018-10-29 09:20:52 +08:00
2018-10-29 21:25:46 +08:00
data = {
count: 0
}
2018-10-29 09:20:52 +08:00
sub = () => {
this.data.count--
}
add = () => {
this.data.count++
}
render() {
return (
< div >
< button onClick = {this.sub} > -< / button >
< span > {this.data.count}< / span >
< button onClick = {this.add} > +< / button >
< / div >
)
}
}
render(< my-counter / > , "body")
2019-03-29 15:01:45 +08:00
``` -->
<!--
You will find that the `MyCounter` class name defined above is never used. So you can also use the following way to avoid Eslint hints: -->
2018-10-30 06:13:12 +08:00
```js
2018-10-30 06:39:32 +08:00
import { render, WeElement, define } from 'omi'
2018-10-30 06:13:12 +08:00
2019-01-09 15:55:09 +08:00
define('my-counter', class extends WeElement {
2019-02-26 20:15:34 +08:00
data = {
count: 1
}
2019-01-09 15:55:09 +08:00
2019-03-04 10:21:59 +08:00
static css = `
span{
2019-01-15 11:41:00 +08:00
color: red;
2019-03-04 10:21:59 +08:00
}`
2019-01-15 11:41:00 +08:00
2019-01-09 15:55:09 +08:00
sub = () => {
2019-02-26 20:15:34 +08:00
this.data.count--
2019-01-09 15:55:09 +08:00
this.update()
}
add = () => {
2019-02-26 20:15:34 +08:00
this.data.count++
2019-01-09 15:55:09 +08:00
this.update()
}
render() {
return (
< div >
< button onClick = {this.sub} > -< / button >
2019-02-26 20:15:34 +08:00
< span > {this.data.count}< / span >
2019-01-09 15:55:09 +08:00
< button onClick = {this.add} > +< / button >
< / div >
)
}
})
render(< my-counter / > , 'body')
```
[→ counter demo ](https://tencent.github.io/omi/packages/omi/examples/counter/ )
2019-03-29 15:01:45 +08:00
<!-- You can also be defined as a form of pure functions:
2018-10-31 17:39:18 +08:00
```js
import { define, render } from 'omi'
define('my-counter', function() {
const [count, setCount] = this.use({
data: 0,
effect: function() {
document.title = `The num is ${this.data}.`
}
})
2018-11-03 21:17:28 +08:00
this.useCss(`button{ color: red; }`)
2018-10-31 17:39:18 +08:00
return (
< div >
< button onClick = {() = > setCount(count - 1)}>-< / button >
< span > {count}< / span >
< button onClick = {() = > setCount(count + 1)}>+< / button >
< / div >
)
})
render(< my-counter / > , 'body')
```
2019-03-29 15:01:45 +08:00
If you don't need effect, you can use `useData` directly:
2018-10-31 19:44:01 +08:00
```js
const [count, setCount] = this.useData(0)
2018-12-28 09:27:50 +08:00
``` -->
2018-10-31 19:44:01 +08:00
2019-03-29 15:01:45 +08:00
## Getting Started
2018-10-20 10:59:36 +08:00
2019-03-29 15:01:45 +08:00
### Install
2018-10-20 10:59:36 +08:00
```bash
2019-04-22 10:12:50 +08:00
$ npm i omi-cli -g # install cli
$ omi init my-app # init project
$ cd my-app
$ npm start # develop
$ npm run build # release
2018-10-20 10:59:36 +08:00
```
2019-03-29 15:01:45 +08:00
> `npx omi-cli init my-app` is also supported(npm v5.2.0+).
2018-11-21 22:43:27 +08:00
2019-03-29 15:01:45 +08:00
Directory description:
2018-10-20 10:59:36 +08:00
```
├─ config
├─ public
├─ scripts
├─ src
│ ├─ assets
2019-03-29 15:01:45 +08:00
│ ├─ elements //Store all custom elements
│ ├─ store //Store all this store of pages
│ ├─ admin.js //Entry js of compiler, will build to admin.html
│ └─ index.js //Entry js of compiler, will build to index.html
2018-10-20 10:59:36 +08:00
```
2019-01-08 11:57:08 +08:00
#### Scripts
2019-01-08 11:54:56 +08:00
```json
"scripts": {
"start": "node scripts/start.js",
"build": "PUBLIC_URL=. node scripts/build.js",
"build-windows": "set PUBLIC_URL=.& & node scripts/build.js",
"fix": "eslint src --fix"
}
```
2019-03-29 15:01:45 +08:00
You can set up the PUBLIC_URL, such as:
2019-01-08 11:54:56 +08:00
```json
...
"build": "PUBLIC_URL=https://fe.wxpay.oa.com/dv node scripts/build.js",
"build-windows": "set PUBLIC_URL=https://fe.wxpay.oa.com/dv& & node scripts/build.js",
...
```
2019-01-15 14:36:37 +08:00
2019-04-26 09:35:45 +08:00
#### Switch omi, omio and reomi
2019-01-15 14:36:37 +08:00
2019-03-29 15:01:45 +08:00
Add or remove the alias config in package.json to switch omi and omio:
2019-01-15 14:36:37 +08:00
```js
2019-04-25 11:33:05 +08:00
"alias": {
"omi": "omio"
}
```
2019-04-26 09:35:45 +08:00
Using reomi:
2019-04-25 11:33:05 +08:00
```js
"alias": {
2019-04-26 09:35:45 +08:00
"omi": "reomi",
"react": "reomi",
"react-dom": "reomi"
2019-04-25 11:33:05 +08:00
}
2019-01-15 14:36:37 +08:00
```
2019-01-08 11:54:56 +08:00
2019-03-29 15:01:45 +08:00
<!-- About compiled website URL:
2018-10-29 11:55:16 +08:00
2019-03-25 18:21:31 +08:00
* [build env doc ](https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#referencing-environment-variables-in-the-html )
2019-03-29 15:01:45 +08:00
* [build problem ](https://stackoverflow.com/questions/42686149/create-react-app-build-with-public-url )
2018-10-29 11:55:16 +08:00
2019-03-29 15:01:45 +08:00
Such as in windows:
2018-10-29 11:55:16 +08:00
```json
"scripts": {
"start": "node scripts/start.js",
"_build": "node scripts/build.js",
"build":"set PUBLIC_URL=https://fe.wxpay.oa.com/dv& & npm run _build"
}
```
2019-03-29 15:01:45 +08:00
In mac os:
2018-11-06 22:37:08 +08:00
```json
"scripts": {
"start": "node scripts/start.js",
"_build": "node scripts/build.js",
"build":"PUBLIC_URL=https://fe.wxpay.oa.com/dv npm run _build",
"fix": "eslint src --fix"
},
```
2019-03-29 15:01:45 +08:00
If you only want to use relative addresses:
2018-12-13 15:47:26 +08:00
```
"build":"set PUBLIC_URL=.& & npm run _build" //windows
"build":"PUBLIC_URL=. npm run _build", //mac os
2019-01-08 11:54:56 +08:00
``` -->
2018-12-13 15:47:26 +08:00
2019-03-29 15:01:45 +08:00
### Project Template
2018-10-24 02:04:13 +08:00
2018-11-25 21:33:52 +08:00
| **Template Type** | **Command** | **Describe** |
2018-11-25 21:22:54 +08:00
| ------------ | -----------| ----------------- |
2019-03-29 15:01:45 +08:00
|Base Template(v3.3.0+)|`omi init my-app`| Basic omi or omio(IE8+) project template.|
|Base Template with snapshoot|`omi init-snap my-app`| Basic omi or omio(IE8+) project template with snapshoot prerendering.|
|TypeScript Template(omi-cli v3.3.0+)|`omi init-ts my-app`|Basic template with typescript.|
|Mobile Template|`omi init-weui my-app`| Mobile web app template with weui and omi-router.|
|omi-mp Template(omi-cli v3.0.13+)|`omi init-mp my-app` |Developing web with mini program template.|
|MVVM Template(omi-cli v3.0.22+)|`omi init-mvvm my-app` |MVVM template.|
<!-- |[SPA Template](https://tencent.github.io/omi/packages/omi - router/examples/spa/build/)(omi - cli v3.0.10+)|`omi init - spa my - app`|Single page application template with omi - router.| -->
2019-04-02 17:11:04 +08:00
The base Template(`omi init my-app`) is based on a single-page create-react-app to be converted into a multi-page one, with configuration issues to see [create-react-app user guide ](https://facebook.github.io/create-react-app/docs/getting-started )
2018-10-20 10:59:36 +08:00
### Hello Element
2019-03-29 15:01:45 +08:00
Define a custom element by extending ** `WeElement` ** base class:
2018-10-20 10:59:36 +08:00
```js
2018-10-30 09:08:59 +08:00
import { define, WeElement } from 'omi'
2018-10-20 10:59:36 +08:00
2018-10-30 09:08:59 +08:00
define('hello-element', class extends WeElement {
2018-10-25 21:30:18 +08:00
onClick = evt => {
// trigger CustomEvent
2018-10-30 09:08:59 +08:00
this.fire('abc', { name: 'dntzhang', age: 12 })
evt.stopPropagation()
}
2018-10-25 21:30:18 +08:00
2019-03-29 15:01:45 +08:00
static css = `
2019-01-15 11:41:00 +08:00
div {
color: red;
cursor: pointer;
}`
2018-10-25 21:30:18 +08:00
render(props) {
return (
< div onClick = {this.onClick} >
Hello {props.msg} {props.propFromParent}
< div > Click Me!< / div >
< / div >
2018-10-30 09:08:59 +08:00
)
2018-10-25 21:30:18 +08:00
}
2018-10-30 09:08:59 +08:00
})
2018-10-20 10:59:36 +08:00
```
2019-03-29 15:01:45 +08:00
Using `hello-element` :
2018-10-20 10:59:36 +08:00
2018-10-22 03:50:09 +08:00
```js
2018-10-30 09:08:59 +08:00
import { define, render, WeElement } from 'omi'
import './hello-element'
2018-10-20 10:59:36 +08:00
2018-10-30 09:08:59 +08:00
define('my-app', class extends WeElement {
data = { abc: 'abc', passToChild: 123 }
2018-10-25 21:30:18 +08:00
2018-10-30 09:08:59 +08:00
// define CustomEvent Handler
2018-10-25 21:30:18 +08:00
onAbc = evt => {
// get evt data by evt.detail
2018-10-30 09:08:59 +08:00
this.data.abc = ' by ' + evt.detail.name
this.data.passToChild = 1234
this.update()
}
2018-10-25 21:30:18 +08:00
2019-01-15 11:41:00 +08:00
css = `
div{
color: green;
}`
2018-10-25 21:30:18 +08:00
}
render(props, data) {
return (
< div >
Hello {props.name} {data.abc}
< hello-element
onAbc={this.onAbc}
2018-12-05 09:10:38 +08:00
propFromParent={data.passToChild}
2018-10-25 21:30:18 +08:00
msg="WeElement"
/>
< / div >
2018-10-30 09:08:59 +08:00
)
2018-10-25 21:30:18 +08:00
}
2018-10-30 09:08:59 +08:00
})
2018-10-20 10:59:36 +08:00
2018-10-30 09:08:59 +08:00
render(< my-app name = "Omi v4.0" / > , 'body')
2018-10-20 10:59:36 +08:00
```
2019-03-29 15:01:45 +08:00
Tell Babel to transform JSX into `Omi.h()` call:
2018-10-20 10:59:36 +08:00
2019-03-29 15:01:45 +08:00
```json
2018-10-20 10:59:36 +08:00
{
2019-03-29 15:01:45 +08:00
"presets": ["env", "omi"]
2018-10-20 10:59:36 +08:00
}
```
2019-03-29 15:01:45 +08:00
The following two NPM packages need to be installed to support the above configuration:
2018-10-20 10:59:36 +08:00
2019-03-29 15:01:45 +08:00
```bash
2018-10-20 10:59:36 +08:00
"babel-preset-env": "^1.6.0",
"babel-preset-omi": "^0.1.1",
```
2019-03-29 15:01:45 +08:00
If you use babel7, you can also use the following packages and configuration:
2018-10-27 16:08:24 +08:00
```bash
npm install --save-dev @babel/preset -env
npm install --save-dev @babel/preset -react
```
```js
{
"presets": [
"@babel/preset-env",
[
"@babel/preset-react",
{
2019-01-07 10:08:11 +08:00
"pragma": "Omi.h"
2018-10-27 16:08:24 +08:00
}
]
]
}
```
2019-03-29 15:01:45 +08:00
If you don't want to write CSS in JS, you can use [to-string-loader ](https://www.npmjs.com/package/to-string-loader ) of webpack,
For example, the following configuration:
2018-10-20 10:59:36 +08:00
2019-03-29 15:01:45 +08:00
```js
2018-10-20 10:59:36 +08:00
{
2019-03-29 15:01:45 +08:00
test: /[\\|\/]_[\S]*\.css$/,
use: [
'to-string-loader',
'css-loader'
]
2018-10-20 10:59:36 +08:00
}
```
2019-03-29 15:01:45 +08:00
If your CSS file starts with "`_`", CSS will use `to-string-loader` ., such as:
2018-10-20 10:59:36 +08:00
2019-01-15 11:41:00 +08:00
``` js
2018-10-20 10:59:36 +08:00
import { tag, WeElement render } from 'omi'
2019-01-15 11:41:00 +08:00
define('my-app', class extends WeElement {
2018-10-20 10:59:36 +08:00
2019-01-15 11:41:00 +08:00
css = require('./_index.css')
2018-10-20 10:59:36 +08:00
...
...
...
```
2019-03-29 15:01:45 +08:00
You can also forget the tedious configuration and use omi-cli directly, no need to configure anything.
2018-10-27 16:12:05 +08:00
2018-10-20 10:59:36 +08:00
### TodoApp
2019-03-29 15:01:45 +08:00
Here is a relatively complete example of TodoApp:
2018-10-20 10:59:36 +08:00
```js
2018-11-03 06:49:36 +08:00
import { define, render, WeElement } from 'omi'
2018-10-20 10:59:36 +08:00
2018-11-03 06:49:36 +08:00
define('todo-list', function(props) {
return (
< ul >
{props.items.map(item => (
< li key = {item.id} > {item.text}< / li >
))}
< / ul >
)
2018-10-30 06:42:07 +08:00
})
define('todo-app', class extends WeElement {
2018-10-30 07:01:01 +08:00
static observe = true
2018-11-03 06:49:36 +08:00
data = { items: [], text: '' }
2018-10-30 07:01:01 +08:00
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 = ''
}
2018-10-30 06:42:07 +08:00
})
render(< todo-app / > , 'body')
2018-10-20 10:59:36 +08:00
```
### Store
2019-03-29 15:01:45 +08:00
Omi Store provides a way to pass data through the component tree without having to pass props down manually at every level, injected from the root component and shared across all subcomponents. It's very simple to use:
2019-01-11 09:02:26 +08:00
```js
import { define, render, WeElement } from 'omi'
define('my-hello', class extends WeElement {
render() {
2019-03-29 15:01:45 +08:00
//use this.store in any method of any children components
2019-01-11 09:02:26 +08:00
return < div > {this.store.name}< / div >
}
})
define('my-app', class extends WeElement {
handleClick = () => {
2019-03-29 15:01:45 +08:00
//use this.store in any method of any children components
2019-01-11 09:02:26 +08:00
this.store.reverse()
this.update()
}
render() {
return (
< div >
< my-hello / >
2019-01-11 09:28:44 +08:00
< button onclick = {this.handleClick} > reverse< / button >
2019-01-11 09:02:26 +08:00
< / div >
)
}
})
const store = {
name: 'abc',
reverse: function() {
this.name = this.name.split("").reverse().join("")
}
}
2019-03-29 15:01:45 +08:00
//Injection through a third parameter
2019-01-11 09:02:26 +08:00
render(< my-app / > , document.body, store)
```
2019-03-29 15:01:45 +08:00
Unlike global variables, when there are multiple root nodes, multiple stores can be injected, while there is only one global variable.
2019-01-11 09:02:26 +08:00
2019-03-29 15:01:45 +08:00
<!-- It will automatically update the UI partially when store.data is changed. The powerful **Store architecture** is high-performanced since all the data is mounted on the store.
2018-10-20 10:59:36 +08:00
```js
export default {
2018-10-25 21:30:18 +08:00
data: {
items: [],
2019-03-29 15:01:45 +08:00
text: "",
firstName: "dnt",
lastName: "zhang",
fullName: function() {
return this.firstName + this.lastName;
2018-10-25 21:30:18 +08:00
},
2019-03-29 15:01:45 +08:00
globalPropTest: "abc", // Change it will refresh all elements without changing the components and page declaring data dependency.
ccc: { ddd: 1 } // Change it will refresh all elements without changing the components and page declaring data dependency.
2018-10-25 21:30:18 +08:00
},
2019-03-29 15:01:45 +08:00
globalData: ["globalPropTest", "ccc.ddd"],
add: function() {
2018-10-25 21:30:18 +08:00
if (!this.data.text.trim().length) {
2019-03-29 15:01:45 +08:00
return;
2018-10-25 21:30:18 +08:00
}
this.data.items.push({
text: this.data.text,
id: Date.now()
2019-03-29 15:01:45 +08:00
});
this.data.text = "";
2018-10-25 21:30:18 +08:00
}
2019-03-29 15:01:45 +08:00
// Default value is false, set to true will update all instances when data changing.
// updateAll: true
};
2018-10-20 10:59:36 +08:00
```
2019-03-29 15:01:45 +08:00
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:
2018-10-20 10:59:36 +08:00
```js
2018-10-30 09:15:43 +08:00
define('todo-app', class extends WeElement {
2019-03-29 15:01:45 +08:00
// 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;
};
2018-10-25 21:30:18 +08:00
2019-03-29 15:01:45 +08:00
handleSubmit = e => {
e.preventDefault();
this.store.add();
};
2018-10-30 09:15:43 +08:00
})
2018-10-20 10:59:36 +08:00
```
2019-03-29 15:01:45 +08:00
- 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.
2018-10-20 10:59:36 +08:00
2019-03-29 15:01:45 +08:00
You need to inject `store` from the root node at render time to use this store:
2018-10-20 10:59:36 +08:00
```js
2019-03-29 15:01:45 +08:00
render(< todo-app / > , "body", store);
2018-10-20 10:59:36 +08:00
```
2019-03-29 15:01:45 +08:00
[→ Store Source Code ](https://github.com/Tencent/omi/blob/master/packages/omi/examples/store/main.js ) -->
2018-10-20 10:59:36 +08:00
2019-03-25 16:59:37 +08:00
<!--
2018-11-21 09:19:12 +08:00
## Mitt
2019-03-29 15:01:45 +08:00
If you don't want to use store's data system, you can also use publish subscribe mode. For example, using [mitt ](https://github.com/developit/mitt ) across component communication in Omi:
2018-11-21 09:19:12 +08:00
2019-03-25 16:59:37 +08:00
* [cross-component-communication ](https://github.com/Tencent/omi/blob/master/packages/omi-30-seconds/README.md#cross-component-communication ) -->
2018-11-21 09:19:12 +08:00
2018-12-24 09:47:09 +08:00
<!--
2019-03-29 15:01:45 +08:00
If you want to be compatible with IE11, please use the `omi-mobx` instead of omi's own observe.
2018-10-21 17:19:49 +08:00
2018-10-28 08:19:56 +08:00
### Omi Mobx
2018-10-21 17:19:49 +08:00
```js
2018-10-28 08:19:56 +08:00
import { tag, WeElement } from "omi"
import { observe } from "omi-mobx"
2018-10-21 17:19:49 +08:00
@observe
2018-10-22 03:50:09 +08:00
@tag ("my-app")
2018-10-21 17:19:49 +08:00
class MyApp extends WeElement {
2018-10-25 21:30:18 +08:00
install() {
2018-10-28 08:19:56 +08:00
this.data.name = "omi"
2018-10-25 21:30:18 +08:00
}
onClick = () => {
2018-10-28 08:19:56 +08:00
this.data.name = "Omi V4.0"
}
2018-10-25 21:30:18 +08:00
render(props, data) {
return (
< div onClick = {this.onClick} >
< h1 > Welcome to {data.name}< / h1 >
< / div >
2018-10-28 08:19:56 +08:00
)
2018-10-25 21:30:18 +08:00
}
2018-10-21 17:19:49 +08:00
}
2018-12-24 09:47:09 +08:00
``` -->
2018-10-21 17:19:49 +08:00
2019-03-29 15:01:45 +08:00
### Lifecycle
2018-10-28 08:19:56 +08:00
| 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 update |
2018-11-25 21:13:16 +08:00
| `updated` | after update |
2018-10-28 08:19:56 +08:00
| `beforeRender` | before `render()` |
2018-11-20 19:09:19 +08:00
| `receiveProps` | parent element re-render will trigger it |
2018-10-28 08:19:56 +08:00
2019-03-29 15:01:45 +08:00
## Debugging
2018-10-28 08:19:56 +08:00
2019-03-29 15:01:45 +08:00
Easy to debug via [Omi DevTools Extension ](https://github.com/f/omi-devtools ) [[Install from Chrome WebStore ](https://chrome.google.com/webstore/detail/omijs-devtools/pjgglfliglbhpcpalbpeloghnbceocmd )], using Omi DevTools you can simply debug and manage your UI **without any configuration** . Just install and debug.
2018-10-28 08:19:56 +08:00
2019-03-29 15:01:45 +08:00
Since Omi uses Web Components and Shadow-DOM, it doesn't need to have another elements panel such as React has. It just adds a panel to the **Elements' sidebar** and it's powerful as much as React DevTools.
2018-10-28 08:19:56 +08:00
![Omi DevTools ](https://github.com/f/omi-devtools/raw/master/omi-devtools.gif )
2019-03-25 16:58:16 +08:00
<!--
2019-03-29 15:01:45 +08:00
## React to Omi
2018-11-05 13:14:43 +08:00
2019-03-29 15:01:45 +08:00
For example, the below is about migration React button as weui Omi button:
2018-11-05 13:14:43 +08:00
![react to omi ](./assets/react-to-omi.png )
* [Diff Split ](https://github.com/Tencent/omi/commit/9790fadaaf20cfede80bcf9213756a83fc8c3949?diff=split )
* [Diff Unified ](https://github.com/Tencent/omi/commit/9790fadaaf20cfede80bcf9213756a83fc8c3949?diff=unified )
* [Before ](https://github.com/Tencent/omi/blob/c8af654f1d5865dc557c0b4b8ad524f702a69be5/packages/omi-weui/src/omi-weui/elements/button/button.js )
2019-03-25 16:58:16 +08:00
* [After ](https://github.com/Tencent/omi/blob/9790fadaaf20cfede80bcf9213756a83fc8c3949/packages/omi-weui/src/omi-weui/elements/button/button.js ) -->
2018-11-05 13:14:43 +08:00
2019-03-29 15:01:45 +08:00
## Browsers Support
2018-10-20 10:59:36 +08:00
2019-03-29 15:01:45 +08:00
> [Omio](https://github.com/Tencent/omi/tree/master/packages/omio) - Omi for old browsers(IE8+ and mobile browsers)
2018-12-13 16:15:47 +08:00
2018-10-20 10:59:36 +08:00
Omi 4.0+ works in the latest two versions of all major browsers: Safari 10+, IE 11+, and the evergreen Chrome, Firefox, and Edge.
2018-10-23 06:47:28 +08:00
![→ Browsers Support ](./assets/browsers-support.png )
2018-10-20 10:59:36 +08:00
2019-03-29 15:01:45 +08:00
[→ Polyfills ](https://github.com/webcomponents/webcomponentsjs )
2018-10-20 10:59:36 +08:00
2018-12-11 14:56:28 +08:00
```html
< script src = "https://unpkg.com/@webcomponents/webcomponentsjs@2.0.0/webcomponents-bundle.js" > < / script >
```
2019-03-29 15:01:45 +08:00
## Contributors
2018-11-26 17:42:55 +08:00
< table > < tbody >
2019-04-29 10:23:15 +08:00
< tr > < td > < a target = "_blank" href = "https://github.com/dntzhang" > < img width = "60px" src = "https://avatars2.githubusercontent.com/u/7917954?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/LeeHyungGeun" > < img width = "60px" src = "https://avatars2.githubusercontent.com/u/2471651?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/xcatliu" > < img width = "60px" src = "https://avatars1.githubusercontent.com/u/5453359?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/1921622004" > < img width = "60px" src = "https://avatars1.githubusercontent.com/u/19359217?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/yanceyou" > < img width = "60px" src = "https://avatars2.githubusercontent.com/u/16320418?s=60&v=4" > < / a > < / td > < / tr > < tr > < td > < a target = "_blank" href = "https://github.com/f" > < img width = "60px" src = "https://avatars0.githubusercontent.com/u/196477?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/pasturn" > < img width = "60px" src = "https://avatars0.githubusercontent.com/u/6126885?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/132yse" > < img width = "60px" src = "https://avatars3.githubusercontent.com/u/12951461?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/akira-cn" > < img width = "60px" src = "https://avatars0.githubusercontent.com/u/316498?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/ZainChen" > < img width = "60px" src = "https://avatars3.githubusercontent.com/u/15615524?s=60&v=4" > < / a > < / td > < / tr > < tr > < td > < a target = "_blank" href = "https://github.com/dangxuandev" > < img width = "60px" src = "https://avatars1.githubusercontent.com/u/5436704?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/daizhan" > < img width = "60px" src = "https://avatars0.githubusercontent.com/u/5318547?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/validalias" > < img width = "60px" src = "https://avatars1.githubusercontent.com/u/44221844?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/elfman" > < img width = "60px" src = "https://avatars3.githubusercontent.com/u/948001?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/NoBey" > < img width = "60px" src = "https://avatars3.githubusercontent.com/u/10740524?s=60&v=4" > < / a > < / td > < / tr > < tr > < td > < a target = "_blank" href = "https://github.com/hilkbahar" > < img width = "60px" src = "https://avatars2.githubusercontent.com/u/12161006?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/eyea" > < img width = "60px" src = "https://avatars0.githubusercontent.com/u/17020223?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/guisturdy" > < img width = "60px" src = "https://avatars1.githubusercontent.com/u/7098619?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/KidneyFlower" > < img width = "60px" src = "https://avatars1.githubusercontent.com/u/16027183?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/zhangsanshi" > < img width = "60px" src = "https://avatars1.githubusercontent.com/u/3771933?s=60&v=4" > < / a > < / td > < / tr > < tr > < td > < a target = "_blank" href = "https://github.com/xland" > < img width = "60px" src = "https://avatars0.githubusercontent.com/u/2980915?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/winstonxie" > < img width = "60px" src = "https://avatars3.githubusercontent.com/u/16422642?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/ghostzhang" > < img width = "60px" src = "https://avatars3.githubusercontent.com/u/194242?s=60&v=4" > < / a > < / td >
2019-04-29 10:26:21 +08:00
< td > < a target = "_blank" href = "https://github.com/jayZOU" > < img width = "60px" src = "https://avatars3.githubusercontent.com/u/8576977?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/zhengbao" > < img width = "60px" src = "https://avatars3.githubusercontent.com/u/1736166?s=60&v=4" > < / a > < / td > < / tr > < tr > < td > < a target = "_blank" href = "https://github.com/vorshen" > < img width = "60px" src = "https://avatars3.githubusercontent.com/u/10334783?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/akira-cn" > < img width = "60px" src = "https://avatars3.githubusercontent.com/u/316498?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/loo41" > < img width = "60px" src = "https://avatars3.githubusercontent.com/u/28095677?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/rainmanhhh" > < img width = "60px" src = "https://avatars3.githubusercontent.com/u/13862623?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/nbompetsis" > < img width = "60px" src = "https://avatars3.githubusercontent.com/u/11991105?s=60&v=4" > < / a > < / td > < / tr > < tr > < td > < a target = "_blank" href = "https://github.com/CodeFalling" > < img width = "60px" src = "https://avatars1.githubusercontent.com/u/5436704?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/daizhan" > < img width = "60px" src = "https://avatars0.githubusercontent.com/u/5318547?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/ritschwumm" > < img width = "60px" src = "https://avatars2.githubusercontent.com/u/547138?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/kahwee" > < img width = "60px" src = "https://avatars3.githubusercontent.com/u/262105?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/alanyinjs" > < img width = "60px" src = "https://avatars3.githubusercontent.com/u/25688258?s=60&v=4" > < / a > < / td > < / tr > < tr > < td > < a target = "_blank" href = "https://github.com/electerious" > < img width = "60px" src = "https://avatars2.githubusercontent.com/u/499088?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/nanhupatar" > < img width = "60px" src = "https://avatars1.githubusercontent.com/u/27266016?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/ilker0" > < img width = "60px" src = "https://avatars1.githubusercontent.com/u/23511412?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/MrGrabazu" > < img width = "60px" src = "https://avatars2.githubusercontent.com/u/6928672?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/Tagir-A" > < img width = "60px" src = "https://avatars2.githubusercontent.com/u/23556586?s=60&v=4" > < / a > < / td > < / tr > < tr > < td > < a target = "_blank" href = "https://github.com/mahmut-gundogdu" > < img width = "60px" src = "https://avatars2.githubusercontent.com/u/2217899?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/howel52" > < img width = "60px" src = "https://avatars3.githubusercontent.com/u/9854818?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/yolio2003" > < img width = "60px" src = "https://avatars1.githubusercontent.com/u/352931?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/loo41" > < img width = "60px" src = "https://avatars3.githubusercontent.com/u/28095677?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/nbompetsis" > < img width = "60px" src = "https://avatars1.githubusercontent.com/u/11991105?s=60&v=4" > < / a > < / td > < / tr > < tr > < td > < a target = "_blank" href = "https://github.com/WozHuang" > < img width = "60px" src = "https://avatars2.githubusercontent.com/u/22727100?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/web-padawan" > < img width = "60px" src = "https://avatars2.githubusercontent.com/u/10589913?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/SuperHuangXu" > < img width = "60px" src = "https://avatars1.githubusercontent.com/u/14816052?s=60&v=4" > < / a > < / td > < td > < a target = "_blank" href = "https://github.com/LastHeaven" > < img width = "60px" src = "https://avatars1.githubusercontent.com/u/10590077?s=60&v=4" > < / a > < / td >
< td > < a target = "_blank" href = "https://github.com/Wscats" > < img width = "60px" src = "https://avatars3.githubusercontent.com/u/17243165?s=60&v=4" > < / a > < / td > < / tr > < / tbody > < / table >
2018-11-26 17:42:55 +08:00
2019-03-29 15:01:45 +08:00
## Maintainers
2018-10-20 10:59:36 +08:00
2018-10-22 03:50:09 +08:00
- [@f ](https://github.com/f )
2018-11-01 10:43:37 +08:00
- [@LeeHyungGeun ](https://github.com/LeeHyungGeun )
2018-10-22 03:50:09 +08:00
- [@dntzhang ](https://github.com/dntzhang )
2018-10-25 11:38:56 +08:00
- [@xcatliu ](https://github.com/xcatliu )
2018-10-20 10:59:36 +08:00
2019-03-29 15:01:45 +08:00
Please contact us for any questions. Also, Add [Omi QQ Group ](https://github.com/Tencent/omi/issues/169 ).
2018-11-10 14:44:23 +08:00
2019-03-29 15:01:45 +08:00
## Thanks
2018-10-29 14:58:04 +08:00
* [preact ](https://github.com/developit/preact )
2019-04-28 14:35:22 +08:00
* [htm ](https://github.com/developit/htm )
2018-11-12 15:53:48 +08:00
* [create-react-app ](https://github.com/facebook/create-react-app )
* [JSX ](https://github.com/facebook/jsx )
2019-04-25 11:13:29 +08:00
* [JSONPatcherProxy ](https://github.com/Palindrom/JSONPatcherProxy )
2018-10-29 14:58:04 +08:00
2018-10-20 10:59:36 +08:00
## License
MIT © Tencent