English | [简体中文](./README.CN.md) | [한국어](./README.KR.md)

v5.0.11

omi

Omi - Next generation web framework using web components with omio fallback(IE9+) in 4kb JavaScript. Easy to MVVM.

## Why Omi? - Tiny size. _(**4kb** gzipped)_ - 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 - Supports TypeScript - Reactive data-binding - Enhanced CSS, [rpx unit support](https://github.com/Tencent/omi/releases/tag/v4.0.26) base on **750** screen width - [Based on Shadow DOM](https://developers.google.com/web/fundamentals/web-components/shadowdom) - 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)] - Compliance with browser trend and API design - Merge [**Web Components**](https://developers.google.com/web/fundamentals/web-components/) and [**JSX**](https://reactjs.org/docs/introducing-jsx.html) into one framework - Built in observe feature (No need to call `this.update()`) - 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) - 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 automatically update UI partially when data is changed - 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 - 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: | **Omi** | **React** | | ------------------------------- | ----------------------------------- | | ![Omi](./assets/omi-render.jpg) | ![React](./assets/react-render.jpg) | Omi uses Shadow DOM based style isolation and semantic structure. ## Ecosystem of Omi | **Project** | **Description** | | ------------------------------- | ----------------------------------- | | [omi-docs](https://github.com/Tencent/omi/blob/master/docs/main-concepts.md)| Omi official documents | | [omio![](https://raw.githubusercontent.com/dntzhang/cax/master/asset/hot.png) ](https://github.com/Tencent/omi/tree/master/packages/omio)| Omi for old browsers(IE9+ and mobile browsers).| | [omi-mvvm![](https://raw.githubusercontent.com/dntzhang/cax/master/asset/hot.png) ](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-chart![](https://raw.githubusercontent.com/dntzhang/cax/master/asset/hot.png) ](https://github.com/Tencent/omi/tree/master/packages/omi-chart)| Simple HTML5 Charts using chart-x tag.| | [omi-html](https://github.com/Tencent/omi/tree/master/packages/omi-html)| Using [htm](https://github.com/developit/htm) in omi.| | [omi-30-seconds![](https://raw.githubusercontent.com/dntzhang/cax/master/asset/hot.png) ](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.| | [omi-mp![](https://raw.githubusercontent.com/dntzhang/cax/master/asset/hot.png) ](https://github.com/Tencent/omi/tree/master/packages/omi-mp)| Develop and generate Web HTML5 Single-Page Applications by wechat mini program.| | [omi-router](https://github.com/Tencent/omi/tree/master/packages/omi-router) |Omi official router. [→ DEMO](https://tencent.github.io/omi/packages/omi-router/examples/spa/build/) | | [omi-devtools](https://github.com/f/omi-devtools)| Browser DevTools extension | | [omi-cli](https://github.com/Tencent/omi/tree/master/packages/omi-cli)| Project scaffolding | | [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-tap2](https://github.com/Tencent/omi/releases/tag/v4.0.24)| Native tap event support(omi v4.0.24+)| | [omi-tap](https://github.com/Tencent/omi/tree/master/packages/omi-tap)|Support tap event in your omi project| | [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-mobx](https://github.com/Tencent/omi/tree/master/packages/omi-mobx)|Omi Mobx Adapter| | [omi-use](https://github.com/Tencent/omi/blob/master/docs/main-concepts.md#use)|React hooks like API| | [omi-native](https://github.com/Tencent/omi/tree/master/packages/omi-native)|Render web components to native| | [omi-weui](https://github.com/Tencent/omi/tree/master/packages/omi-weui) |[Weui](https://weui.io/) for Omi by [@132yse](https://github.com/132yse).| |[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)| ## Useful Resources | **Title Name** | **Other language** | **Related**| | ----------------------------------------- | ------------------ |-----------------| |[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)| | [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/)|求翻译| |[ShadowRoot](https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot)|[简体中文](https://developer.mozilla.org/zh-CN/docs/Web/API/ShadowRoot)|| ## omi-mp > Develop and generate HTML5 SPA through Wechat Mini Programe. (The output source is base on omi + [omi-router](https://github.com/Tencent/omi/tree/master/packages/omi-router)) Conversion example of the official template: | **Index** | **Logs** | | ------------------------------- | ----------------------------------- | |![](./assets/mp1.jpg)| ![](./assets/mp2.jpg)| Because in the web cannot take the user login state, the user avatar and name are replaced. --- # Overview of the Readme - [Ecosystem of Omi](#ecosystem-of-omi) - [Useful Resources](#useful-resources) - [omi-mp](#omi-mp) - [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) - [Hello Element](#hello-element) - [TodoApp](#todoapp) - [Store](#store) - [Mitt](#mitt) - [Observe](#observe) - [Lifecycle](#lifecycle) - [Debugging](#debugging) - [React to Omi](#react-to-omi) - [Browsers Support](#browsers-support) - [Contributors](#contributors) - [Q & A](#q--a) - [Thanks](#thanks) - [License](#license) ## Add Omi in One Minute This page demonstrates using Omi **with no build tooling**. - [Online Demo!](https://tencent.github.io/omi/assets/) - [Omi.js CDN](https://unpkg.com/omi) ```html Add Omi in One Minute ``` You can also use `like-button` tag directly in HTML: ```jsx ``` ### Add Omi in 30 Seconds You can also quickly build omi projects using modern JS code: ```js import { render, WeElement, tag, observe } from "omi" @observe @tag("my-counter") class MyCounter extends WeElement { data = { count: 0 } sub = () => { this.data.count-- } add = () => { this.data.count++ } render() { return (
{this.data.count}
) } } render(, "body") ``` [→ counter demo](https://tencent.github.io/omi/packages/omi/examples/counter/) 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: ```js import { render, WeElement, define } from 'omi' define('my-counter', class extends WeElement { static observe = true data = { count: 1 } sub = () => { this.data.count-- } add = () => { this.data.count++ } render() { return (
{this.data.count}
) } }) render(, 'body') ``` You can also be defined as a form of pure functions: ```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}.` } }) this.useCss(`button{ color: red; }`) return (
{count}
) }) render(, 'body') ``` If you don't need effect, you can use `useData` directly: ```js const [count, setCount] = this.useData(0) ``` ## Getting Started ### Install ```bash $ npm i omi-cli -g # install cli $ omi init my-app # init project, you can also exec 'omi init' in an empty folder $ cd my-app # please ignore this command if you executed 'omi init' in an empty folder $ npm start # develop $ npm run build # release ``` > `npx omi-cli init my-app` is also supported(npm v5.2.0+). Directory description: ``` ├─ config ├─ public ├─ scripts ├─ src │ ├─ assets │ ├─ 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 ``` About compiled website URL: * [build env doc](https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#referencing-environment-variables-in-the-html) * [build problem](https://stackoverflow.com/questions/42686149/create-react-app-build-with-public-url) Such as in windows: ```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" } ``` In mac os: ```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" }, ``` If you only want to use relative addresses: ``` "build":"set PUBLIC_URL=.&& npm run _build" //windows "build":"PUBLIC_URL=. npm run _build", //mac os ``` ### Project Template | **Template Type**| **Command**| **Describe**| | ------------ | -----------| ----------------- | |Base Template|`omi init my-app`| Basic template for omi project.| |TypeScript Template(omi-cli v3.0.5+)|`omi init-ts my-app`|Basic template with typescript.| |[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.| |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.| CLI's auto-created project scaffolding 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) ### Hello Element Define a custom element by extending **`WeElement`** base class: ```js import { define, WeElement } from 'omi' define('hello-element', class 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 (
Hello {props.msg} {props.propFromParent}
Click Me!
) } }) ``` Using `hello-element`: ```js import { define, render, WeElement } from 'omi' import './hello-element' define('my-app', class extends WeElement { data = { abc: 'abc', passToChild: 123 } // define CustomEvent Handler onAbc = evt => { // get evt data by evt.detail this.data.abc = ' by ' + evt.detail.name this.data.passToChild = 1234 this.update() } css() { return ` div{ color: green; }` } render(props, data) { return (
Hello {props.name} {data.abc}
) } }) render(, 'body') ``` Tell Babel to transform JSX into `Omi.h()` call: ```json { "presets": ["env", "omi"] } ``` The following two NPM packages need to be installed to support the above configuration: ```bash "babel-preset-env": "^1.6.0", "babel-preset-omi": "^0.1.1", ``` If you use babel7, you can also use the following packages and configuration: ```bash npm install --save-dev @babel/preset-env npm install --save-dev @babel/preset-react ``` ```js { "presets": [ "@babel/preset-env", [ "@babel/preset-react", { "pragma": "Omi.h", } ] ] } ``` 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: ```js { test: /[\\|\/]_[\S]*\.css$/, use: [ 'to-string-loader', 'css-loader' ] } ``` If your CSS file starts with "`_`", CSS will use `to-string-loader`., such as: ```js 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 } ... ... ... ``` You can also forget the tedious configuration and use omi-cli directly, no need to configure anything. ### TodoApp Here is a relatively complete example of TodoApp: ```js import { define, render, WeElement } from 'omi' define('todo-list', function(props) { return (
    {props.items.map(item => (
  • {item.text}
  • ))}
) }) define('todo-app', class extends WeElement { static observe = true data = { items: [], text: '' } render() { return (

TODO

) } 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 = '' } }) render(, 'body') ``` ### Store Say goodbye to `this.update` method when using store system! It will automatically update the UI partially when data is changed. The powerful **Store architecture** is high-performanced since all the data is mounted on the store, except for components that rely on props to determine the state of the component. ```js export default { data: { items: [], text: "", firstName: "dnt", lastName: "zhang", fullName: function() { return this.firstName + this.lastName; }, 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. }, 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: ```js define('todo-app', class 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: ```js render(, "body", store); ``` [→ Store Source Code](https://github.com/Tencent/omi/blob/master/packages/omi/examples/store/main.js) #### Summary: - `store.data` is used to list all attributes and default values (except the components of the view decided by props). - The static data of the element 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 ## Mitt 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: * [cross-component-communication](https://github.com/Tencent/omi/blob/master/packages/omi-30-seconds/README.md#cross-component-communication) ## Observe ### Omi Observe You can also use observe to create response views for element who no need `store`, such as: ```js import { define, WeElement } from "omi" define("my-app", class extends WeElement { static observe = true install() { this.data.name = "omi" } onClick = () => { this.data.name = "Omi V4.0" } render(props, data) { return (

Welcome to {data.name}

) } }) ``` If you want to be compatible with IE11, please use the `omi-mobx` instead of omi's own observe. ### Omi Mobx ```js import { tag, WeElement } from "omi" import { observe } from "omi-mobx" @observe @tag("my-app") class MyApp extends WeElement { install() { this.data.name = "omi" } onClick = () => { this.data.name = "Omi V4.0" } render(props, data) { return (

Welcome to {data.name}

) } } ``` ### 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 update | | `afterUpdate` | after update (deprecated) | | `updated` | after update | | `beforeRender` | before `render()` | | `receiveProps` | parent element re-render will trigger it | ## Debugging Using [Omi DevTools](https://chrome.google.com/webstore/detail/omijs-devtools/pjgglfliglbhpcpalbpeloghnbceocmd) you can simply debug and manage your UI **without any configuration**. Just install and debug. Since Omi uses Web Components and Shadow-DOM, it doesn't need to have another elements panel such as React or Vue has. It just adds a panel to the **Elements' sidebar** and it's powerful as much as React and Vue DevTools. ![Omi DevTools](https://github.com/f/omi-devtools/raw/master/omi-devtools.gif) ## React to Omi For example, the below is about migration React button as weui Omi button: ![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) * [After](https://github.com/Tencent/omi/blob/9790fadaaf20cfede80bcf9213756a83fc8c3949/packages/omi-weui/src/omi-weui/elements/button/button.js) ## Browsers Support > [Omio](https://github.com/Tencent/omi/tree/master/packages/omio) - Omi for old browsers(IE9+ and mobile browsers) 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](./assets/browsers-support.png) [→ Polyfills](https://github.com/webcomponents/webcomponentsjs) ```html ``` > You can also give up the store system and use omi-mobx to be compatible with IE11. ## Contributors
## Q & A - [@f](https://github.com/f) - [@LeeHyungGeun](https://github.com/LeeHyungGeun) - [@dntzhang](https://github.com/dntzhang) - [@xcatliu](https://github.com/xcatliu) Please contact us for any questions. Also, Add [Omi QQ Group](https://github.com/Tencent/omi/issues/169). ## Thanks * [preact](https://github.com/developit/preact) * [JSONPatcherProxy](https://github.com/Palindrom/JSONPatcherProxy) * [create-react-app](https://github.com/facebook/create-react-app) * [JSX](https://github.com/facebook/jsx) ## License MIT © Tencent