<commit_before># Omi 多端开发之 - omip 适配 h5 原理揭秘

Omi 是腾讯开源的下一代前端框架，提供桌面、移动和小程序整体解决方案(One framework. Mobile & Desktop & Mini Program), Omip 是腾讯 Omi 团队开发的跨端开发工具集，支持小程序和 H5 SPA，最新的 omip 已经适配了 h5，如下方新增的两条命令：

```js
npm i omi-cli -g
omi init-p my-app
cd my-app
npm start        //开发小程序
npm run dev:h5   //开发 h5
npm run build:h5 //发布 h5
```

> node 版本要求 >= 8

> 也支持一条命令 `npx omi-cli init-p my-app` (npm v5.2.0+)

当然也支持 TypeScript:

```js
omi init-p-ts my-app
```

TypeScript 的其他命令和上面一样。

## 开发预览

![omip](https://github.com/Tencent/omi/raw/master/assets/omip-pv.png)

特性包括:

* 一次学习，多处开发，一次开发，多处运行
* 使用 JSX，表达能力和编程体验大于模板
* 支持使用 npm/yarn 安装管理第三方依赖
* 支持使用 ES6+,ES2015+,TypeScript
* 支持使用 CSS 预编译器
* 小程序 API 优化，异步 API Promise 化
* 超轻量的依赖包，顺从小程序标签和组件的设计

Omip 不仅可以一键生成小程序，还能一键生成 h5 SPA。怎么做到的？下面来一一列举难点，逐个击破。

## 问题列表

* CSS rpx 转换问题
* app.css 作用域问题
* JSX 里的小程序标签映射
* wx api 适配
* 集成路由

## CSS rpx 转换问题

小程序扩展尺寸单位 rpx（responsive pixel）: 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上，屏幕宽度为375px，共有750个物理像素，则750rpx = 375px = 750物理像素，1rpx = 0.5px = 1物理像素。

因为浏览器是不支持 rpx 单位，所以需要**运行时**转换，刚好 omi 内置了这个函数：

```js
function rpx(str) {
  return str.replace(/([1-9]\d*|0)(\.\d*)*rpx/g, (a, b) => {
    return (window.innerWidth * Number(b)) / 750 + 'px'
  })
}
```

## app.css 作用域问题

Shadow tree 与 omi 不一样，omi 是从根开始 shadow root，而小程序是从自定义组件开始，omio 则没有 shadow root。

| | **omi** | **omio** | **小程序**|
|-|-|-|
| Shadow DOM| 从根节点开始 | 无 |从自定义组件开始|
| Scoped CSS|  从根节点开始局部作用域，浏览器 scoped| 从根节点开始局部作用域(运行时 scoped)| 自定义组件局部作用域|

所以，app.css 需要污染到 page 里的 WXML/JSX，在 omi 中怎么做？

先看 app.js 源码：

```js
import './app.css' //注意这行！！！
import './pages/index/index'
import { render, WeElement, define } from 'omi'<commit_msg>update tutorial<commit_after># Omi 多端开发之 - omip 适配 h5 原理揭秘

Omi 是腾讯开源的下一代前端框架，提供桌面、移动和小程序整体解决方案(One framework. Mobile & Desktop & Mini Program), Omip 是腾讯 Omi 团队开发的跨端开发工具集，支持小程序和 H5 SPA，最新的 omip 已经适配了 h5，如下方新增的两条命令：

```js
npm i omi-cli -g
omi init-p my-app
cd my-app
npm start        //开发小程序
npm run dev:h5   //开发 h5
npm run build:h5 //发布 h5
```

> node 版本要求 >= 8

> 也支持一条命令 `npx omi-cli init-p my-app` (npm v5.2.0+)

当然也支持 TypeScript:

```js
omi init-p-ts my-app
```

TypeScript 的其他命令和上面一样。

## 开发预览

![omip](https://github.com/Tencent/omi/raw/master/assets/omip-pv.png)

特性包括:

* 一次学习，多处开发，一次开发，多处运行
* 使用 JSX，表达能力和编程体验大于模板
* 支持使用 npm/yarn 安装管理第三方依赖
* 支持使用 ES6+,ES2015+,TypeScript
* 支持使用 CSS 预编译器
* 小程序 API 优化，异步 API Promise 化
* 超轻量的依赖包，顺从小程序标签和组件的设计

Omip 不仅可以一键生成小程序，还能一键生成 h5 SPA。怎么做到的？下面来一一列举难点，逐个击破。

## 问题列表

* CSS rpx 转换问题
* app.css 作用域问题
* JSX 里的小程序标签映射
* wx api 适配
* 集成路由

## CSS rpx 转换问题

小程序扩展尺寸单位 rpx（responsive pixel）: 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上，屏幕宽度为375px，共有750个物理像素，则750rpx = 375px = 750物理像素，1rpx = 0.5px = 1物理像素。

因为浏览器是不支持 rpx 单位，所以需要**运行时**转换，刚好 omi 内置了这个函数：

```js
function rpx(str) {
  return str.replace(/([1-9]\d*|0)(\.\d*)*rpx/g, (a, b) => {
    return (window.innerWidth * Number(b)) / 750 + 'px'
  })
}
```

从 rpx 源码可以看到，需要运行时转换 rpx，而非编译时！因为只有运行时能拿到 屏幕宽度，omi 早期版本已经支持运行时的 rpx 转换：

```js
import { WeElement, define, rpx } from 'omi'

define('my-ele', class extends WeElement {

  static css = rpx(`div { font-size: 375rpx }`)

  render() {
    return (
      <div>my ele</div>
    )
  }
})
```

## app.css 作用域问题

Shadow tree 与 omi 不一样，omi 是从根开始 shadow root，而小程序是从自定义组件开始，omio 则没有 shadow root。

| | **omi** | **omio** | **小程序**|
|-|-|-|
| Shadow DOM| 从根节点开始 | 无 |从自定义组件开始|
| Scoped CSS|  从根节点开始局部作用域，浏览器 scoped| 从根节点开始局部作用域(运行时 scoped)| 自定义组件局部作用域|

所以，app.css 需要污染到 page 里的 WXML/JSX，在 omi 中怎么做？

先看 app.js 源码：

```js
import './app.css' //注意这行！！！
import './pages/index/index'
import { render, WeElement, define } from 'omi'
{'fraction_non_alphanumeric': 0.15556167400881057, 'fraction_numerical': 0.026156387665198236, 'mean_word_length': 3.9767123287671233, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 13, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2806502', 'n_tokens_mistral': 2350, 'n_tokens_neox': 2521, 'n_words': 390}