NutUI is a very good mobile component library. It has 1.8K star on GitHub and over 13K NPM downloads. The company has been able to support 40+ projects internally and 20+ projects externally. Users will receive the following benefits:

  1. The component library ecosystem covers a wide range, with more than 50+ components in layout category, operation feedback category, basic category and navigation category, and their usage scenarios are fully considered for each category.
  2. Active discussion groups, if you are not happy with it, you can ask some questions on GitHub, if you still feel slow, you can also directly @ the developer in our wechat group.
  3. Detailed API explanations and rich Demo application scenarios are listed. Even if you are a back-end developer, you can quickly use NutUI to develop your website once you have a basic understanding of Vue.
  4. The official website is powerful, providing component search, NutUI version switch, Demo display and other functions.
  5. Support loading on demand to reduce the volume of our development projects.
  6. The addition of new features will not affect the old version of the code, so it can be said that forward compatibility, without changing the code, can be safe to update.

NutUI has been around for 2 years, with the 2017 version being V1.0, which is a process of building wheels and fumbling. Most of the original components are components that come from the business and are pulled out of the project and packaged.

Back in the days when anyone could submit components, the naive idea was to reuse, to accumulate the number of components in the business first. For example, it takes a student 2-3 days to develop an address distribution component, which will also be available in another shopping scenario project. If everyone develops one, it will be wasted. The earliest component libraries were only used internally, and NutUi looked like this at the time:

Early home pages:

Early document pages:

Through the above two pictures, we can see that the original website has many shortcomings and even become pain points, specific performance is as follows:

  1. The homepage of the official website is dark and heavy, with too much display content and no good information classification.
  2. The display area on the right lacks the real-time Demo display, only the code display, which cannot directly reflect the UI of the plug-in.
  3. The left navigation component is not classified, which is not conducive to the user to find the desired component.
  4. Developers also pay a lot of attention to the details of the documentation, such as style and functionality, when writing component library documentation.
  5. The Demo is not comprehensive and the styles of components are not uniform.
  6. Without automated testing, components are tested by developers themselves, making it difficult to consider everything.

Changes to these pain points 2.0 are as follows:

  1. Professional designers provide internal standard design drafts for websites and their components.
  2. Automated testing tools and regular code reviews are introduced to ensure component stability.
  3. To develop a one-click build tool for the official website, developers can easily complete the component documentation by remembering the simple MD tag.
  4. 2.0 also goes with the flow and supports new features such as internationalized one-touch skin peels.

Compared with 1.0, our component library has been comprehensively improved, with simple code specification, strong maintainability, full consideration of component usage scenarios and more perfect functions. So with so many components, how is its official website constructed? This article will give you the secrets.

After this article you will learn about the development process of the NutUI component library official website. At the same time, we analyze in detail why we choose Webpack plug-in in this form to develop, and the benefits of.md to.vue.

In the development of this plug-in function, we also used some Node operations, and NPM dependency package, it and our usual front-end development has many differences, different from the page interaction logic, I feel this is more interesting, so let’s explore it.

use

Before we start, let’s take a look at how to use the plugin to help you understand how we’re going to implement this feature.

In general, it is a Webpack plug-in, so it only needs to be configured in Webpack for use as follows:

{
    [
        ...new mdtohtml({
            entry: "./docs".output: "./sites/doc/page/".template: "./doc-site/template.html".nav: "left".needCode: false.isProduction: isDev
        })
    ];
}
Copy the code

Attributes that

parameter value instructions
entry string Path to the folder where you want to process the file
output string Path to the output file after processing
template string Converted to.vuePath to the HTML template to be configured later
nav string Generate site navigation location, currently only supported on the left
needCode boolean Whether code display tools are required
isProduction boolean Is it a development environment or a compilation environment

Design thinking

Demand analysis

What are the requirements for our official NutUI website?

  1. A unified presentation style is required.
  2. Reduce the coding effort of the developer and only worry about the documentation being written.
  3. You can quickly find a component by entering its name for an internal search.
  4. Create navigation bookmarks for each component description document.
  5. Distinguish between HTML and JS code and highlight it
  6. Each component needs a Demo on the right.

Implementation approach

Now that you know the requirements, you can develop the features. The most important thing is to choose the right path.

Here I chose to convert.md to.vue. Why?

