DevUI is a team with both design and engineering perspectives, serving huawei Cloud DevCloud platform and several huawei internal middle and background systems, as well as designers and front-end engineers. Design Ng Component library: ng-Devui (Welcome Star)
1. Development background
To improve the usability of DevUI components for consumers:
- For the DevUI component library, there are currently only plugins that insert code blocks. Users can generate code blocks by entering keywords in an HTML file
For example, if you type d-button, vscode will automatically assume that when selected, the code block will appear:
- Avoid constantly switching to the component library website to query Demo and API while using components
- Auto complete, enter
<d-
suchComponent tag, can promptAPI
And complete, at the same time can promptparameterAnd completion. - Relevant hover prompts for existing code: The user hovers over the keyword to display the relevant description.
While it seems that many UI libraries do not yet implement the idea of moving API documentation from the website to the code, we may be able to implement an “API documentation enabled page “.
2. Development overview
2.1. Functional assumptions
The original version of the function envisioned as follows, the part of the fishbone map near the head means higher priority and should be developed first.Along with solving the bug, a new idea came up: relying on finding alarms/completing photo prompts/providing custom images for the GUI….
2.2. Achievements have been demonstrated
2.3. How did it happen?
This plug-in builds on its predecessors and is developed with reference to the Parser section of the Angular Language Service plug-in. The overall logic is get material + appropriate tools = functionality. Plug-in development details such as function registration /package configuration, please see the previous article, thank you for sharing!
2.3.1. Ideas of different versions
- Version 1.0 idea: Find the exported material module through the string matching, and call the corresponding API to complete the function when appropriate
- Idea of version 2.0: object-oriented encapsulation of functions and parameters for subsequent expansion, and integration of material module, reconstruction of its form, for 3.0 resource module object paving the way
- 3.0Version idea: Import the Server
LSP
, the tag sentence is generated by lexical/grammatical/semantic analysisAST
Replace the original regular match, and replace the Local API with the Server API - 4.0Version idea: interface oriented programming to further reduce the coupling degree of each module, optimization
parser
, try to add full functional support for instructions and custom commands to achieve rapid development
Aside: How do I find the tools? Read the API is one, read the source is one.
2.3.2. Current general architecture
The current architecture is shown in the following figure:
-
Control layer: with server.ts as the entry point, the connection with the language server is established through THE TCP connection provided by LSP, so that the HOST plans to invoke the functional API. Meanwhile, the Parser and resource module are activated (initialized), and an abstract syntax tree is generated based on the source code. A resource tree is generated based on the resource files (.json, etc.) generated according to the API documentation.
-
Model layer: Then build a bridge between Hunter node tree and resource tree. On one hand, get node information from abstract syntax tree and query corresponding resources in resource tree; on the other hand, cache method is adopted to improve the query efficiency next time.
-
Service layer: The obtained node information, such as Position and corresponding resources (or processing resources), is passed into the functional API provided by the LSP as parameters to implement the corresponding functions.
Overall, the architecture does not leave the general logic of getting material + appropriate tools = functional implementation, but it is worth noting that the existence of the Hunter class solves the problem of the node resource tree being refreshed together and gives both more possibilities. This is the benefit of high cohesion and low coupling.
3. Functional development
3.1. Get the material
For API calls, the network transmission overhead is expected to be greater than the local preprocessing, so the material can be
- Crawler results are processed to get the material
- Material documentation is locally provided by
Java
After processing, export the module module node_modules
Has been integrated in the module
Sample material:
export const HTML_SCHEMA=[
Accordion "| | - this is a accordion component"."Data | | Array < any > or AccordionMenuType | | null | | data source | | will choose, data source, you can customize the Array or use default AccordionMenuType | | true | | false | | []"."TitleKey | | string | | in the | | title attribute name | | optional, title of the property name, item titleKey type string, as the title shows content | | false | | false | | []"."LoadingKey | | string | | loading | | submenu whether loading of judging the property name | | optional, whether the sub menu to load the property name, item [loadingKey] type of Boolean | | false | | false | | []"."ChildrenKey | | string | | children | | property name of the sub menu | | optional, the property name of the sub menu, item [childrenKey] type of Array < any > | | false | | false | | []"
]
Copy the code
If the LACK of specification in the API documentation affects the processing of the material, you can coordinate with the component team or suggest that the team adopt an industry specification such as Angular Doc. In order to solve the versioning problem, the best solution is to integrate the material module into the node_modules of the corresponding component library, or consider the product’s own module processing script.
3.2. Using tools
3.2.1. Regular expressions
A regular expression describes a pattern of string matching. It can be used to check whether a string contains a substring, replace a matching substring, or take a substring that matches a certain condition from a string. For component characteristics such as
- Component of DevUI
d-button
thed-
, AntdesignButton
uppercaseB
And the modules that are introduced
import { DevUIModule } from 'ng-devui'
Operations during development
- Knock Spaces,
[]
(properties),(a)
Event, etc
Can be used as a regular match condition to implement a condition restriction or trigger. Examples of code:
// The use of devui starts with d-, such as d-button, to trigger
const componentRegex = /<(d-[a-zA-Z0-9-]*)\b[^<>]***/g;
// Match "", rather than "" and Spaces or "" and >, to make the condition that "" does not trigger but "" can trigger
const attributeValue= /^=\"[\s\S]*\"(? ! | \ 1)/(>);
Copy the code
3.2.2. Calls to the API
By looking at vscode’s own API documentation API, you can open up a new world of functionality. You may have to be patient and learn the interfaces and return values layer by layer. Take registerHoverProvider as an example:
3.2.3. Language Server Protocol
3.2.3.1. What is LSP?
Microsoft launches LSP, intended to standardize communication between language tools and code editors:It’s shipped with the Angular framework and JdkLSP
In VS Code, the language server consists of two parts:
- Language client: use
JavaScript
/TypeScript
Ordinary VS Code extensions written. This extension gives access to all the VS Code namespace apis. - Language server: A language analysis tool that runs in a separate process.
As long as a reliable connection (such as TCP) is established between C/S,Language Server can perform static program analysis to establish an abstract syntax tree for specified feature code (such as component library code) or all code, depending on the library/specification interface provided by the Language or Language tool developer. To get the required parameters of the API interface provided by the LSP, the code editor can implement many functions of the Client, including auto completion, hover prompt and auto error correction.
3.2.3.2. Why use AST?
Abstract syntax tree is a tree representation of the structure of program source code. Various kinds of words (tokens) are obtained from the program source code through the Lexer, which is then analyzed and checked by the Parserparser to obtain an abstract syntax tree (AST). For the following C code:
while(i < n){
sum += A[i++];
}
Copy the code
You can generate the AST structure as shown below:Usually the root node of the AST represents the entire program, and the internal nodes are abstract syntactic structures or words. The core of the AST is that it can work with the various syntactic elements in the input source codeOne to one correspondence. It turns out that most requests for LSPS are saying”Performs a specified action at a specified location“– this means that the plug-in developer only needs to think about when and where to trigger the specified action, so common arguments are
- Of the file
URI
- Of the file
change.document
- The word
position
The syntax tree provides the exact position of the Token(including the word). This is an advantage that can’t be achieved through regular expression matching.
Of course, when you dig into how languages are compiled, you can actually create your own language definitions. There’s plenty of room for imagination.
3.2.3.3. Importing LSPS on the ServerLSPGuide
When introducing vscode-languageserver in the package.json of the server folder:
"Dependencies ": {"vscode-languageserver": "^4.1.3"}Copy the code
Then developers can use the Server API.
3.2.3.4. Basic structure of LSPS
.Exercises ── Client // Language Client: │ ├── SRC │ ├── test // End to End tests for Language Client/Server │ ├─ extension.ts // Language Client Entry Point ├── package.json // The extension manifest ├─ server // Language Server ├─ SRC ├─ server.ts // Language Server entry pointCopy the code
3.2.4. Syntax tree of component libraries
As in the previous AST, HTML/CSS /ts/.d.ts files can be parsed into syntax trees. In the case of an HTML file, each level tag can be treated as a DOM node, and component statements can be broken into tokens through lexical/syntactic/semantic analysis.
- The label(e.g.,
d-button
) - api(e.g.,
style
) - attribute(e.g.,
primary
) - symbol(e.g.,
= ""
),
Then delimit the recognition range (keySpan) around each segmented element, and finally generate AST syntax tree after serialization. Consider the following code that uses the DevUI component library:
<div class="main">
<div class="left">
<d-accordion
[data] ="menu"
class="menu"
[restrictOneOpen] ="restrictOneOpen"
(itemClick) ="itemClick(**event)"
(menuToggle) ="menuToggle(**event)">
hello
</d-accordion>
</div>
<div class="content">
<app-table></app-table>
</div>
</div>
Copy the code
The AST generated by this plug-in can be expressed in part as:
However, it is important to note that similar work has already been done with tools like PosthTML, and if you want to parse markdown and the like, there are libraries for that, so “don’t redo the wheel” before you develop it yourself.
Each component label can finally achieve a single tree. In such a forest, the node tree can be matched with the resource tree node after reading a node position around the cursor and looking for its parents and children. In theory, autofix or dependency checking can also be used. Such forests can be saved by creating snapshots through initial analysis, and when local trees change, the snapshots are treated as dirty data. In the early days (referring to version 2.0), this idea could be used as a Map, which was considered to be a single node tree to query.
3.2.4.1. A few questions
- How is AST generation different from Angular or other tools?
A: It depends on the scope of the analysis. Angular, for example, is full-text and relies on the TS parser; The analysis component library has only the devui part :d-button — bsStyle — primary.
- Can YOU reuse AST from other tools?
A: In theory, yes, but implementing an Angular AST doesn’t extend your DevUI well and is bloated.
- Can markDown’s parsing package be called locally, or can markDown’s parsing display be implemented locally?
A: Be prepared to try!
- Can other component libraries be adapted?
A: Yes! Get the material + appropriate tool = functionality implementation is universal, and in some special cases, in addition to building a tree alone, you can use operations like limiting a functionality to only be activated when the component is used in conjunction with the [] binding variable or () binding function, as Angular does with devui components based on itself. In fact, the Industry for Rome is taking it a step further and wants to unify all the functionality based on AST, rather than each tool doing its own AST parsing.
4. Code and performance optimization
- Programming for interfaces and including modules that will be reused such as
getName()
Export into module decoupling - Consider not activating plug-ins if they are not necessary
- Whether the corresponding dependency is introduced, such as
@angualr
- Is there an iconic symbol, such as
<
ord-
- Whether or not the corresponding file,
html
orts
It’s worth noting that in the early days this might have been just a matter of reading local files and FileReader using regular expressions to detect whether devui dependencies were introduced in app.module.ts to avoid wasting resources by invalidly launching plug-ins; The problem was solved when the tool was upgraded to use the AST to obtain the element Token.
- Other Design patterns
5. Go online for inspection!
Use the VSCE package to publish to the VSCode plugin market. Note that you can omit parts such as test and out with.vscodeignore.
At present, preDevUIHelper4.0 has been launched in the VSCode plug-in market. Welcome to Star, Issue & PR, welcome to use! : -)
Join us
We are DevUI team, welcome to come here and build elegant and efficient man-machine design/R&D system with us. Recruitment email: [email protected].
Author: curtain guest
Editor: DevUI team
“Easy to use to fly! VSCode plug-in DevUIHelper design and development overview (2)” is coming, please look forward to ~
Previous article recommended
10 Things You Might Want to Take Back from Using Git
Dark Patterns and Thematic Development for Web Interfaces
How to Build a Grayscale Publishing Environment
- Snippets in VSCode↩
- Programmatic Language Features↩
- In addition to converting program text into data structures such as AST, Parser can also be used to process CSV, JSON, XML and other formats. ↩
- Language Server Extension Guide↩
- but
posthtml
The converted node tree is insensitive to location information, i.ekeySpan
Therefore, this project chose to rewritehtmlparser
, may be considered later in the specificationposthtml
Add the start and end information of a node.↩ - Vscode developed in Electron can use Nodejs to read and write local files, make cross-domain requests, and even create a local server.↩
2.0
Version and before you can see thislink↩