基于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

相关文章
相关标签/搜索