Advantages of using MD editing

  1. The syntax is simple, and even non-developers can get used to it quickly. All MD tags are based on these four symbols (* – +. >) or a combination of them, and HTML has a lot of tags that are hard to remember and unstyled.

  2. Component library documents will have a lot of code display and style display, using HTML tag is not easy to control but using MD will be much easier, you can easily control the code display format. We want to show a piece of CSS code or JS code just use “” JS” “or” “CSS” “can do the code display.

  3. Easy to use a fixed template, let the document writer to follow the template to write the document, easier to unify the document.

  4. MD documents do not require strict closure like HTML tags, which is one of the reasons for choosing MD development.

  5. There are a lot of MD-to-HTML NPM packages on the market and we can save a lot of work on this part of the process.

  6. First of all, NutUI components are Vue based, and it would be too expensive to use a different framework for the same build tool.

  7. Using the.vue template development just happens to be able to nest the HTML converted from.md directly into the template.

  8. Modular development facilitates unified management of each component.

Style of management

Our Style rarely uses Class, instead styling based on tag selection:

h1.h2.p
{
	color: # 333333;
}

h1
{
	font-size: 30px;
	font-weight: 700;
	margin: 10px 0 20px;
}

Copy the code

The advantage of this is that we don’t have to worry about this when we document and can write a relatively complete document by remembering a few simple MD syntax.

The basic writing format is as follows:

  1. # Level 1 title – Component name
  2. ## Secondary title – bookmark
  3. CSS is used to display CSS code
  4. Js is used to display THE JS code
  5. | | header header

Language transformation

MD convert HTML principles

First of all, thanks to AST, we can implement this function. Now let’s take a look at how it transforms. We can not only drive, but also learn to repair cars. It is also the basis of all the transcoding tools on the market today. Without further ado, let’s get started.

Let’s start with a simple example. Here is a fragment in MD format:

# # marked transformation
# # # marked transformation
\` \ `\`js
var a = 0;
var b = 2;
\` \ `\ `Copy the code

The AST processing results are as follows:

The result is a large object, with each node having a specific Type, which we can then process to reproduce the format we want.

As you can see from the image above, the Type of ## is heading, depth: 2

This is an H2 tag, and the Type of ‘ ‘is Code. Everything we write in’ ‘ ‘is stored in the Code object.

It’s structured like a big tree with different branches, which IS why I think an AST is called an abstract syntax tree. By processing the generated AST object structure you can refer to the following figure:

Let’s take a look at the detailed conversion, such as the one we need to convert to HTML in this project.

We recursively process the structure of the object, converting it into the desired text. There are also a number of toolkits in the NPM package that work on this object for me, such as estraverse, a plugin library that loops through all the nodes of an AST object:

const res = estraverse.traverse(ast, {
    enter: function (node, parent) {
        if (node.type == "heading") return "";
    },
    leave: function (node, parent) {
        if (node.type == "code") console.log(node.id.name); }});Copy the code

Note: Use estraverse. Traverse to traverse an AST object. During traversal it accepts an option with two properties, Enter and leave. They represent the entry and exit phases of the listening traversal respectively. Usually we just need to define the methods inside Enter, as in the example above, to perform some of the processing we want when the conditions are met.

The above is just a simple simulation of the code conversion process, and the actual development process we can use packaged tools to complete the above things. You might want to try and convert some of the code yourself. Vue React Babel ESlint Loader in Webpack and code comparison tools all have AST in them. The AST approach to file analysis is all around us.

Transformation implementation scheme

When I started writing this plugin, I found a lot of mature packages in the NPM library. Here ARE two implementations for your reference.

Plan a
const parser = require("@babel/parser");
const remark = require("remark");
const guide = require("remark-preset-lint-md-style-guide");
const html = require("remark-html");
getAst = (path) = > {
    // Read the entry file
    const content = fs.readFileSync(path, "utf-8");
    remark()
        .use(guide)
        .use(html)
        .process(content, function (err, file) {
            console.log(String(file));
        });
};
getAst("./src/test.md");
Copy the code

The conversion result is as follows:

<h2>MdtoVue code conversion test</h2>
<pre>
	<code class="language-js">
		var a = 0; var b = 2;
	</code>
</pre>
Copy the code
Scheme 2

Use the plugin marked.

download

npm i marked -D
Copy the code

use

const fs = require("fs");
const marked = require("marked");
test = (path) = > {
    const content = fs.readFileSync(path, "utf-8");
    const html = marked(content);
    console.log(html);
};
test("./src/test.md");
Copy the code

Output result:

<h2 id="Mdtovue - Code Conversion Test">MdtoVue code conversion test</h2>
<pre><code class="language-js">var a = 0;
var b = 2;</code></pre>
Copy the code

Finally, I chose plan 2 because it was marked(content). We didn’t need to pay attention to the internal processing.

Wait, we’re not done yet. Is our plugin that simple? Of course not, everyone drink a saliva slowly look down ha ~

Selected conversion tools we also need to customize some of the content, for example, we need to add a TWO-DIMENSIONAL code in it, add a bookmark directory, general websites will have such requirements, so how to do it? Ladies and gentlemen, please scroll down

Controls marked to transform the output

Here’s an example of this functionality using qr codes on the site: Marked exposes a property called rendererMd, which allows us to process the results of the code marked transforms.

_that.rendererMd.heading = function (text, level) {
    const headcode = Qrcode ` < I class = "" > < a: href =" demourl "> < span > please use a mobile phone and yards experience < / span > < img: SRC =" codeurl "Alt =" "> < / a > < / I > `;
    const codeHead = `<h1>` + text + headcode + `</h1>`;

    if (_that.options.hasMarkList && _that.options.needCode) {
        if (level == 1) {
            return codeHead;
        } else if (level == 2) {
            return maskIdHead;
        } else {
            returnnormal; }}};Copy the code

From the above code we can see that rendererMd is an object, which is the Type in the AST, such as heading, code, and so on. You can have a fn that takes two parameters: text content and level depth. You can see the AST processing result earlier in the article. By changing the contents of the marked transform, we can insert the HTML structure of the QR code at the beginning of each component document into the result of the transform, and then concatenate the result of the above transform into a.vue file like this:

write(param){
    const _that = this;
    return new Promise((resolve, reject) = > {
        const outPath = path.join(param.outsrc, param.name);
        const contexts =
            `
       +
