基於React開發範式的思考:寫在Lesx發佈之際

例子:lesx-example
webpack loader: lesx-loaderjavascript

一些背景

如今前端框架已經呈現出React、Angular、Vue三足鼎立的局勢,對於三者的對比以及技術選型的思考與爭論也被討論了很是多,好比知乎上的這個問題:react.js,angular.js,vue.js學習哪一個好?,對於這個問題咱們再也不作過多贅述。但無論怎麼樣,如今github上star數最多、npm上安裝量最大的仍是React,阿里巴巴不少團隊的技術棧也是基於React的。此篇文章也是基於React的開發範式來進行討論的。 css

JSX的模板範式沒有選擇HTML模板,而是徹底基於JS的,同時提供了一種JSX的語法糖,方便用戶的開發。這樣作是有幾種考慮的,首先React是跨平臺跨終端的,不只能夠在Web browser中運行,還能夠基於RN在移動端APP、服務端基於SSR來運行,基於虛擬DOM的實現讓他能夠輕鬆地作到以上幾點,另外,徹底基於JS的開發能夠不用掌握相似Vue/angular的指令式的語法,而是更多的偏向於使用純js的語法開發範式,一次學習終身受益,而不用每次在開發的過程當中還要去查看API文檔。 html

可是,React的這種開發模式也帶來了一個額外的問題,就是jQuery時代尊崇的UI與邏輯分離的最佳實踐在JSX時代又有了極大的後退。因而咱們一直在思考,能不能有一種模式,既能享受像Vue那樣UI、展現(樣式)與邏輯分離,方便維護與可擴展,又能享受React JSX的語法帶來的便利呢?前端

Lesx的誕生

基於上面的思考,因而有了Lesx這個構建式的框架vue

構建式的框架並非咱們的獨創,可是這個概念不知道是否是咱們第一次正式提出來。業界已經有的AOT(Ahead Of Time)、非侵入式的框架比較知名的是svelte,他的開發範式跟Lesx比較類似,可是他並非基於React或者哪一個框架的,而是本身研發了一套底層組件機制,對於模板代碼的解析也是基於本身實現的一套AST解析實現,語法相似於Handlebars。基於React的開發範式跟Lesx比較類似的仍是react-templates,他稱本身是:Lightweight templates for React。他只是把React Class的render部分抽了出來,DSL會被編譯成React.createElement,而後生成一個函數做爲React Class的render方法。同時,react-templates裏還增添了不少相似vue的指令的功能,好比:rt-ifrt-repeat等,這樣的框架的問題就是問題解決的並非很完全,抽出render部分的同時,咱們仍是須要對React建立部分須要大量的代碼書寫;同時,對於JSX語法擴展指令的模式增添了開發者的學習成本,後面開發中也須要不斷地去查看文檔如何使用這些指令,這是咱們極不推崇的。 java

在這樣的背景下,我花了兩天時間,早起晚睡、憋屎憋尿的完成了基於React作到UI、展現(樣式)與邏輯分離的構建式開發框架:Lesx的第一版。react

基於Lesx的開發模式

Lesx做爲webpack的loader存在,使用相似Vue的單文件的開發範式,方便開發者的代碼組織與開發: webpack

index.lesx:ios

<style>
    a {
        color: red;
    }
</style>

<template>
    <div>
        <a onClick={this.func}>點我</a>

        {console.log(this.props)}

        <If condition={ this.props.valid }>
            <div>{this.state.name}</div>
        </If>

        <Button type="primary" onClick={() => {
            alert('I am an antd button!');
            $setState({
                name: 'new name'
            });
        }}>antd button</Button>

        <My />
    </div>
</template>

<script>
    module.exports = {
        props: {
            valid: true
        },

        state: {
            name: 'xiangzhong.wxz'
        },

        func({
            setState,
        }) {
            alert('I am a function!');

            setState({
                name: 'new name'
            });
        }
    };
</script>

很明顯的,他有幾個特色:git

UI、樣式與邏輯分離

lesx文件有style/template/script三個標籤,內部分別存放他們對應的內容代碼。

style部分咱們默認使用跟css徹底兼容同時有更多便利性語法的Sass語言,後面立刻也會支持Less語法。

tenplate部分則徹底是React的jsx語法,同時由如下幾個擴展:

  • 咱們基於babel插件jsx-control-statements提供了便利性的控制流標籤,好比:IfFor等等,語法很是簡單,一次學習終生高效!固然,有的同窗可能會不承認這種標籤擴展控制流的模式,此時你也能夠繼續使用你熟悉的三元運算符、數組map等方式來實現邏輯與展現控制,可是咱們相信,標籤控制符是更清晰、更容易維護的開發模式;
  • 你能夠在DSL裏面使用一些輔助性全局變量:

    • $setState: this.setState的簡便寫法,經過改變state值來觸發UI渲染;
    • $getRef: React經過組件ref屬性獲取組件的簡便寫法;
    • $getProps: 獲取React屬性的簡便性方法,至關於:this.xxx;

後面咱們還會作一些其餘的更高級的便利性擴展,好比:接入axios的異步操做,React的forceUpdate便利性機制等等。

script部分是用於書寫前端邏輯處理的地方,你可使用ES6的語法,作各類的數據處理,只須要最後把一個對象交給module.exports變量便可,這個對象能夠包含以下內容:

  • state: React Component的state初始值,能夠是對象也能夠是函數;
  • props: React props初始值,能夠是對象也能夠是函數;
  • React組件的生命週期鉤子函數: 好比:componentDidMount等,會被自動掛在到最終生成的React Component Class裏面去;
  • 其餘任意的屬性或方法: 均會被掛在到React Component實例(this)上去,並且,對於方法部分會被自動綁定到this做用域(this.xxx.bind(this)) 。

