例子: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這個構建式的框架
。 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-if
,rt-repeat
等,這樣的框架的問題就是問題解決的並非很完全,抽出render部分的同時,咱們仍是須要對React建立部分須要大量的代碼書寫;同時,對於JSX語法擴展指令的模式增添了開發者的學習成本,後面開發中也須要不斷地去查看文檔如何使用這些指令,這是咱們極不推崇的。 java
在這樣的背景下,我花了兩天時間,早起晚睡、憋屎憋尿的完成了基於React作到UI、展現(樣式)與邏輯
分離的構建式開發框架:Lesx
的第一版。react
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
lesx文件有style/template/script三個標籤,內部分別存放他們對應的內容代碼。
style
部分咱們默認使用跟css徹底兼容同時有更多便利性語法的Sass
語言,後面立刻也會支持Less
語法。
tenplate
部分則徹底是React的jsx語法,同時由如下幾個擴展:
jsx-control-statements
提供了便利性的控制流標籤,好比:If
,For
等等,語法很是簡單,一次學習終生高效!固然,有的同窗可能會不承認這種標籤擴展控制流的模式,此時你也能夠繼續使用你熟悉的三元運算符、數組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 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
就是開發的重點所在,而script
跟style
只是起到了添磚加瓦的便利性的開發,這個時候Lesx的職責就是頁面級別
的代碼組織方式;若是是比較複雜的應用,好比SPA應用,這時咱們能夠基於Lesx來開發本身的一個個的React組件,而後加入vanex、dva等數據流管理框架來方便對大量數據的操做,最後經過react-router
等router組件進行統一組織,而後進行渲染。這個時候Lesx的職責就不同了,變成了組件級別
的代碼組織。
怎麼樣,有沒有那麼一點點的打動你的心呢?^_^ 若是有的話,不妨去體驗下Lesx,相信會帶給你不同的開發體驗。
例子:lesx-example
webpack loader: lesx-loader