param.html +
(_that.options.hasMarkList
? '<ul class="markList">' + _that.Articlehead + "</ul>"
: "") +
`
`
;
_that.Articlehead = "";
_that.Articleheadcount = 0;
fs.writeFile(outPath, contexts, "utf8", (err, res) => {});
});
}
Copy the code

In the whole process above we did three things:

  1. throughmark.mdThe file is converted to HTML and inserts the code structure we want to customize.
  2. Insert HTML text into a generic VUE template.
  3. throughfs.writeFileMake a new one.vueFile.

This completes the first function of our.md to.vue transformation, converting the MD language to vUE language.

Optimization of conversion process

The following is a bit boring, but it’s an integral part of the plugin, and without it the whole conversion process would be incredibly slow.

With the basis of the above, then we will need to use the Node to read and write files, in fact, as a front-end developer, I started for the master is 0, but with countless read code, natural law of several of the slice in the heart, through the study of Node official document, I get to the knowledge sharing for everyone, Then came the humiliation.

As always, find your way before you drive, clear your mind, get twice the result with half the effort!

  1. Use Node to find.mdThe file.
  2. Save all file paths and add history here we are using hash to record history.

The requirement is that wherever the.md file is located, we need it to find and parse it. And fast, because time is life. The first thing I wanted to do was grab the path once and store it, then hash it again. For specific ideas, we look at the following process:

The advantage of this is that the conversion will only be performed again if the file changes. If the file does not change, there is no need to perform the conversion over and over again. The code is as follows:

const { hashElement } = require("folder-hash");
hashElement(_that.options.entry, {
    folders: { exclude: [". *"."node_modules"."test_coverage"]},files: { include: ["*.md"]},matchBasename: true
}).then((res) = > {});
Copy the code

Its return res structure is as follows:

{
    name: ".".hash: "YZOrKDx9LCLd8X39PoFTflXGpRU=".children: [{name: "examples".hash: "aG8wg8np5SGddTnw1ex74PC9EnM=".children: [{name: "readme-example1.js".hash: "Xlw8S2iomJWbxOJmmDBnKcauyQ8="
                },
                {
                    name: "readme-with-callbacks.js".hash: "ybvTHLCQBvWHeKZtGYZK7+6VPUw="
                },
                {
                    name: "readme-with-promises.js".hash: "43i9tE0kSFyJYd9J2O0nkKC+tmI="
                },
                { name: "sample.js".hash: "PRTD9nsZw3l73O/w5B2FH2qniFk="}]}, {name: "index.js".hash: "kQQWXdgKuGfBf7ND3rxjThTLVNA=" },
        { name: "package.json".hash: "w7F0S11l6VefDknvmIy8jmKx+Ng=" },
        {
            name: "test".hash: "H5x0JDoV7dEGxI65e8IsencDZ1A=,".children: [{name: "parameters.js".hash: "3gCEobqzHGzQiHmCDe5yX8weq7M=" },
                { name: "test.js".hash: "kg7p8lbaVf1CPtWLAIvkHkdu1oo="}]}]};Copy the code

