使用新一代js模板引擎NornJ提高React.js開發體驗

當前的前端世界中有不少著名的開源javascript模板引擎HandlebarsNunjucksEJS等等,相信不少人對它們都並不陌生。javascript

js模板引擎的現狀

一般來說,這些js模板引擎項目都有一個共同的特性:只專一渲染字符串(html)html

早在幾年前Backbone等mv*框架流行的時候,js模板引擎遇到了它們的春天,由於Backbone能夠支持選配用戶本身喜愛的模板,並提供了接入方案。可是在新一代前端mv*框架盛行的今天,人們更多的關注點在於React的JSX支持的邏輯何等地強大、Vue的v-show等指令使用起來多麼地方便,而js模板引擎呢?它們彷佛只能在Node.js服務器端找到它們的歸宿,並且還被React及Vue的SSR(服務端渲染)繼續蠶食着僅有的市場。前端

爲何各類各樣的js模板引擎都只專一於渲染html字符串?這或許跟歷史緣由有關,畢竟五、6年前的時候並無虛擬dom,使用jQuery等框架的$('div').html(str)方法渲染dom是理所固然的事情。vue

新型js模板引擎

咱們不妨試想一下,其實js模板引擎在當前的時代只要也能作到渲染虛擬dom對象,或許就能夠再次找到它們被重用的機會:java

+---------------------+
         ¦ <Template string /> ¦
         +---------------------+
                    |
                    |
         +---------------------+
         |      render to      |
         |                     |
  +-------------+    +-------------------+
  ¦ html string ¦    ¦ React virtual dom ¦
  +-------------+    +-------------------+

然而目前有一個新的js模板引擎能夠作到上述的同時支持渲染html和React組件,它就是NornJreact

github:https://github.com/joe-sky/nornj
官方文檔(github pages):https://joe-sky.github.io/nornj-guide/
官方文檔(gitbook):https://joe-sky.gitbooks.io/nornj-guide/webpack

安裝

npm install nornj
npm install nornj-react   # React開發請一塊兒安裝此包
npm install nornj-loader  # webpack環境請一塊兒安裝此包

在線演示地址

渲染html字符串

渲染React組件

在React開發中的基本使用方法

React在介紹本身時常說JSX是"可選的",但實際上,脫離了JSX的React根本就幾乎沒法正常地開發。若是有了另外一種DSL(js模板引擎)可適配React開發,那麼JSX才能真正地成爲可選的技術。git

NornJ的模板語法在參考自HandlebarsNunjucksVue等多個著名項目的基礎上,也有不少本身獨特的語法如tagged template string自定義語句與運算符等等,與html+js很是類似可快速上手。須要提一下另外一個React的模板項目react-templates,它是React生態中惟一一個比較完善的模板項目,但很惋惜的是它如今已經幾乎不維護了,並且功能很是有限。github

每一個React組件都需要在render返回組件的標籤代碼,如在HelloWorld組件中渲染一個下拉框,用JSXNornJ的語法分別實現:web

  • JSX
export default class HelloWorld extends Component {
  render() {
    return (
      <div className="hello" style={{ width: 300, height: 200 }}>
        <input type="text" />
        <select>
          {[1, 2, 3].map((item, i) => i > 1
            ? <option>{item + 1}</option>
            : <option>{item}</option>
          )}
        </select>
      </div>
    );
  }
}
  • NornJ
import { template as t } from 'nornj';
import 'nornj-react';
import { Input } from 'antd';

export default class HelloWorld extends Component {
  render() {
    return t`
      <div class="hello" style="width:300px;height:200px;">
        <input type="text">
        <select>
          <#each {1 .. 3}>
            <#if {@index > 1}>
              <option>{@item + 1}</option>
              <#else><option>{@item}</option></#else>
            </#if>
          </#each>
        </select>
      </div>
      <${Input} placeholder="Basic usage" />
    `;
  }
}

如上例,這就是NornJ最基本的使用方法了,開箱即用。它可使用ES6+tagged template literals語法在js文件中描述模板,模板語法在處理邏輯時的結構比JSX更加易讀,且語法和html更爲接近:

  • 能夠寫class替代className。
  • style可使用html中寫style屬性的方式,固然寫對象也一樣支持。
  • 模板語法提供了#if#each等擴展標籤用於處理邏輯,可替代三目運算符數組map方法
  • input和img等標籤支持只寫開標籤,如<input type="text">,JSX中必定要寫爲<input type="text" />
  • 可直接在組件的render中返回同一級別的多個標籤,外面不用套上數組。
  • 雙花括號{{}}和單花括{}號語法在React開發中都支持,除特殊場景外依我的喜愛而定。
  • 模板和JSX同樣支持嵌入任意js變量,這固然也包含第三方React組件和JSX變量,NornJ模板和JSX是能夠共存的!

NornJtagged template literals語法更多細節請查看官方文檔

上面的例子也能夠這樣改寫:

import nj from 'nornj';
import 'nornj-react';
import { Input } from 'antd';

const tmplFn = nj`
  <div class="hello" style="width:300px;height:200px;">
  ...
  </div>
  <${Input} placeholder="Basic usage" />
`;

export default class HelloWorld extends Component {
  render() {
    return tmplFn();
  }
}

