成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Babel 在提升前端效率的實踐

chanthuang / 3029人閱讀

摘要:經(jīng)過一周左右的時間完成了基礎(chǔ)組件的編寫。配置涵蓋了目前的業(yè)務(wù)場景的基本需求,但是可擴展性很低。最終決定采用的生態(tài)鏈來解決上述遇到的問題。在指定的路徑下寫入對應(yīng)的文件。

大綱

    遇到的問題場景及解決方案對比

    什么是babel?

    解決過程

    目前遺留的問題

    目前實現(xiàn)功能API

    參考

遇到的問題場景及解決方案對比

我們目前采用的是antd + react(umi)的框架做業(yè)務(wù)開發(fā)。在業(yè)務(wù)開發(fā)過程中會有較多頻繁出現(xiàn)并且相似度很高的場景,比如基于一個table的基礎(chǔ)的增刪改查,這個相信大家都非常熟悉。在接到一個新的業(yè)務(wù)需求的時候,相信有不少人會選擇copy一份功能類似的代碼然后基于這份代碼去改造以滿足當(dāng)前業(yè)務(wù),當(dāng)然我目前也是這樣做的~

其實想把這塊功能提取成一個公共組建的想法由來已久,最近開始做基礎(chǔ)組件,便拿這個下手了。經(jīng)過一周左右的時間完成了基礎(chǔ)組件的編寫。

查看基礎(chǔ)支持的功能點API。

基本的思路是通過json生成一些抽象配置,然后通過解析json的抽象配置+渲染器最終生成頁面。json配置涵蓋了目前80%的業(yè)務(wù)場景的基本需求,但是可擴展性很低。比如一些復(fù)雜的業(yè)務(wù)場景:表單的關(guān)聯(lián)校驗、數(shù)據(jù)關(guān)聯(lián)顯示、多級列表下鉆等等功能。雖然通過一些較為復(fù)雜的處理可以把這些功能融入進來,但最終組件將會異常龐大難以維護。

所以,我能不能通過這些json配置通過某種工具生成對應(yīng)的代碼?這樣一來以上提到的問題就完全不存在了,因為這和我們自己寫的代碼完全一樣,工具只是幫我們完成初始化的過程。所以后來想了很多辦法,最初采用template string的方式,這種方式較為簡單粗暴,無非通過string中嵌套變量的判斷來輸出code。但是在實際寫的時候發(fā)現(xiàn)很多問題,比如

    function的輸出(JSON.stringify會將function忽略)

    多層函數(shù)嵌套之后怎么獲取最終渲染的節(jié)點code

    嵌入變量怎么實現(xiàn)、umi-models-effects/reducer中額外的字典查詢怎么生成等等..

最終學(xué)習(xí)了一些生成代碼的工具比如angular-cli以及一些關(guān)于js生成代碼的文章,主要是通過知乎上的這篇討論了解到了大家是怎么處理這種問題的。最終決定采用babel的生態(tài)鏈來解決上述遇到的問題。

我們目前采用的方式是基于antd+react(umi)編寫通用的CRUD模板,然后通過代碼生成器解析json中的配置生成對應(yīng)的代碼,大致的流程是:

React --> JavaScript AST ---> Code Generator --> Compiler --> Page

目前功能只是完成了初步版本,待應(yīng)用在項目中使用一段時間穩(wěn)定之后將會開源~

什么是babel?

Babel是一個工具鏈,主要用于編譯ECMAScript 2015+代碼轉(zhuǎn)換為向后兼容的可運行在各種瀏覽器上的JavaScript。主要功能:

    語法轉(zhuǎn)換

    環(huán)境中缺少的Polyfill功能

    源代碼轉(zhuǎn)換

    查看更多Babel功能

Understanding ASTs by Building Your Own Babel Plugin

如上提供了babel基本的流程及一篇介紹AST的文章。

我的理解中比如一段string類型code,首先通過babel.transform會將code轉(zhuǎn)為一個包含AST(Abstract Syntax Tree)的Object,同樣可以使用@babel/generator將AST轉(zhuǎn)為code完成逆向過程。 例如一段變量聲明代碼:

const a = 1;

在解析之后的結(jié)構(gòu)為:

