Intro to VuePress 1.x
TL;DR: This post is a speech reinterpretation of the same name given to me on 3th VueConf Shanghai on June 8th, 2019, you can click this link to get the full slides.
Since April 2018, with the hard work of the maintainers, VuePress, a static website generator launched by Vue.js, has released 96 versions and recently reached from alpha to beta stage. Today, we are execited to announce the release of VuePress 1.x, and what exciting features it brings us.
First, let’s take a look at some of the excellent VuePress works from the community. Special thanks to @vicbergquist for contributing to the collection of quality VuePress sites.
If you want to find more examples, you can continue to check out the links below.
Looking at above examples, I believe that even if you are not familiar with VuePress, you can probably guess that it is a tool for building websites. Well, let’s talk first, what is VuePress?
Let’s take a look at the earliest look of VuePress, which is VuePres 0.x.
First, VuePress is a static website generator. The most important feature of VuePress is that it naturally supports using Vue in Markdown. In the core, we also have a simple theming system, and the theming system has a built-in default theme for writing documentations. In addition, it also supports a layout system that allows users to dynamically specify layout components.
In this context, thanks to its lightweight and easy to use, VuePress quickly attracted a large number of users. But over time, iteration continues to grow, the core code is getting more and more, it slowly seems to become difficult to maintain, at the same time, in the many feature requests submitted by users, some of the really valuable features do not seem to great for being placed in the core repo. Therefore, we are thinking, is there a way to achieve the unlimited increase of new features with avoiding the endless growth of the main warehouse code?
So, we started 1.x, and VuePress has gradually become the following in the past few months.
First of all, regarding the “theme”, we have evolved from a “simple theme system” to a “theme system”, that is, a VuePress theme will no longer be just an SFC, it may also contain its own styles, configurations, and the plugins we will talk about next. At the same time, we have added an official blog theme. In addition, the layout system is extracted from the default theme to the core, such a great feature also reached cross-the-theme reusing.
In addition, it may be the biggest change in 1.x, that is, we have added a plugin system. The internals of 1.x are implemented with plugin APIs on some core functions, and a large number of reusables are precipitated.
Under such an architecture, in addition to solving the problems of 0.x, we also decouple the “core” and “business requirements”, and many functions (such as pwa, search) achieve reusing across themes.
To learn more about the 1.x design concepts, you can move to this link.
To make VuePress easier to get started, we recently released create-vuepress , which is indeed an npm package, but it doesn’t mean you need to install it manually first.
We can create a VuePress project with the native scaffolding capabilities provided by the package management tool. Here we show the yarn as an example:
Open the url, you will see a document site that is almost same to VuePress’s official website:
Next, let’s take a look at what the project structure of this site looks like.
First, you can see your docs directory with a lot of markdown files, which will be converted to the corresponding urls based on its hierarchy. The last .vuepress, which is a convention to hold all the configuration, agreed files, etc. then let’s see what is in .vuepress?
The first directory, it’s components, all Vue SFCs in this directory can be used directly in markdown. In the following styles, you can write custom styles in index.styl and global colors in palette.styl. Finally, the config.js, which is the configuration file of the VuePress.
Some users here may say that I don’t want to create a project locally, it doesn’t matter, you have another option, codesandbox, while the boilerplate is also a wonderful contribution from @vicberquist!
When user build a new project, he/she may also think, I don’t like this default theme. Well, let’s talk about the theme next.
By convention, let’s take a look at the existing themes.
On the left, it is the default theme, we have just seen it, so will not repeat it here. On the right, this is the recently launched blog theme. You can select the blog boilerplate to initialize such a blog in the yarn create vuepress that we just used to create a new project. In addition, this theme has been iterated very frequently recently. If you are interested, feel free to submit pull requests.
Some users may say: Hey, I don’t like the official theme, what should I do?
Well, just changing the theme, there are many high-quality themes in the community that can be used directly. Next, I will list a few more distinctive themes for you.
The third one seems to be based on Material Design:
Fourth, a little nice:
The fifth, the style is really good.
With so many good-looking themes, how do I use them?
You only need to care the name of the theme in npm, which can be configured in the theme field of the configuration file. If the theme you are using also accepts some configuration, then you can pass them in themeConfig.
But what if I cannot a theme I like? At this time, it is time to write one by yourself.
Regarding the specific details, you can find them in the documentation.
Having said that, we don’t seem to have seen the plugin yet. Well, then, let’s start talking about plugins.
The same convention, let’s take a look at what plugins are there.
The first, PWA plugin, it makes your website faster. As you can see, if you have visited VuePress’s official website, you will find that next time the speed will be very fast, because these requests are taken directly from the Service Worker’s cache. In addition, we also provide a Popup. It pops up automatically when the Service Worker has installed an update.
Let’s take a quick look at the implementation of this plugin.
First, when the user first visits a VuePress site with PWA enabled, VuePress will automatically register the Service Worker; when the user accesses the second time, the Service Worker will hijack the client request and directly return the result of the cache. The next time you redeploy your site, the Service Worker will silently install it in the background. When it is installed, it will send an update event from the Worker process to the main process of the page. At this point the user can see the Popup.
If the user clicks Refresh, the main process will transfer this message to the worker process to trigger the Service Worker’s skipWating to implement refresh. Since pwa is not the main content of this speech, anyone interested in it can head to the blog post below to find out why we are adopting this solution.
The second, search plugin, is designed to make searching easier.
On the left is the out-of-the-box headers-based search, while the right is the optional full-text search powered by Algolia Search, which requires you to register and apply for an appId.
Next we look at the interaction of this search plugin.
The user first types the keyword, and the <SearchBox> component registered by the search plugin will try to find the matching results in VuePress’s built-in application metadata. If found, the matching result will be rendered to the user.
In this search plugin, two most important is the search experience of the user interaction layer, and the underlying search matching algorithm. If you are interested, you can submit pull request to optimize the built-in search algorithm, VuePress search does not currently support word segmentation.
Here, I also thought about a very interesting question: “Since the pages are loaded asynchronously, how do we implement out-of-the-box full-text search?
Next is the official blog plugin, what features does it have?
- Customize classification based on directory (e.g. _post) or Front Matter (e.g. tag)
- Built-in blog-styled permalinks
- Out-of-the-box paging
The design philosophy of this plugin is: We hope that for blog theme developers pay more attention to the interactive experience of the theme itself, rather than the logic of classification, pagination, etc. that are invisible and not of interest to users.
So how can this plugin simplify the productivity of developing a blog theme? I’ve prepared an example of using only 70 lines of code to implement a functionality qualified blog theme.
The next is the yuque plugin, the biggest significance of creating it is that we create the possibility of connecting to a purely dynamic data source.
How to use this plugin? You only need to configure a repoUrl option for this plugin, and the plugin will do all the conversion work for you.
Of course, here is a mention. In fact, since yuque uses a rich text editor, the page data obtained through its Open API may lose some information (such as Videos), and at the same time, due to the existence of some custom styles, so the yuque is not the best possible data source for VuePress.
So, as long as you are willing to, you can connect any data source to VuePress.
After learning a few VuePress plugins, let’s take a look at how the VuePress plugin system works.
First, let’s take a look at the architecture diagram of the VuePress plugin.
Start with the bottom: we have two main project concepts, the user side and the theme side.
The same thing about both is that both the user and the theme can have their own configuration, and some applied plugins. The difference is that the most important files on the user side is the one-on-one markdown file, while for a theme is the layout components it provides.
Go back to the above section. We know that VuePress has a webpack-based build process. In this case, the plugin API allows you to do something before and after the dev server. You can also apply some additional Webpack plugins or Loaders. Also, the plugin can also extend the internal markdown-it compiler, and you can also generate some dynamic modules for client consumption.
Then, let’s see what plugin APIs we have.
here we focus on VuePress’s most unique and core plugin option APIs during the build process:
- extendPageData, you can use this option to add some extra fields to the object of each page.
- additionalPages: used to add some dynamic pages. The blog plugin mentioned above uses this option to dynamically generate some pages for you.
- clientDynamicModules: VuePress is based on Vue Router, and you will find that you have not configured the routes. Yes, VuePress internally generates dynamic routing modules by this option and then consumes them on the client.
Other plugin APIs are available and can be found on the official documentation.
Then, let’s take a look at how to write a VuePress plugin:
- Export a plain object directly and then configure the plugin options you want to use;
- If your plugin also wants to have options, then it can be a function that exports a plain object, where the first parameter of the plugin itself, the second parameter is the current compilation context of the application.
Here, let’s demonstrate a plugin example:
In addition, what did 1.x bring to us?
Here is an intuitive example to express the role of permalinks.
Using SFC as source page
Just when we showed the plugin example, we mentioned that our page can point directly to a Vue SFC. Here, the only thing that we need to consider is how to use Front Matter.
Why do we need theme inheritance?
At 0.x, we found that many users would choose to eject the default theme, even though he/she just wanted to change one of the components.
In addition, let’s imagine that if there is such a feature that allows me to extend a parent theme, if I want to modify one of the files, then I only need to create a new file in the same name in the child theme I created. And then tweak it. This is a very natural experience.
So, how does VuePress implement this kind of file overriding? Let’s take overriding the <Navbar> component in default theme as an example.
In fact, this overriding is based on webpack alias. Since the default theme imports <Navbar> with alias @theme/components/Navbar.vue, once you create the same file in the same location, VuePress will automatically change the alias point to the new file, Once you remove the file, the point of this alias will be restored.
So, it means that to give your theme the ability to be extended, you need to use the @theme alias to import all of your components.