We just need a recursion to process the entire structure into a file path map to complete the hash extraction

const fileHash = {};
const disfile = (res, outpath) = > {
    if (res.children) {
        disfile(res.children, res.name);
    }
    fileHash[res.name + outpath] = res.hash;
};
disfile(obj, "");
Copy the code

What we end up with is an object with a full path and hash:

{
    "./src/test.md": "3gCEobqzHGzQiHmCDe5yX8weq7M"."./src/tes2.md": "3gCEobqzHGzQiHmCDe5yX8weq7M"."./src/test/tes2.md": "3gCEobqzHGzQiHmCDe5yX8weq7M"
}
Copy the code

We store this object in a cache file via Node’s FS. You can use fs.writefile to write files to it. The main path here is to use fs.readfile to get the contents of the file for conversion.

We can see from the flowchart that after this step, when executing again, we just need to compare the file hash and history hash to see if there is any change. If there is no change, we can skip the rest of the process, which saves a lot of time and improves conversion efficiency. Compare the hash code and put it in a new JS file.

Implementation of real-time compilation

We’re used to writing documents as we go along, so we need real-time compilation. This feature looks difficult but is actually not:

filelisten() {
  const _that = this;
  const watcher = Chokidar.watch(path, {
    persistent: true.usePolling: true
  });
  const log = console.dir.bind(console);
  const watchAction = function ({ event, eventPath }) {
    // This is where the file changes
    if (/\.md$/.test(eventPath)) { _that.vueDesWrite(eventPath); }}; watcher .on("change", (path) =>
        watchAction({ event: "change".eventPath: path })
       )
    .on("unlink", (path) =>
        watchAction({ event: "remove".eventPath: path })
       );
}
Copy the code

The core method is Chokidar. Watch and when we detect that a file has changed we convert it once through the converter THAT I’ve defined.

But as I was writing this article, I got creative and came up with a new plan:

First, the more files chokidar.watch listens on, the more performance is affected, and second, the entire file is recompiled every time you change one character. If we could make it clear that PATH only listens to the currently edited file, performance would definitely improve.

The second is to compile the transformation, which should use the hot update principle, similar to the Vnode implementation, which only updates the changed node. I’m not aware of any off-the-shelf toolkits out there, and I’m looking for someone with the will to implement one

Webpack plug-in development

With all the functionality in place, we need to integrate our code into Webpack, which is written as a Webpack plug-in. So what’s important about plug-in development for Webpack?

Key points of Plug-in development

In fact, the development of the plug-in is very simple, just need to pay attention to define an Apply to listen for Webpack events.

MyPlugin.prototype.apply = function(compiler) {}
Copy the code

This is done primarily through Compiler, which is a reference to the Webpack Compiler. Compiler can be used to monitor Webpack:

When Webpack starts compiling

apply(compiler) {
  compiler.plugin("compile".function (params) {
    console.log("The compiler is starting to compile...");
  });
}
Copy the code

When Webpack compiles and generates the final resource