{ "type": "Program", "start": 0, "end": 191, "body": [ { "type": "VariableDeclaration", "start": 179, "end": 191, "declarations": [ { "type": "VariableDeclarator", "start": 185, "end": 190, "id": { "type": "Identifier", "start": 185, "end": 186, "name": "a" }, "init": { "type": "Literal", "start": 189, "end": 190, "value": 1, "raw": "1" } } ], "kind": "const" } ], "sourceType": "module" }

首先類型為VariableDeclaration,首先他的類型是const,可以通過點擊查看api其它還有let、var的值。其次是聲明declarations部分,這里值為數(shù)組,因為我們可以同時定義多個變量。數(shù)組中值的類型為VariableDeclarator,包含idinit兩個參數(shù),分別為變量名稱以及變量值。id的類型為Identifier,譯為修飾符即是變量名稱。init類型為Literal,即是常量,一般常用的有stringLiteral、numericliteralbooleanliteral等。此時即完成了變量賦值的過程。

當(dāng)然這只是很簡單的語法轉(zhuǎn)換,如果大家想學(xué)習(xí)更多關(guān)于轉(zhuǎn)換及類型的知識,可參考如下兩個官方鏈接:

babel-types

ast轉(zhuǎn)換工具

解決過程

首先定義目錄結(jié)構(gòu):

. ├── genCode // 代碼生成器 | ├── genDetail // 需要新頁面打開時多帶帶的detail目錄 | └── genIndex // 首頁 | └── genModels // umi models | └── genServices // umi services | └── genTableFilter // table篩選區(qū)域 | └── genTableForm // 非新頁面模式,新增/更新模態(tài)框 | └── genUpsert // 新頁面模式下,新增/更新頁面 | └── genUtils // 生成工具類 ├── schema // 模型定義文件 | ├── table // 當(dāng)前要生成的模型 | └── ├──config.js // 基礎(chǔ)配置 | └── └──dataSchema.js // 列表、新增、更新配置 | └── └──querySchema.js // 篩選項配置 ├── scripts // 生成腳本 | ├── generateCode.js // 生成主文件 | └── index.js // 入口 | └── utils.js // 工具類 ├── toCopyFiles // 生成時需要拷貝的文件,比如less └── index.js // 主入口

主體流程為:

    指定要生成代碼的路徑。

    根據(jù)schema中當(dāng)前json配置路徑,依次調(diào)用genCode目錄中各個模塊的代碼生成方法獲取對應(yīng)code。

    在指定的路徑下寫入對應(yīng)的文件。

    執(zhí)行eslint ${filePath} --fix格式化生成的代碼。

    根據(jù)配置對應(yīng)復(fù)制toCopyFiles文件夾中依賴的less等文件到對應(yīng)的文件夾。

其中主要模塊為genCode文件夾中根據(jù)json配置生成代碼的過程。 以genModels為例,首先提取可以使用template string完成的部分,減少代碼解析的工作量。

module.exports = (tableConfig) => { return ` import { message } from "antd"; import { routerRedux } from "dva/router" import { parse } from "qs" ${dynamicImport(dicArray, namespace)} export default { namespace: "${namespace}", state: { ... }, effects: { *fetch({ payload }, { call, put }) { const response = yield call(queryData, payload); if (response && response.errorCode === 0) { yield put({ type: "save", payload: response.data, }); } else { message.error(response && response.errorMessage || "請求失敗") } }, ..., ${dynamicYieldFunction(dicArray)} }, reducers: { save(state, action) { return { ...state, data: action.payload, }; }, ..., ${dynamicReducerFunction(dicArray)} }, }; ` }

因為列表數(shù)據(jù)可能有字典項從后臺獲取值來對應(yīng)顯示,所以import、effects、reducers模塊均有需根據(jù)配置動態(tài)生成的代碼。 以dynamecImport為例:

