1. Vite brings the light

It’s no exaggeration to say that Vite has brought an absolute revolution to the front-end.

Or we can say that the integration of esbuild, Browser es modules, HMR, Pre-Bundling, and other advanced tools and ideas about JS compilation development in the community behind Vite has brought about a revolutionary changes.

The main reason why Vite is faster is that esbuild does pre-bundles dependencies + browser native ESM dynamic compilation, which I won’t go into too much detail here

native ESM

In the context of this idea, going back to our component development scenario and looking at it again will reveal the following issues that are highly compatible:

  • Component libraries are developed without actually compiling all the components.
  • Component development, compilation of preview pages mainly for developers, browser compatibility can be controlled.
  • The HMR (hot update) capability is even more immediate with Vite, which used to be the most time-consuming area for component development and debugging.
  • All source modules in Vite are dynamically compiled, i.e. TypeScript type definitions and JS annotations can also be compiled dynamically, greatly reducing the scope of compilation.

Then, the old way of thinking like StoryBook and the previous way we used to extract tsx component type definitions will be able to make a relatively big change

Previously, in order to get the type data of the component input, a plugin was made at the Wwebpack level to dynamically analyze the tsx component of export, and a static attribute variable of __docgenInfo was dynamically added under the component to inject the type data and annotation information obtained from AST analysis into the component JS Bundle, which can be further processed into dynamic parameter settings.

TypeScript’s definition of component Props:

TypeScript’s definition of component Props

Analyze the content injected into the JS Bundle:

JS Bundle

Analysis of the parameter interaction settings achieved after conversion

-

So for the component, actually getting this metadata for the type definition is redundant for the component itself. Whether or not this metadata is used in the component, it will be extracted and injected into the component Bundle during Webpack compilation, which is obviously very inefficient.

In the idea of Vite, it is perfectly possible to get the metadata information of a component when it is used, for example, loading a React component as:

1
import ReactComponent from './component1.tsx'

Then load its metadata i.e.

1
2
3
4
import ComponentTypeInfo from './component1.tsx.type.json'; 

// or 
const ComponentTypeInfoPromise = import('./component1.tsx.type.json');

Load .type .json file type through Rollup plugin capability in Vite to parse component metadata. Also, with the ability of Rollup itself for compilation dependency collection and HMR, we can do the hot update of component type changes

2. Design ideas

The above is a preliminary idea inspired by the module loading idea of Vite.

But if we really want to make such a React and Rax component development kit based on Vite, there are certainly other problems that need to be solved besides the acquisition of component entry metadata, the first of which is the parsing of .md files

2.1 Component Usage

Referring to the component development ideas provided by dumi and Icework, the component Usage can be written to any .md file in the form of a Markdown write document, which is dynamically parsed by the compiler for jsx, tsx, css, scss, less code block, and compiles it as an executable script to run on the page

This is not only in writing the document, but also can run debugging components under the different components into the performance of the component, how many components in the Case, can be written in different blocks for the user to choose to see, this design idea is really let people applaud!

Finally, if you can combine the esbuild dynamic loading and HMR capabilities of Vite mentioned above, the whole component development experience will take another quantum leap

So for Markdown files a Vite plugin needs to be made to perform file parsing and loading of .md, with the following expected capabilitieswill be as follows:

1
2
3
4
import { content, modules } from "./component1/README.md";

// The original content of content README.md
// modules run modules by parsing the obtained `jsx`, `tsx`, `css`, `scss`, `less`

Please click to enlarge to see the expected effect.

2.2 Components Runtime

What should a regular component repository directory look like? Whether it is in a separate component repository or in an existing business project, the directory structure of components is actually similar, roughly as follows:

1
2
3
4
5
6
7
8
9
components
├── component1
│   ├── README.md 
│   ├── index.scss
│   └── index.tsx
├── component2
│   ├── README.md
│   ├── index.scss
│   └── index.tsx

In our scenario you can start the component development mode in any project, and after running vite-comp you will see a component-specific interface, where the component Usage written in README.md and index.tsx defined in index.tsx are already parsed and rendered for you. interface, you just need to access the different file paths to see how the corresponding component is represented