對於異步處理部分,默承認以直接調用this.axios.xxx的方法來實現,並支持ES7:async/await語法:

module.exports = {
    async getData(reqArg = {}) {
        const res = await this.axios.post('url/post', reqArg);

        return res;
    }
};

同時,支持異步請求庫可配置,能夠在loader的配置裏配置本身的異步請求庫,此時會替換掉默認的axios。但這一塊功能暫時尚未加入,承諾在接下來的一週以內會加上去。目前能夠經過組件props傳遞的方式來使用異步,好比:

import App from './index.lesx';
import axios from 'axios';


console.log('App:', App);

render(<App
    axios={axios}
    components={{
        My,
    }}
/>, document.querySelector('#root'));

而後在lesx文件的script裏面就能夠這樣用:

module.exports = {
    props: {
        valid: true
    },

    state: {
        id: 1001,
    },

    async getData(reqArg = {}) {
        const res = await this.props.axios.post('url/post', reqArg);

        return res;
    },

    clickHandler({
        setState,
    }) {
        const {
            id,
        } = this.state;

        const userData = this.getData({
            id,
        });

        setState({
            name: userData.name,
        });
    }
};

開發的極大便利:

UI庫是咱們在開發中重度依賴的部分,特別是對於像React這種徹底組件化的開發框架來講,有個好用的UI框架簡直是如虎添翼,會讓咱們的開發效率獲得極大地提高!因此,咱們的開發框架默認集成了國內最優秀的React UI庫:antd,固然了,你也能夠經過loader的配置來更改UI庫,好比可使用material-ui等。

在配置了UI庫以後,無需作任何工做就能夠直接在template標籤裏面使用該UI庫的任意組件了,好比使用Button組件:

<script>
    <Button type="primary" onClick={() => {
        alert('I am an antd button!');
        $setState({
            name: 'new name'
        });
    }}>antd button</Button>
</script>

Lesx不只會自動幫你打包你使用到的組件,同時,還會自動幫你把組件的樣式引入;另外,基於babel的插件:babel-plugin-import,咱們作到了按需打包,只會把你用到的組件給打包進來,保證打包後的文件的最小體積。

開發者不須要書寫React的組件生成代碼

由於咱們把React Component生成的過程所有放在了AOT裏實現,因此開發者無需寫React組件生成、UI庫組件引入的操做,其實,開發者甚至不須要知道React的存在,也甚至更不須要學習React,惟一須要作的就是在渲染js文件中作一些組件引入以及渲染執行的操做,可是就這一塊的成本實際上是極低的。

目前前端的資源是極度缺少的,整個互聯網都缺前端,因此,咱們在考慮如何釋放前端人力這個方案的時候,咱們是否能夠考慮如何下降前端的上手成本,讓後端同窗能夠上手前端開發,作到網後端開發賦能呢?其實Lesx的開發範式一開始就是爲這個方向考慮的,在知足下降前端開發成本、下降前端開發複雜度、提升代碼可維護性的同時,也能夠很方便的提供給後端,讓後端同窗能夠輕鬆上手前端開發,從而達到合做雙贏的狀態。對於前端人手緊缺的公司能夠考慮這個方案的落地,也許會起到意想不到的效果。

同時,爲了可擴展性,咱們作了一些額外的處理。除了能夠給Lesx DSL轉成的Component傳遞屬性而後能夠在Lesx文件使用以外,當咱們確實須要第三方或者本身以前基於React原生模式開發的組件須要拿過來直接使用的時候,咱們提供了components屬性,將任意的第三方組件放在conponents屬性對象中,既能夠直接在DSL中使用,以下:

import React, { Component } from 'react';
import { render } from 'react-dom';
import My from './My';
import App from './index.lesx';


console.log('App:', App);

render(<App
    components={{
        My,
    }}
/>, document.querySelector('#root'));

在上面咱們引入了本身開發的My組件,並放在了Lesx DSL轉成的App組件的components屬性裏,因而能夠在lesx文件中像下面這樣使用:

<style>
    { /** style代碼 */ }
</style>

<template>
    <div>
        <a onClick={this.func}>點我</a>
        <My />
    </div>
</template>

<script>
    { /** 邏輯代碼 */ }
</script>

其實,基於這種開發範式針對不一樣的場景能夠有不一樣的代碼組織模式。若是你的界面不是很複雜,或者是比較典型的中後臺應用場景(增刪改查這種),你能夠徹底基於一個.lesx文件開發完你全部的頁面邏輯,更多的則是依賴於第三方的UI庫來爲你的開發提供便利,說白了就是更多的依賴於組件搭積木式的開發範式,這個時候template就是開發的重點所在,而scriptstyle只是起到了添磚加瓦的便利性的開發,這個時候Lesx的職責就是頁面級別的代碼組織方式;若是是比較複雜的應用,好比SPA應用,這時咱們能夠基於Lesx來開發本身的一個個的React組件,而後加入vanexdva等數據流管理框架來方便對大量數據的操做,最後經過react-router等router組件進行統一組織,而後進行渲染。這個時候Lesx的職責就不同了,變成了組件級別的代碼組織。

怎麼樣,有沒有那麼一點點的打動你的心呢?^_^ 若是有的話,不妨去體驗下Lesx,相信會帶給你不同的開發體驗。

例子:lesx-example
webpack loader: lesx-loader

相關文章
相關標籤/搜索