apply(compiler) {
   compiler.plugin("emit".function(compilation, callback) {}}Copy the code

In fact, Webpack will be compiled in the process of many nodes, we can use this method to listen to Webpack. Compilation can also be used to listen for references to compiled objects when this method is called through Compilation. Compiler Compilation: Compiler Compilation: Compiler Compilation: Compiler Compilation

  • CompilerRepresents a compiler entity, essentially a callback event on the compiler.
  • CompilationRepresents the compilation process which is the process that we define in the compiler

Such as:

// compilation (' compiler 'listener for' compiling ')
compiler.plugin("compilation".function(compilation) {
  console.log("The compiler is starting a new compilation...");
  The compilation event listener allows you to access the compilation reference, which is an object reference that represents the compilation process
  // We must distinguish between Compiler and compilation, with one representing the compiler entity and the other representing the compilation process
  // optimize(' compile 'listener for' optimize file 'event)
  compilation.plugin("optimize".function() {
    console.log("The compilation is starting to optimize files...");
  });
});
Copy the code

We’ll talk about this in more detail below, and finally at the end of the document we pass

 module.export = MyPlugin;
Copy the code

You can just export the whole function.

How do I intervene in the Webpack process

After a brief understanding of Webpack plug-in development, we also need to know the processing process of Webpack, because our plug-in needs a suitable time to enter. This is done as soon as Webpack starts executing, because the product of our transformation is not the final HTML but the Vue, which needs to be processed by Webpack.

We hope that the whole process can be implemented as follows:

The purpose of doing this is to hope for better performance, more convenient to use!

Therefore, we need to have a simple understanding of the plug-in mechanism of Webpack, which is of great significance to the development of our whole function. When the plug-in has problems, we can quickly locate them.

From the above picture we can see that the conversion from MD to Vue must be done synchronously. This is a key point. Only when we convert all.md to.vue can we make Webpack do the following work.

Webpack, on the other hand, is essentially a serial event stream mechanism that works by connecting plug-ins in series

At the heart of all this is Tapable.

Tapable

Tapable is a nodejs-like Library for EventEmitter that controls the publishing and subscription of hook functions. Of course, the hook mechanism provided by Tapable is relatively comprehensive, which can be divided into synchronous and asynchronous (asynchronous parallel and asynchronous serial are distinguished in asynchronous). According to different termination conditions of event execution, the Bail/Waterfall/Loop type is derived.

Many objects in Webpack extend from the Tapable class. The Tapable class exposes the TAP, tapAsync, and tapPromise methods, and you can choose a function injection logic based on how the hook is synchronous/asynchronous.

  • Tap Synchronous hook, which cannot contain asynchronous calls when used.
  • TapAsync Asynchronous hook, which tells Webpack that the asynchron has finished with a callback
  • TapPromise Asynchronous hook, which returns a Promise telling Webpack that the asynchro is done

What is a Compiler

The Compiler object represents the complete Configuration of the Webpack environment. This object is created once when Webpack is started, and all the actionable Settings are configured, including options, Loader, and plugin. When a plug-in is applied in a Webpack environment, the plug-in receives a reference to this Compiler object. You can use compiler to access the main Webpack environment. Its internal implementation is roughly as follows:

class Compiler extends Tapable {
  constructor(context) {
    super();
    this.hooks = {
      /** @type {SyncBailHook<Compilation>} */
      shouldEmit: new SyncBailHook(["compilation"], / * * @)type {AsyncSeriesHook<Stats>} */
      done: new AsyncSeriesHook(["stats"], / * * @)type {AsyncSeriesHook<>} */
      additionalPass: new AsyncSeriesHook([]),
      /** @type{AsyncSeriesHook<Compiler>} */ ...... . some code }; . . some code }Copy the code

As you can see, Compier inherits Tapable and binds a hook object to the instance so that the instance of Compier can be used like this

compiler.hooks.compile.tapAsync(
    "afterCompile",
    (compilation, callback) => {
        console.log("This is an example plugin!");
        console.log(
            "Here's the compilation 'object which represents a single build of assets:",
            compilation
        );
        // Use the Plugin API provided by WebPack to manipulate the build results
        compilation.addModule(/ *... * /); callback(); });Copy the code

Compiler object is the compiler object of Webpack, the core of Webpack is the compiler.

What is a Compilation

The compilation object represents a resource version build. When running the Webpack development environment middleware, each time a file change is detected, a new compilation is created, resulting in a new set of compilation resources. A compilation object represents the current module resources, the compile-generated resources, the changing files, and the state information of the dependencies being tracked. The Compilation object also provides a number of critical timing callbacks that plug-ins can choose to use when doing custom processing. Its internal implementation is roughly as follows:

class Compilation extends Tapable {
	/** * Creates an instance of Compilation. * @param {Compiler} compiler the compiler which created the compilation */
	constructor(compiler) {
		super(a);this.hooks = {
			/** @type {SyncHook<Module>} */
			buildModule: new SyncHook(["module"]),
			/** @type {SyncHook<Module>} */
			rebuildModule: new SyncHook(["module"]),
			/** @type {SyncHook<Module, Error>} */
			failedModule: new SyncHook(["module"."error"]),
			/** @type {SyncHook<Module>} */
			succeedModule: new SyncHook(["module"]),
			/** @type {SyncHook<Dependency, string>} */
			addEntry: new SyncHook(["entry"."name"]),
			/** @type {SyncHook<Dependency, string, Error>} */}}}Copy the code

The compilation object is simply responsible for generating compilation resources. Let’s look at some of the more important event hooks in The Compiler and compilation in Webpack.

Compiler:

Event hooks trigger parameter type
entry-option Initialize the option SyncBailHook
run Begin to compile compiler AsyncSeriesHook
compile The compilation that actually begins, before the compilation object is created compilation SyncHook
compilation Now that I’ve generated the Compilation object, I’m ready to manipulate it compilation SyncHook
make Recursively analyze the dependencies starting with Entry and prepare to build each module compilation AsyncParallelHook
after-compile The build process is complete compilation AsyncSeriesHook
emit Before writing the contents of assets in memory to disk folder compilation AsyncSeriesHook
after-emit After writing the contents of assets in memory to the disk folder compilation AsyncSeriesHook
done Complete all compilation procedures stats AsyncSeriesHook
failed When a compilation fails error SyncHook

Compilation:

Event hooks trigger parameter type
normal-module-loader Normal module loader, which actually loads (one by one) the functions of all modules in the module graph. loaderContext module SyncHook
seal Triggered when the compilation stops receiving new modules. SyncHook
optimize Triggered when the optimization phase begins. SyncHook
optimize-modules Module optimization modules SyncBailHook
optimize-chunks To optimize the chunk chunks SyncBailHook
additional-assets Create additional assets for compilation. AsyncSeriesHook
optimize-chunk-assets Optimize all chunk resources (assets). chunks AsyncSeriesHook
optimize-assets Optimize all assets stored in compilation.assets assets AsyncSeriesHook

As you can see, you simply pass in a Compiler instance in Apply and register events based on that instance, Compilation as well, and then Webpack will execute the Call method in each process.

The syntax is

Compileer.hooks. Stage. Tap function ('Plug-in name', (phase callback parameter) => {});Copy the code

Such as:

compiler.hooks.run.tap(pluginName, compilation=>{
           console.log('Webpack build process begins'); 
});
Copy the code

After we run Webpack in Node, we can see:

$webpack .. Config webpack.dev. js webpack build start hash:f12203213123123123..... Donein 4.1s~~~~
Copy the code

We can also listen for some webPack-defined events, as follows.

compiler.plugin('complie', params => {
  console.log('I'm a sync hook')});Copy the code

To summarize, Webpack has a lot of event nodes, and our plug-in listens to Webpack through Apply. Step in at the right time to do what you want.

Function of the front

Along the way, we finally converted.md to.vue as a component, and then the vUE side of development, finally to the front end of things to do.

The routing process

Our single-page applications need routing, so how do we manage it? A distribution map that gives you an idea of NutUI’s structure

Md-vue to view. Md-vue to view. Md-vue to view. Put our quotes, etc. Md conversions into the page. In fact, this is mainly for the administrator to distinguish between them.

How do we manage our router? First of all, when we create our project, we will have a JSON file which mainly records some information of the component

"sorts": [
    "Data presentation"."Data entry"."Operational feedback"."Navigation component"."Layout components"."Basic components"."Business Component"]."packages": [{"name": "Cell"."version": "1.0.0"."sort": "4"."chnName": "List item"."type": "component"."showDemo": true."desc": "List items that can be combined into lists."."author": "Frans"}]Copy the code

Now all we have to do is combine it with our catalog.

const routes = [];
list.map((item) = > {
    if (item.showDemo === false) return;
    const pkgName = item.name.toLowerCase();
    // With the conversion our path has been determined
    routes.push({
        path: "/" + item.name,
        components: {
            default: Index,
            main: (a)= > import("./view/" + pkgName + ".vue")},name: item.name
    });
});
const router = new VueRouter({
    routes
});
Vue.use(vueg, router, options);
export default router;
Copy the code

Our website also has full screen and copy functions, which are easy enough for a Vue project. I won’t describe them in detail, but just write the documentation of each component into a JS file via mixins and mix it in.

conclusion

This is the end of the article, this paper mainly introduces the REALIZATION of MD format to Vue, and finally one key to generate the official website. Our exploration in the technical field is not over yet. It is the persistence of every developer in our field to find faster solutions by summarizing plans. In the future, NutUI will improve its own shortcomings with users’ feedback, strive to make its user experience more excellent, and create its own way in the era of rich front-end component library. The road ahead is long, let’s explore it together!