能夠看出,實質上tagged template literals語法就是建立了一個模板函數,而後再在render中執行了而已。這時不難想到,使用第一種方法將模板函數放到render中執行,這樣會不會每次執行render時都進行模板編譯(內部涉及各類正則析取)會形成性能降低?並不會,由於NornJ模板在編譯時會進行緩存,只有第一次render時會進行模板編譯,以後的每次render就會走緩存了。

另外,NornJJSX還能夠嵌套編寫,僅僅在很小的粒度使用NornJ模板也徹底沒有問題,具體請見官方文檔

單文件模板

NornJ模板除了能夠在js文件中編寫以外,還能夠編寫在單獨的模板文件中,用來作組件(或頁面)展示層與結構層的分離(具體請參考官方文檔)。例如編寫一個helloWorld.nj.html文件:

<template name="partial">
  <ant-Input placeholder="Basic usage" value={value} />
</template>

<template name="helloWorld">
  <div class={styles.hello}>
    <select>
      <#each {1 .. 3}>
        <#if {@index > 1}>
          <option>{@item + 1}</option>
          <#else><option>{@item}</option></#else>
        </#if>
      </#each>
    </select>
  </div>
  <#include name="partial" />
</template>

而後能夠在js文件中引入後使用:

import tmpls from './helloWorld.nj.html';

export default class HelloWorld extends Component {
  state = {
    value: 'test'
  };

  render() {
    return tmpls.helloWorld(this.state, this.props);
  }
}

如上,每一個*.nj.html文件內均可以定義一個或多個template標籤。這些template標籤會在引用它的js文件中經過nornj-loader進行解析,生成一個以template標籤的name屬性爲key的模板函數集合對象,在各個組件的render中調用它們就會生成相應的React vdom對象。

針對NornJ單文件模板,咱們也提供了一些IDE的語法高亮與提示工具

擴展模板

NornJHandlebars比較相似具備很是強大的可擴展性,#if#each等實際上都是擴展出來的語法,您徹底能夠本身擴展出#customIf#customEach等新語句。在可擴展性這一點上,不難想到JSX也能夠經過babel進行擴展,也能夠搞新的語法出來,例如jsx-control-statements。可是babel擴展上手門檻不低,要學各類babel AST的用法,開發一個完美的插件出來彷佛並不是易事。

因爲NornJ繼承於Handlebars的擴展方式,它內部的每一個擴展均可以用一個函數簡單地開發出來,例如爲NornJ擴展一個**運算符,做用是乘方運算:

import nj from 'nornj';

nj.registerFilter('**', (val1, val2) => Math.pow(val1, val2));

而後就能夠直接使用了:

<input value="{ 2 ** 10 / 100 }">

固然上述只是個最簡單的例子,更多模板擴展描述請參考官方文檔

結合Mobx建立雙向數據綁定

利用NornJ的可擴展性,模板語法在理論上能夠實現無限的可能性。#mobx-modelNornJ實現的一個行內擴展標籤(相似於vue及ng的指令),具體用法以下:

import { Component } from 'react';
import { observable } from 'mobx';
import nj from 'nornj';
import 'nornj-react';
import 'nornj-react/mobx';

class TestComponent extends Component {
  @observable inputValue = '';

  render() {
    return nj`<input :#mobx-model="inputValue">`(this);
  }
}

#mobx-model的底層實現方式和Vue的v-model是比較相似的。React也有其餘雙向綁定的實現如Mota,但該項目的實現方式是經過高階組件。利用NornJ的擴展語法,咱們還能實現更多相似於#mobx-model的擴展功能。

結合React的各類生態

NornJ能夠完美結合各類React生態,包括React-NativeReduxReact-RouterMobxAnt Design等等,它能夠和任何已有的React生態共存。

更多詳細文檔請見官方文檔

適配各類React-Like庫

NornJ在理論上能夠適配任意React-Like庫,包括PreactinfernoanuNerv等。

具體適配方式請見官方文檔

渲染html字符串

NornJ同時還支持渲染html字符串,這和傳統的js模板引擎就徹底同樣了。使用方法和React中幾乎徹底同樣,具體請看這個在線實例:

固然,NornJ也可以支持Node.js服務器ExpressKoa等。傳統js模板的compilerender等方法,NornJ也支持。

更多細節請見官方文檔

NornJ的將來計劃

NornJ在將來咱們還有不少能夠加強的方面,例如:

  • 開發eslint插件

NornJ目前雖然內部有語法錯誤警告機制,但只是將錯誤打印在控制檯。對於靜態語法錯誤檢測,NornJ未來有必要開發一個eslint插件。

  • 性能持續優化

雖然NornJ目前的模板渲染效率已然不低(請見模板渲染效率測試),但仍尚有很大的優化空間,會持續進行優化工做。

  • 國際化

  • 對Vue提供適配

NornJ適配Vue暫時是個設想,理論上是能夠實現的。但有幾個難題:

  1. Vue使用的虛擬dom對象結構並不是React那樣簡單,它使用相似snabbdom的結構,其中的事件等方法都綁在特殊的對象上。這對NornJ來講適配起來和React比有必定難度。
  2. Vue的模板語法已然很好用,雖然NornJ能夠提供一些自身獨特的語法,可是提高開發體驗的做用恐怕沒有在React中那樣明顯。

NornJ發展到今天已經擁有了不少強大的功能,往後還會繼續完善,歡迎試用。

相關文章
相關標籤/搜索