At the same time, you can finally compile and package all the contents of this interface and publish the screenshots to NPM, so that others can see the component clearly and see the component parameters, usage, screenshots, etc. You can even open the Demo address and modify the component parameters to see how the component behaves in different states.

To achieve this effect, a set of component runtime Runtime support is needed to coordinate React components, README.md, TypeScript type definitions in tandem into the component debugging + documentation we need for the integrated component development page.

In such a Runtime, it is also necessary to use the module parsing capabilities of Vite to convert the request whose URL is *//(README|*).html into an accessible component Runtime Html that is returned to the browser, thus allowing the browser to run the real component development page.

1
2
3
4
5
6
7
http://localhost:7000/components/component1/README.html
-> 
/components/component1/README.html 
->
/components/component1/README.md
-> 
Runtime Html

2.3 components Props Interface

As I mentioned above, if you use Vite to add a component props interface type resolution capability to tsx, you can also make a standalone plugin for parsing file types ending in .tsx .type .json by importing such types of files which allows the compiler to dynamically parse the TypeScript types defined in its tsx files and return them to the front-end for consumption as modules

The loading process can be treated as a virtual module, which means that you can directly import a virtual file address and get the corresponding React component meta information

1
2
3
4
5
6
7
// React Component
import Component from './component1.tsx';
// React Component Props Interface
import ComponentTypeInfo from './component1.tsx.type.json';

// or
const ComponentTypeInfoPromise = import('./component1.tsx.type.json');

Since this parsing capability is not performed with the help of esbuild, it is not possible to synchronize the conversion performance with the compilation of the main flow of the component.

When requesting this file type, consider opening a new thread in Vite’s Serve mode to compile this part, as the whole process is asynchronous and will not affect the component main flow rendering progress. When the request returns a response, it is then used to render the component Props definition and the sidebar panel part.

During the hot update process, it is also necessary to consider whether the scope of the tsx file modification involves TypeScript type changes, and then trigger the HMR event to update the module if the modification is found to result in a type change

3. Components Build

The above are discussing the situation of components in the Serve state of Vite (that is, the development state), and we heavily relied on Vite above to take advantage of the loading capabilities of the browser’s es module to do some extensions to the dynamic loading capabilities of the development state.

But Vite does not have a Server service to start during the final Build of the component, and of course it will not be dynamically loaded by the browser, so in order to allow others to see the component we have developed and to experience how we debug the component during development, we need to consider compiling a html for the component that can be run by the browser.

So in the Vite plugin development process, it is necessary to consider the compilation path in the Build state, if it is in the Build state, Vite will use the Rollup compilation ability, then you need to consider manually provide all components of the rollup.input(entries).

During the plugin writing process, it is important to follow the plugin loading lifecycle provided by Rollup to ensure that the module loading logic and compilation logic of the Build process and the Serve process are consistent.

I didn’t understand the relationship between Vite and Rollup well enough in the beginning, and relied a lot on the server-side middleware capabilities provided by Vite’s Server in the module parsing process. It was only when considering the Build state that I realized the problem, and ended up almost rewriting the previous loading logic

4. Summary

I will call this program (kit) vite-comp, its general composition is composed of Vite + 3 Vite Pugins, each plug-in is not coupled with each other, mutual responsibilities are not the same, that is, you can get any one Vite plug-in to do other purposes, the follow-up will consider separate open source, respectively.

  • Markdown, used to parse .md files and load them to get the original text and runnable blocks such as jsx and tsx.
  • TypeScript Interface, used to parse .tsx files for props type definitions of export components
  • Vite Comp Runtime, used to run the component development state and compile the final component documentation

Preview Experience

Start:

Millisecond response for Markdown component documents:

TypeScript type recognition

This new compile mode has already brought me a lot of development state gains, combined with the Vite play in the future will certainly be endless, such as Midway + lambda + Vite front-end integration program is also to see the people to applaud, in this thriving front-end era, I believe that different front-end products will be combined with the Vite out of the next legendary story.


Reference https://mp.weixin.qq.com/s/j4F2KVTlJjbMs99FjBn_6A