function dynamicImport (dicArray, namespace) { // 基礎(chǔ)api import let baseImport = [ "queryData", "removeData", "addData", "updateData", "findById" ] // 判斷json數(shù)據(jù)中是否有需從后臺加載項 if (dicArray && dicArray.length) { baseImport = baseImport.concat(dicArray.map(key => getInjectVariableKey(key))) } // 遍歷生成依賴項 const _importDeclarationArray = map(specifier => ( _importDeclarationArray.push(t.importSpecifier(t.identifier(specifier), t.identifier(specifier))) )) // 定義importDeclaration const ast = t.importDeclaration( _importDeclarationArray, t.stringLiteral(`../services/${namespace}`) ) // 通過@babel/generator 將ast生成code const { code } = generate(ast) return code }

其它代碼生成邏輯類似,有不確定如何生成的部分可參考上方提供的鏈接完成代碼轉(zhuǎn)換再去生成。

若有通過babel轉(zhuǎn)換無法生成的代碼,可通過正則來完成。

例如以下umi-models代碼:

*__dicData({ payload }, { call, put }) { const response = yield call(__dicData, payload); if (response && response.errorCode === 0) { yield put({ type: "updateDic", payload: response.data, }); } else { message.error(response && response.errorMessage || "請求失敗") } }

基礎(chǔ)代碼可通過yieldExpression生成,但是轉(zhuǎn)換之后無function之后的*符號,反復(fù)查了文檔之后沒有解決辦法,最后只能將生成完的code利用正則替換來解決。 如果大家有遇到類似的問題歡迎討論~

問題

    目前使用的編輯器組件為braft-editor,但是結(jié)合antd使用initialValue不生效,必須使用setFieldsValue。但是使用useEffects時會默認添加props.form作為依賴并且props.form會不斷變化而觸發(fā)死循環(huán),目前無奈只有禁用eslint react-hooks/exhaustive-deps。

useEffect(() => { props.form.setFieldsValue({ editorArea: BraftEditor.createEditorState(current.editorArea), editorArea2: BraftEditor.createEditorState(current.editorArea2) }); }, [current.editorArea, current.editorArea2]);

    生成的代碼怎么刪除未使用的依賴?使用eslint --fix不會刪除未使用的變量定義。

    初始化之后的代碼要修改怎么辦?因當(dāng)前方法只會完成代碼初始化過程,以后修改的過程暫無思路解決。

功能API

參數(shù)規(guī)范參考react-antd-admin 功能配置包含三個基礎(chǔ)配置文件:

config.json配置基本屬性

dataSchema.json配置列表及新增修改字段

querySchema.json配置篩選區(qū)域字段

config.json

配置列表

參數(shù) 必填 類型 默認值 說明
namespace true string null 命名空間
showExport false boolean true 是否顯示導(dǎo)出
showCreate false boolean true 是否顯示創(chuàng)建
showDetail false boolean true 是否顯示查看
showUpdate false boolean true 是否顯示修改
showDelete false boolean true 是否顯示刪除
newRouterMode false boolean false 在新的頁面新增/編輯/查看詳情。若包含富文本編輯器,建議此值設(shè)為true,富文本在模態(tài)框展示不是非常美觀。
showBatchDelete false boolean true 是否顯示批量刪除,需multiSelection為 true
multiSelection false boolean true 是否支持多選
defaultDateFormat false string "YYYY-MM-DD" 日期格式
upload false object null 上傳相關(guān)配置,上傳圖片和上傳普通文件分別配置。 詳見下方upload屬性
pagination false object null 分頁相關(guān)配置, 詳見下方pagination屬性
dictionary false array null 需要請求的字典項,用于下拉框或treeSelect的值為從后端獲取的情況,可在dataSchema 和querySchema中使用, 詳見下方dictionary屬性

upload

參數(shù) 必填 類型 默認值 說明
uploadUrl false string null 默認的上傳接口.優(yōu)先級image/fileApiUrl > uploadUrl > Global.apiPath
imageApiUrl false string null 默認的圖片上傳接口
fileApiUrl false string null 默認的文件上傳接口
image false string "/uploadImage" 默認的上傳圖片接口
imageSizeLimit false number 1500 默認的圖片大小限制, 單位KB
file false string "/uploadFile" 默認的上傳文件接口
fileSizeLimit false number 10240 默認的文件大小限制, 單位KB

pagination

參數(shù) 必填 類型 默認值 說明
pageSize false number 10 每頁顯示數(shù)量
showSizeChanger false boolean false 是否可以改變pageSize
pageSizeOptions false array ["10", "20", "50", "100"] 指定每頁可以顯示多少條
showQuickJumper false boolean false 是否可以快速跳轉(zhuǎn)至某頁
showTotal false boolean true 是否顯示總數(shù)

dictionary

參數(shù) 必填 類型 默認值 說明
key true string null 變量標識
url true string null 請求數(shù)據(jù)地址

dataSchema.json

配置列表

參數(shù) 必填 類型 默認值 說明
key true string null 唯一標識符
title true string null 顯示名稱
primary false boolean false 主鍵 如果不指定主鍵, 不能update/delete, 但可以insert;
如果指定了主鍵, insert/update時不能填寫主鍵的值;
showType false string input 顯示類型
input/textarea/inputNumber/datePicker/rangePicker/radio/select/checkbox/multiSelect/image/file/cascader/editor
disabled false boolean false 表單中這一列是否禁止編輯
addonBefore false string/ReactNode null showType 為input可以設(shè)置前標簽
addonAfter false string/ReactNode null showType 為input可以設(shè)置后標簽
placeholder false string null 默認提示文字
format false string null 日期類型的格式
showInTable false boolean true 這一列是否要在table中展示
showInForm false boolean true 是否在新增或編輯的表單中顯示
validator false boolean null 設(shè)置校驗規(guī)則, 參考https://github.com/yiminghe/async-validator#rules
width false string/number null 列寬度
options false array null format:[{ key: "", value: "" }]或string。showType為cascader時,此字段暫不支持Array,數(shù)據(jù)只能通過異步獲取。
min false number null 數(shù)字輸入的最小值
max false number null 數(shù)字輸入的最大值
accept false string null 上傳文件格式限制
sizeLimit false number 20480 上傳文件格式限制
url false string null 上傳圖片url。圖片的上傳接口, 可以針對每個上傳組件多帶帶配置, 如果不多帶帶配置就使用config.js中的默認值;如果這個url是http開頭的, 就直接使用這個接口; 否則會根據(jù)config.js中的配置判斷是否加上host
sorter false boolean false 是否排序
actions false array null 操作

actions

參數(shù) 必填 類型 默認值 說明
keys false array null 允許更新哪些字段, 如果不設(shè)置keys, 就允許更所有字段
name true string null 展示標題
type false string null update/delete/newLine/component

querySchema.json

配置列表

參數(shù) 必填 類型 默認值 說明
key true string null 唯一標識符
title true string null 顯示名稱
placeholder false string null 提示語
showType false string input 顯示類型, 一些可枚舉的字段, 比如type, 可以被顯示為單選框或下拉框
input, 就是一個普通的輸入框, 這時可以省略showType字段
目前可用的showType: input/inputNumber/datePicker/rangePicker/select/radio/checkbox/multiSelect/cascader
addonBefore false string/ReactNode null showType 為input可以設(shè)置前標簽
addonAfter false string/ReactNode null showType 為input可以設(shè)置后標簽
defaultValue false string/array/number null 多選的defaultValue是個數(shù)組
min false number null showType為 inputNumber 時可設(shè)置最小值
max false number null showType為 inputNumber 時可設(shè)置最大值
options false array null options的key要求必須是string, 否則會有warning
normal-format: [{"key": "", "value": ""}]
cascader-format: [{"value": "", "label": "", children: ["value": "", "label": "", children: []]}]
如果值為string,代表異步獲取的數(shù)據(jù),則獲取當(dāng)前命名空間下該key對應(yīng)的值
defaultValueBegin false string null showType為 rangePicker 時可設(shè)置默認開始值
defaultValueEnd false string null showType為 rangePicker 時可設(shè)置默認結(jié)束值
placeholderBegin false string 開始日期 showType為 rangePicker 時可設(shè)置默認開始提示語
placeholderEnd false string 結(jié)束日期 showType為 rangePicker 時可設(shè)置默認結(jié)束提示語
format false string null 日期篩選格式
showInSimpleMode false boolean false 在簡單查詢方式下展示,若數(shù)據(jù)中有一項包含此字段且為true的值,則開啟簡單/復(fù)雜篩選切換

參考

react-antd-admin

AST語法轉(zhuǎn)換器

babel-types-api

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/6655.html

相關(guān)文章

  • babel提升前端效率實踐

    摘要:配置涵蓋了目前的業(yè)務(wù)場景的基本需求,但是可擴展性很低。最終決定采用的生態(tài)鏈來解決上述遇到的問題。在指定的路徑下寫入對應(yīng)的文件。 大綱 遇到的問題場景及解決方案對比 什么是babel? 解決過程 目前遺留的問題 目前實現(xiàn)功能API 參考 遇到的問題場景及解決方案對比 我們目前采用的是antd + react(umi)的框架做業(yè)務(wù)開發(fā)。在業(yè)務(wù)開發(fā)過程中會有較多頻繁出現(xiàn)并且相似度很高的場...

    huayeluoliuhen 評論0 收藏0
  • Taro 簡介

    摘要:讓人又愛又恨的微信小程序自微信小程序以下簡稱小程序誕生以來,就伴隨著贊譽與爭議不斷。同時于開發(fā)者來說,小程序的生態(tài)不斷在完善,許多的坑已被踩平,雖然還是存在一些令人詬病的問題,但已經(jīng)足見微信的誠意了。 Taro 介紹 在互聯(lián)網(wǎng)不斷發(fā)展的今天,前端程序員們也不斷面臨著新的挑戰(zhàn),在這個變化多端、不斷革新自己的領(lǐng)域,每一年都有新的美好事物在發(fā)生。從去年微信小程序的誕生,到今年的逐漸火熱,以及...

    sixgo 評論0 收藏0
  • 《從零構(gòu)建前后分離web項目》:前端了解過關(guān)了嗎?

    摘要:前端基礎(chǔ)架構(gòu)和硬核介紹技術(shù)棧的選擇首先我們構(gòu)建前端架構(gòu)需要對前端生態(tài)圈有一切了解,并且最好帶有一定的技術(shù)前瞻性,好的技術(shù)架構(gòu)可能日后會方便的擴展,減少重構(gòu)的次數(shù),即使重構(gòu)也不需要大動干戈,我通常選型技術(shù)棧會參考以下三點一提出自身業(yè)務(wù)的需求是 # 前端基礎(chǔ)架構(gòu)和硬核介紹 showImg(https://segmentfault.com/img/remote/146000001626972...

    lbool 評論0 收藏0
  • 《從零構(gòu)建前后分離web項目》:前端了解過關(guān)了嗎?

    摘要:前端基礎(chǔ)架構(gòu)和硬核介紹技術(shù)棧的選擇首先我們構(gòu)建前端架構(gòu)需要對前端生態(tài)圈有一切了解,并且最好帶有一定的技術(shù)前瞻性,好的技術(shù)架構(gòu)可能日后會方便的擴展,減少重構(gòu)的次數(shù),即使重構(gòu)也不需要大動干戈,我通常選型技術(shù)棧會參考以下三點一提出自身業(yè)務(wù)的需求是 # 前端基礎(chǔ)架構(gòu)和硬核介紹 showImg(https://segmentfault.com/img/remote/146000001626972...

    cgspine 評論0 收藏0
  • 《從零構(gòu)建前后分離web項目》:前端了解過關(guān)了嗎?前端基礎(chǔ)架構(gòu)和硬核介紹

    摘要:前端準備前端了解過關(guān)了嗎前端基礎(chǔ)架構(gòu)和硬核介紹技術(shù)棧的選擇首先我們構(gòu)建前端架構(gòu)需要對前端生態(tài)圈有一切了解,并且最好帶有一定的技術(shù)前瞻性,好的技術(shù)架構(gòu)可能日后會方便的擴展,減少重構(gòu)的次數(shù),即使重構(gòu)也不需要大動干戈,我通常選型技術(shù)棧會參考以下三 # 前端準備 :前端了解過關(guān)了嗎?前端基礎(chǔ)架構(gòu)和硬核介紹 showImg(https://segmentfault.com/img/remote/...

    SwordFly 評論0 收藏0

發(fā)表評論

0條評論

chanthuang

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<