本篇文章給大家分享一個vscode智能提示插件:nutui-vscode-extension,并360全方位的了解它,介紹一下使用方法,希望對大家有所幫助!
NutUI v3 版本發布至今已經 1 年了,無論是集團內部還是外部開發者,都在各自不同的業務場景中開發使用,我們感到驕傲的同時也是壓力倍增,積極努力修復開發者的各種 issue,擴展組件功能,盡可能滿足開發者訴求。今年以來陸續補充了多技術棧(React)、組件級 UI 定制、國際化及代碼智能提示能力。本篇將介紹代碼智能提示(vscode插件)的功能,并就 NutUI-Vscode 的實現給大家做一個詳盡的剖析?!就扑]學習:《vscode入門教程》】
直觀體驗
什么是代碼智能提示?為了讓大家有一個直觀的認識,讓我們先來仔細觀察下面兩張 gif 圖~
組件庫沒有任何的代碼提示
組件庫有了智能提示之后
不知大家在看了上面兩張圖片之后有什么樣的感想?很明顯,我們使用了智能提示之后,無論是快速查看文檔,還是查看組件屬性,都會很方便的進行查閱,當然開發效率上肯定也有了顯著的提升。那么,讓我們快來親自體驗下吧~
使用指南
Tips:NutUI官網-開發工具支持,這里也有簡要介紹哦~
- 在 vscode 中安裝 nutui-vscode-extension 插件
- 安裝 vetur 插件。不了解這個插件的vscode有介紹
安裝完成以上兩個插件之后,重新啟動我們的 vscode ,就可以愉快的體驗 NutUI 的智能提示功能啦,是不是簡直不要太簡單~
體驗也結束了,是不是該跟我一起熟悉熟悉它的原理啦。既然是開發 vscode 插件,那首先我們一定是要先熟悉它的開發以及調試、發布流程。一份文檔送給你哦??催@里:
https://code.visualstudio.com/docs
熟悉了基本的 vscode 開發流程之后,下面就跟隨我一步步揭開這個智能提示功能的神秘面紗吧~
360全方位解讀
快速查看組件文檔
從上圖可以看出,當我們在使用 NutUI 進行開發的時候,我們在寫完一個組件 nut-button,鼠標 Hover 到組件上時,會出現一個提示,點擊提示可以打開 Button 組件的官方文檔。我們可快速查看對應的 API 來使用它開發。
首先我們需要在 vscode 生成的項目中,找到對應的鉤子函數 activate ,在這里面注冊一個 Provider,然后針對定義好的類型文件 files 通過 provideHover 來進行解析。
const?files?=?['vue',?'typescript',?'javascript',?'react']; export?function?activate(context:?vscode.ExtensionContext)?{ ??context.subscriptions.push( ????vscode.languages.registerHoverProvider(files,?{ ??????provideHover ????}) ??); }
下面我們可以具體看看 provideHover 是如何實現的?
const?LINK_REG?=?/(??{ ??const?line?=?document.lineAt(position);?//根據鼠標的位置讀取當前所在行 ??const?componentLink?=?line.text.match(LINK_REG)????[];//對?nut-開頭的字符串進行匹配 ??const?componentBigLink?=?line.text.match(BIG_LINK_REG)????[]; ??const?components?=?[...new?Set([...componentLink,?...componentBigLink.map(kebabCase)])];?//匹配出當前Hover行所包含的組件 ??if?(components.Length)?{ ????const?text?=?components ??????.filter((item:?string)?=>?componentMap[item]) ??????.map((item:?string)?=>?{ ????????const?{?site?}?=?componentMap[item]; ????????return?new?vscode.MarkdownString( ??????????`[NutUI?->?$(references)?請查看?${bigCamelize(item)}?組件官方文檔](${DOC}${site})n`, ??????????true ????????); ??????}); ????return?new?vscode.Hover(text); ??} };
通過 vscode 提供的 API 以及 對應的正則匹配,獲取當前 Hover 行所包含的組件,然后通過遍歷的方式返回不同組件對應的 MarkDownString,最后返回 vscode.Hover 對象。
細心的你們可能發現了,這里面還包含了一個 componentMap ,它是一個對象,里面包含了所有組件的官網鏈接地址以及 props 信息,它大致的內容是這樣的:
export?interface?ComponentDesc?{ ??site:?string; ??props?:?string[]; } export?const?componentMap:?Record<string>?=?{ ????actionsheet:?{ ????????site:?'/actionsheet', ????????props:?["v-model:visible=''"] ????}, ????address:?{ ????????site:?'/address', ????????props:?["v-model:visible=''"] ????}, ????addresslist:?{ ????????site:?'/addresslist', ????????props:?["data=''"] ????} ????... }</string>
為了能夠保持每次組件的更新都會及時同步,componentMap 這個對象的生成會通過一個本地腳本執行然后自動注入,每次在更新發布插件的時候都會去執行一次,保證和現階段的組件以及對應的信息保持一致。這里的組件以及它所包含的信息都需要從項目目錄中獲取,這里的實現和后面講的一些內容相似,大家可以先想一下實現方式,具體實現細節在后面會一起詳解~
組件自動補全
我們使用 NutUI 組件庫進行項目開發,當我們輸入 nut- 時,編輯器會給出我們目前組件庫中包含的所有組件,當我們使用上下鍵快速選中其中一個組件進行回車,這時編輯器會自動幫我們補全選中的組件,并且能夠帶出當前所選組件的其中一個 props,方便我們快速定義。
這里的實現,同樣我們需要在 vscode 的鉤子函數 activate 中注冊一個 Provider。
vscode.languages.registerCompletionItemProvider(files,?{ ????provideCompletionItems, ????resolveCompletionItem })
其中,provideCompletionItems ,需要輸出用于自動補全的當前組件庫中所包含的組件 completionItems。
const?provideCompletionItems?=?()?=>?{ ??const?completionItems:?vscode.CompletionItem[]?=?[]; ??Object.keys(componentMap).forEach((key:?string)?=>?{ ????completionItems.push( ??????new?vscode.CompletionItem(`nut-${key}`,?vscode.CompletionItemKind.Field), ??????new?vscode.CompletionItem(bigCamelize(`nut-${key}`),?vscode.CompletionItemKind.Field) ????); ??}); ??return?completionItems; };
resolveCompletionItem 定義光標選中當前自動補全的組件時觸發的動作,這里我們需要重新定義光標的位置。
const?resolveCompletionItem?=?(item:?vscode.CompletionItem)?=>?{ ??const?name?=?kebabCase(<string>item.label).slice(4); ??const?descriptor:?ComponentDesc?=?componentMap[name]; ??const?propsText?=?descriptor.props???descriptor.props?:?''; ??const?tagSuffix?=?`${item.label}>`; ??item.insertText?=?`${tagSuffix}`; ??item.command?=?{ ????title:?'nutui-move-cursor', ????command:?'nutui-move-cursor', ????arguments:?[-tagSuffix.length?-?2] ??}; ??return?item; };</string>
其中, arguments代表光標的位置參數,一般我們自動補全選中之后光標會在 props 的引號中,便于用來定義,我們結合目前補全的字符串的規律,這里光標的位置是相對確定的。就是閉合標簽的字符串長度 -tagSuffix.length,再往前面 2 個字符的位置。即 arguments: [-tagSuffix.length – 2]。
最后,nutui-move-cursor 這個命令的執行需要在 activate 鉤子函數中進行注冊,并在 moveCursor 中執行光標的移動。這樣就實現了我們的自動補全功能。
const?moveCursor?=?(characterDelta:?number)?=>?{ ??const?active?=?vscode.window.activeTextEditor!.selection.active!; ??const?position?=?active.translate({?characterDelta?}); ??vscode.window.activeTextEditor!.selection?=?new?vscode.Selection(position,?position); }; export?function?activate(context:?vscode.ExtensionContext)?{ ??vscode.commands.registerCommand('nutui-move-cursor',?moveCursor); }
什么?有了這些還不夠?有沒有更加智能化的,我不用看組件文檔,照樣可以輕松開發。emm~~~,當然,請聽下文講解
vetur 智能化提示
提到 vetur,熟悉 Vue 的同學一定不陌生,它是 Vue 官方開發的插件,具有代碼高亮提示、識別 Vue 文件等功能。通過借助于它,我們可以做到自己組件庫里的組件能夠自動識別 props 并進行和官網一樣的詳細說明。
vetur詳細介紹看這里
https://vuejs.github.io/vetur/guide/component-data.html#workspace-component-data
像上面一樣,我們在使用組件 Button 時,它會自動提示組件中定義的所有屬性。當按上下鍵快速切換時,右側會顯示當前選中屬性的詳細說明,這樣,我們無需查看文檔,這里就可以看到每個屬性的詳細描述以及默認值,這樣的開發簡直爽到起飛~
仔細讀過文檔就可以了解到,vetur 已經提供給了我們配置項,我們只需要簡單配置下即可,像這樣:
//packag.json { ????... ????"vetur":?{ ????????"tags":?"dist/smartips/tags.json", ????????"attributes":?"dist/smartips/attributes.json" ????}, ????... }
tags.json 和 attributes.json 需要包含在我們的打包目錄中。當前這兩個文件的內容,我們也可以看下:
//?tags.json { ??"nut-actionsheet":?{ ??????"attributes":?[ ????????"v-model:visible", ????????"menu-items", ????????"option-tag", ????????"option-sub-tag", ????????"choose-tag-value", ????????"color", ????????"title", ????????"description", ????????"cancel-txt", ????????"close-abled" ??????] ??}, ??... }
//attributes.json { ????"nut-actionsheet/v-model:visible":?{ ????????"type":?"boolean", ????????"description":?"屬性說明:遮罩層可見,默認值:false" ????}, ????"nut-actionsheet/menu-items":?{ ????????"type":?"array", ????????"description":?"屬性說明:列表項,默認值:[?]" ????}, ????"nut-actionsheet/option-tag":?{ ????????"type":?"string", ????????"description":?"屬性說明:設置列表項標題展示使用參數,默認值:'name'" ????}, ????... }
很明顯,這兩個文件也是需要我們通過腳本生成。和前面提到的一樣,這里涉及到組件以及和它們關聯的信息,為了能夠保持一致并且維護一份,我們這里通過每個組件源碼下面的 doc.md 文件來獲取。因為,這個文件中包含了組件的 props 以及它們的詳細說明和默認值。
組件 props 詳細信息
tags, attibutes, componentMap 都需要獲取這些信息。 我們首先來看看 doc.md 中都包含什么?
##?介紹 ##?基本用法 ... ###?Prop |?字段?????|?說明?????????????????????????????????????????????????????????????|?類型???|?默認值?| |?--------?|?----------------------------------------------------------------?|?------?|?------?| |?size?????|?設置頭像的大小,可選值為:large、normal、small,支持直接輸入數字???|?String?|?normal?| |?shape????|?設置頭像的形狀,可選值為:square、round????????????|?String?|?round??| ...
每個組件的 md 文檔,我們預覽時是通過 vite 提供的插件 vite-plugin-md,來生成對應的 html,而這個插件里面引用到了 markdown-it 這個模塊。所以,我們現在想要解析 md 文件,也需要借助于 markdown-it 這個模塊提供的 parse API.
//?Function?getSources let?sources?=?MarkdownIt.parse(data,?{}); //?data代表文檔內容,sources代表解析出的list列表。這里解析出來的是Token列表。
在Token 中,我們只關心 type 即可。因為我們要的是 props,這部分對應的 Token 的 type 就是 table_open 和 table_close 中間所包含的部分??紤]到一個文檔中有多個 table。這里我們始終取第一個,*** 這也是要求我們的開發者在寫文檔時需要注意的地方 ***。
拿到了中間的部分之后,我們只要在這個基礎上再次進行篩選,選出 tr_open 和 tr_close 中間的部分,然后再篩選中間 type = inline 的部分。最后取 Token 這個對象中的 content 字段即可。然后在根據上面三個文件不同的需求做相應的處理即可。
const?getSubSources?=?(sources)?=>?{ ??let?sourcesMap?=?[]; ??const?startIndex?=?sources.findIndex((source)?=>?source.type?===?TYPE_IDENTIFY_OPEN); ??const?endIndex?=?sources.findIndex((source)?=>?source.type?===?TYPE_IDENTIFY_CLOSE); ??sources?=?sources.slice(startIndex,?endIndex?+?1); ??while?(sources.filter((source)?=>?source.type?===?TR_TYPE_IDENTIFY_OPEN).length)?{ ????let?trStartIndex?=?sources.findIndex((source)?=>?source.type?===?TR_TYPE_IDENTIFY_OPEN); ????let?trEndIndex?=?sources.findIndex((source)?=>?source.type?===?TR_TYPE_IDENTIFY_CLOSE); ????sourcesMap.push(sources.slice(trStartIndex,?trEndIndex?+?1)); ????sources.splice(trStartIndex,?trEndIndex?-?trStartIndex?+?1); ??} ??return?sourcesMap; };
好了,以上就是解析的全部內容了。總結起來就那么幾點:
1、創建一個基于 vscode 的項目,在它提供的鉤子中注冊不同行為的 command 和 languages,并實現對應的行為
2、結合 vetur,配置 packages.json
3、針對 map json 文件,需要提供相應的生成腳本,確保信息的一致性。這里解析 md 需要使用 markdown-it 給我們提供的 parse 功能。
最后
本文從直觀體驗到實際使用再到實現原理分析,一步步帶著大家感受了 NutUI 和 VSCode 結合,給大家帶來的福利,讓大家能在開發上有了全新的體驗,同時,也讓我們的組件庫越發充滿了魅力。接下來,讓我們共同攜手,讓它發揮出更加強大的價值~
更多關于VSCode的相關知識,請訪問:vscode!!