Skip to content

Getting started with Vitepress

Getting started with Vitepress

This article was written over 18 months ago and may contain information that is out of date. Some content may be relevant but please refer to the relevant official documentation or available resources for the latest information.

Getting started with Vitepress to create your blog site

Have you heard about Vitepress, but you have not checked it out at it yet? Well, in this article, we are going to cover the basic setup and share what all the fuss about this new fantastic static site generator.

If you are looking for something that would allow you to quickly create a static site with Markdown support, search, Light/Dark theme, advertisement, navigation, and much more, then Vitepress is what you are looking for.

Suppose you want some proof of Vitepress's power without having to invest any further time, I suggest you head over to the main Vitepress site (vitepress.dev) and experience what Vitepress can do, as the official site is built on Vitepress!

Vitepress website

What is Vitepress

Vitepress is a powerful Static Site Generator powered by Vite mainly used for Documentation and Blogs with the default theme, and open to customization to be used for anything you may need it to with custom themes and theme overrides.. Vitepress power comes from its low learning curve, powerful configuration settings, and the ability to easily customize it.

For example, internationalization is built-in, Theme toggling is built-in and even full-site searches require a single line in the config to be set up.

What makes Vitepress so powerful is its extensive configuration and the fact that it can be customized by overriding the existing theme, creating your theme, or simply enhancing pages with custom Vue code.

Prerequisites

To successfully run the following demo, you will need:

  • Node.js version 18 or higher.
  • Terminal for accessing VitePress via its command line interface (CLI).
  • Text Editor with Markdown syntax support.
  • VSCode is recommended, along with the official Vue extension.

Create your project

To create the project, we will follow the steps shown in the official Getting Started guide.

If you want to set up a Vitepress project quickly, run the following steps:

  • Create a new folder mkdir vitepress-tutorial
  • Access the folder cd vitepress-tutorial
  • Install Vitepress npm add -D vitepress
  • Run the Wizard npx vitepress init
  • Answer the questions:
    • Where should VitePress initialize the config?
    • Site title
    • Site Description
    • Theme
    • Do you want Typescript support?
  • run npm run docs:dev
  • Enjoy your site.

After you run the above steps, your Vitepress will be ready and running as shown below

New Vitepress installation

What is available out of the box

The site comes fully set up with enough to get you started. Let's see what features are available within the software:

  • Navbar: The site comes with a Navbar that already includes links to our blog pages
  • Light/Dark theme: Out of the box theming
  • Home page: Basic Homepage layout
  • Blogs: Two different blog posts with sidebar navigation

All of the above is available with just 4 files! Let's move forward and see how to customize our app.

Overriding the homepage

It is time to modify our site by accessing its folders. What you will probably notice when opening the site, is that Vitepress follows a very simple file structure, in fact, a new installation just includes 4 extra files on top of the expected package.json and node_modules.

Let's update our homepage to make it more unique. Because Vitepress follows a "file-system based router" we can find this file within the root of the project within a file called index.md. This file will be accessible at "/" or "/index.html" of your site.

The content of the file is the following:

---
# https://vitepress.dev/reference/default-theme-home-page
layout: home

hero:
 name: "Vitepress tutorial"
 text: "A VitePress Site"
 tagline: My great project tagline
 actions:
   - theme: brand
     text: Markdown Examples
     link: /markdown-examples
   - theme: alt
     text: API Examples
     link: /api-examples

features:
 - title: Feature A
   details: Lorem ipsum dolor sit amet, consectetur adipiscing elit
 - title: Feature B
   details: Lorem ipsum dolor sit amet, consectetur adipiscing elit
 - title: Feature C
   details: Lorem ipsum dolor sit amet, consectetur adipiscing elit
---

As you can see, the file has no code in it, and it is just driven by configuration, or more specifically in this case Markdown frontmatter, that is a set of configurations accepted by markdown files that help you set up your options such as title, description, og:image. We will describe frontmatter in more detail later in the article.

Before we jump into modifying the configuration of the file, you should know that Vitepress has a very extensive and well-detailed documentation site where you can find help if you are stuck or would like to learn more. In this case, we are overriding the "home" page, so the documentation can be found here: Home Page Default Theme configuration.

If you read the current file within the homepage, you will notice that it defines a "layout" of "home". This layout displays a main header with CTAs and a set of feature blocks.

There are three different layouts available in the Default theme: "home", "doc" and "page".

The title and description have already been set from the information we provided from the installation wizard. But the rest is just a basic boiler template. Let's see what we can change:

  1. Add a hero image. This image can either be externally sourced or saved within the repository.
hero:
 name: "Vitepress tutorial"
 text: "A VitePress Site"
 tagline: My great project tagline
 image:
   src: 'assets/logo.png'
   alt: 'My logo'
  1. Update the action buttons.
 actions:
   - theme: brand
     text: First Blog
     link: /first
   - theme: alt
     text: Thisdot.co
     link: https://thisdot.co

As shown above, Action buttons have two themes "brand" or "alt" and can accept internal or external links.

Vitepress is clever enough to set the external links to open in a new tab and set the rel="noreferrer".

DOM visual of the rendered external button
  1. Change the feature blocks:

Features blocks are great for engaging with the user and telling them what makes your site special. This accepts an icon and some text, so let's change ours with the following:

features:
 - icon: 🏚️
   title: Your Documentation house
   details: This is the house of your documentation
 - icon:
     src: https://emojipedia.org/house
   title: This is the logo
   details: Nothing else to say

The homepage is now completed and updated and it should look like this: Vitepress homepage with redesign

Please note that what we did on the homepage is just changing the markdown front matter of the "home" layout. What this means is that if you want to, you can easily customise the page further by either adding more blocks to the layout file or actually by writing and styling the rest of the page as normal.

Site configuration

In this step, we are going learn about the main site configuration and how we can use it to customize our site.

The configuration file can be found in the .vitepress folder under the name of "config.mjs".

Just like the homepage layout, the configuration used in the preset file is self-explanatory:

import { defineConfig } from 'vitepress'

// https://vitepress.dev/reference/site-config
export default defineConfig({
 title: "Vitepress tutorial",
 description: "A VitePress Site",
 themeConfig: {
   // https://vitepress.dev/reference/default-theme-config
   nav: [
     { text: 'Home', link: '/' },
     { text: 'Examples', link: '/markdown-examples' }
   ],

   sidebar: [
     {
       text: 'Examples',
       items: [
         { text: 'Markdown Examples', link: '/markdown-examples' },
         { text: 'Runtime API Examples', link: '/api-examples' }
       ]
     }
   ],

   socialLinks: [
     { icon: 'github', link: 'https://github.com/vuejs/vitepress' }
   ]
 }
})

This file is very important and you are probably going to have it open at all times as it is going to be responsible for the layout of the sidebar navigations of your site.

In this section, we are going to learn how to use the Vitepress configuration file to achieve the following:

  • Modify the sidebar navigation
  • Enable Search
  • Add Favicon to your site

Modify the sidebar navigation

The sidebar is the component displayed on the left-hand side of the blog pages. This is not automatically generated, but it is manually set in this file.

You can have more than one navigation, so, for example, you could specify sidebar navigation that shows in pages that have "/blog/" within their path and another one for all markdown pages that have "/tutorials/".

Let's see how to implement this:

{
   sidebar: {
     '/blog/': [
       {
         text: 'Blog',
         items: [
           { text: 'Index', link: '/blog/' },
           { text: 'One', link: '/blog/one' }
         ]
       }
     ],

     '/tutorials/': [
       {
         text: 'Tutorial',
         items: [
           { text: 'Index', link: '/tutorials/' },
           { text: 'Two', link: '/tutorials/two' }
         ]
       }
     ]
   },
}

With the above code, there will be 2 different sidebars. One will just show if the URL includes "/blog" and the other will be displayed if the path includes "tutorials".

Clicking on the above items will give a 404 error as we do not have any pages in that specific location. Still, we can easily fix the issue by creating the two folders "blog" and "tutorial" and creating the required files within these folders in our case are "index.md" and "one.md" for the blog and "index.md" and "two.md" for tutorials.

The sidebar has further settings like the ability to create a nested tree or create collapsable menus. You can learn more by checking out the the official documentation on default theme sidebar.

No documentation or blog site is complete until a search is fully implemented on it. Luckily for us, enabling a site-wide search is extremely simple with Vitepress.

Vitepress supports two different search types: a full-text search using minisearch and Algolia based search.

In this tutorial, we are going to enable the full-text search. This is fully built-in and requires no external accounts.

To enable search, we need to add a "Search" parameter within our themeConfig and set the provider to "local". We can add this right below the socialLinks.

   socialLinks: [
     { icon: 'github', link: 'https://github.com/vuejs/vitepress' }
   ],
   search: {
     provider: 'local'
   }
 }

With just a simple config change, our site will now have a full site search working as shown below: Full site search of Vitepress

The official search documentation has further information about the look and functionality of the search.

Add Favicon to your site

Even if the site configuration is very extensive, there are times when you will need to add something within the site-wise page that is not available.

In this section we are going to learn how to add specific attributes to the <head> of our site, and specifically how to add a favicon.

To add custom values to the head, we are going to use the "head" properties available with the Vitepress configuration.

The "head" configuration is an array that accepts an array with the element type (eg. link, script, meta), and an object including all the attributes for that specific element.

So for example to replicate the following HTML:

<link rel="icon" href="/image/favicon.ico"/>

we would define the following head config:

 head: [
   [ 'link', { rel: 'icon', href: '/images/favicon.ico' } ],
 ]

We can use this technique to set up metadata and even load fonts or Google Analytics. More info in the site-config head

Writing your post

In the last section of this article, we are going to learn how to actually write a blog post and also learn how to customize the pages with JS and styles.

Writing your first page

In the previous section, we created a couple of markdown files, but they are currently empty. Let's see how to create beautiful documentation using the built-in feature of Vitepress.

In this section, we are going to work on the file stored in /blog/index.md. This file can be accessed in your browser by accessing "http://localhost:5174/blog/index.html".

Blog Frontmatter

Every file needs to have a frontmatter defined. This is used to define basic information on the page, such as the title, description, and more.

For best SEO results, it is best practice to always define a title and description for a new page. We can do this by adding the following code at the top of our file:

---
title: My Blog post title
description: My unique description
---

Frontmatter in Markdown files are delimited by the "---". In the above code, we set our title and description.

Vitepress frontmatter supports further config like lastUpdates, sidebar, outline, and more. You can find info on the frontmatter-config documentation.

Frontmatter has some global configuration, such as title and description, but also "layout specific" settings that are just available on specific layouts. This is clearly explained in the documentation.

Blog Markdown

Now that our post frontmatter is set, it is time to write the content of it. This is done using a very extensive markdown engine.

Let's start with the basics and write a heading with some text and a link as shown below:

## My heading one

My text

[link](thisdot.co)

After saving, our development environment will show the following results:

Blog post with basic markdown

Let's add a couple of headings and a table of contents to our document using [[toc]] to the top of our page:

My Table of Contents:
[[toc]]

## first heading
My text

[link](thisdot.co)

### inner heading 3

## second heading
My text

[link](thisdot.co)

The above will produce an unordered list with all our links. Table of content

The last feature that I want to share about the Vitepress markdown engine is the code editors. The markdown engine used in Vitepress offers extensive features when it comes to code rendering.

Features available are "code highlight", "code focus", external snippets loading and much more. The full list of features can be found in the markdown docs.

Let's implement a simple code snippet with a line of code focused. This can be achieved by adding "// [!code focus]" at the end of our row. Let's give it a try:

const myNewFunction = () => {
   externalApi();
   const newCode = true; // [!code focus]
   return newCode;
}

The output of this will be:

Example of code focus in Vitepress markdown

Customize your blog with Vue

In this last section, we will learn how to customize our code by adding js logic, style, and external components.

Before we begin, it is important to understand that when you use the default template of Vitepress, your pages are going to be rendered with Vue.

This means that we can expand the individual page's functionality by rendering other vue components and/or writing logic and styles directly on the page.

To better explain this concept, we are going to create a team page. Create a file called team.md within the root of our repository.

This file will be accessible on "http://localhost:5174/team.html" and will be just a simple Markdown file.

First, we set up the frontmatter as before. In this case, we have to specify an additional config called "layout". This will ensure the page has no style or components loaded such as sidebar or aside.

---
layout: page
title: My team page
---

Then we will have to create our team variable, just like a normal Vue component; we can do so by defining a script setup tag and defining the constant there.

<script setup>
import {
 VPTeamMembers
} from 'vitepress/theme'

const members = [
 {
   avatar: 'assets/logo.png',
   name: 'Simone',
   title: 'Software Architect',
   links: [
     { icon: 'github', link: 'https://github.com/#' },
     { icon: 'Twitter', link: 'https://twitter.com/#' }
   ]
 },
 {
   avatar: 'assets/logo.png',
   name: "This Dot",
   title: "Software Company"
 }
]
</script>

In the above code, we have imported the VPTeamMembers component from the vitepress/theme and defined an array of members. The values used in the members array are hardcoded, but as you may expect, you can load this information directly from an API.

We now have to use the "members" variable within our file. We can do so by writing normal JavaScript. The markdown file will evaluate the JavaScript and render it, so in the following example it will render a specific component.

## Our Team

Say hello to our awesome team.
<VPTeamMembers size="small" :members="members" />

Before we move forward we need to define some style as the page is unstyled since we have loaded the layout of "page".

Just like we did with the <script> tag, we can load a <style> tag and update our styles:

<style>
h1 {
   color: red;
}
h1, p {
   text-align: center;
}
</style>

The completed file will look like this:

---
layout: page
title: My team page
---
<script setup>
import {
 VPTeamPage,
 VPTeamPageTitle,
 VPTeamMembers
} from 'vitepress/theme'

const members = [
 {
   avatar: 'assets/logo.png',
   name: 'Simone',
   title: 'Software Architect',
   links: [
     { icon: 'github', link: 'https://github.com/#' },
     { icon: 'Twitter', link: 'https://twitter.com/#' }
   ]
 },
 {
   avatar: 'assets/logo.png',
   name: "This Dot",
   title: "Software Company"
 }
]
</script>

<style>
h2 {
   color: red;
}
h2, p {
   text-align: center;
}
</style>
## Our Team

Say hello to our awesome team.

<VPTeamMembers size="small" :members="members" />

The file above now includes:

  • A frontmatter that specifies a "page" layout
  • A script tag that loads an external component and defines a variable
  • Styles to make the page pretty
  • Markdown with a custom component

The completed team page would render the following: Customised Theme page in Vitepress

Conclusion

Vitepress is an extremely flexible static site generator. Its default theme provides you with everything you need to get started quickly. The ability to load external themes, enhance the current theme, and or write custom code within your page makes this tool extremely powerful.

In future articles, we will discover what components are available within the Default Theme and see how you can make the most of your Vitepress site but keep on coding.

This Dot is a consultancy dedicated to guiding companies through their modernization and digital transformation journeys. Specializing in replatforming, modernizing, and launching new initiatives, we stand out by taking true ownership of your engineering projects.

We love helping teams with projects that have missed their deadlines or helping keep your strategic digital initiatives on course. Check out our case studies and our clients that trust us with their engineering.

You might also like

Awesome 3D experience with VueJS and TresJS: a beginner's guide cover image

Awesome 3D experience with VueJS and TresJS: a beginner's guide

Awesome 3D experience with VueJS and TresJS: a beginner's guide Vue.js developers are renowned for raving about the ease, flexibility, and speed of development their framework offers. Tres.js builds on this love for Vue by becoming the missing piece for seamless 3D integration. As a Vue layer for Three.js, Tres.js allows you to leverage the power of Three.js, a popular 3D library, within the familiar and beloved world of Vue components. This means you can create stunning 3D graphics and animations directly within your Vue applications, all while maintaining the clean and efficient workflow you've come to expect. TresJS is a library specifically designed to make incorporating WebGL (the web's 3D graphics API) into your Vue.js projects a breeze. It boasts several key features that make 3D development with Vue a joy: - Declarative Approach: Build your 3D scenes like you would any other Vue component, leveraging the power and familiarity of Vue's syntax. This makes it intuitive and easy to reason about your 3D elements. - Powered by Vite: Experience blazing-fast development cycles with Vite's Hot Module Replacement (HMR) that keeps your scenes updated in real-time, even as your code changes. - Up-to-date Features: Tres.js stays on top of the latest Three.js releases, ensuring you have immediate access to the newest features and functionality. - Thriving Ecosystem: The Tres.js ecosystem offers many resources to enhance your development experience. This includes: - Cientos: A collection of pre-built components and helpers that extend the capabilities of Tres.js, allowing you to focus on building your scene's functionality rather than reinventing the wheel (https://cientos.tresjs.org/). - TresLeches: A powerful state management solution specifically designed for 3D applications built with Tres.js (https://tresleches.tresjs.org/). You can try TresJS online using their official Playground or on their StackBlitz starter. But now, let's dive into a quick code example to showcase the simplicity of creating a 3D scene with TresJS. Setup First, install the package: npm install @tresjs/core three And then, if you are using Typescript, be sure to install the types: npm install @types/three -D If you are using Vite, now you need to modify your vite.config.ts file in this way to make the template compiler work with the custom renderer: ` Create our Scene Imagine a 3D scene as a virtual stage. To bring this stage to life, we need a few key players working together: 1. Scene: Think of this as the container that holds everything in your 3D world. It acts as the canvas where all the objects, lights, and the camera reside, defining the overall environment. 2. Renderer: This is the magician behind the curtain, responsible for taking all the elements in your scene and translating them into what you see on the screen. It performs the complex calculations needed to transform your 3D scene into 2D pixels displayed on your browser. 3. Camera: Like a real camera, this virtual camera defines the perspective from which you view your scene. You can position and adjust the camera to zoom in, zoom out, or explore different angles within your 3D world. - To make our camera dynamic and allow canvas exploration, we are going to leverage the client's OrbitControls component. Below are our examples. You will see that we just include the component in our canvas, and it just works. 4. Objects: These actors bring your scene to life. They can be anything from simple geometric shapes like spheres and cubes to complex models like characters or buildings. You create the visual elements that tell your story by manipulating and animating these objects. Starting from the beginning: to create our Scene with TresJS we just need to use our component TresCanvas in our Vue component's template: ` The TresCanvas component is going to do some setup work behind the scenes: - It creates a WebGLRenderer that automatically updates every frame. - It sets the render loop to be called on every frame based on the browser refresh rate. Using the window-size property, we force the canvas to take the width and height of our full window. So with TresCanvas component we have created our Renderer and our Scene. Let's move to the Camera: ` We just have to add the TresPerspectiveCamera component to our scene. NOTE: It's important that all scene-related components live between the TresCanvas component. Now, only the main actor is missing, let's add some styles and our object inside the scene. Our Vue component will now look like: ` And our scene will be: A Mesh is a basic scene object in three.js, and it's used to hold the geometry and the material needed to represent a shape in 3D space. As we can see, we can achieve the same with TresJS using the TresMesh component, and between the default slots, we are just passing our object (a Box in our example). One interesting thing to notice is that we don't need to import anything. That's because TresJS automatically generates a Vue Component based on the three objects you want to use in PascalCase with a Tres prefix. Now, if we want to add some color to our object the Three.js Material class comes to help us. We need to add: ` Conclusion Tres.js not only supercharges Vue.js applications with stunning 3D graphics, but it also integrates seamlessly with Nuxt.js, enabling you to harness the performance benefits of server-side rendering (SSR) for your 3D creations. This opens the door to building exceptional web experiences that are both interactive and performant. With Tres.js, Vue.js developers can leverage a declarative approach, cutting-edge features, and a vast ecosystem to bring their immersive web visions to life. If you want to elevate your Vue.js projects with a new dimension, Tres.js is an excellent choice to explore....

How to test React custom hooks and components with Vitest cover image

How to test React custom hooks and components with Vitest

Introduction In this guide, we'll navigate through the process of testing React hooks and components using Vitest—a powerful JavaScript unit testing framework. Discover how Vitest simplifies testing setups, providing an optimal solution for both Vite-powered projects and beyond. Vitest is a javascript unit testing framework that aims to position itself as the Test Runner of choice for Vite projects and as a solid alternative even for projects not using Vite. Vitest was built primarily for Vite-powered projects, to help reduce the complexity of setting up testing with other testing frameworks like Jest. Vitest uses the same configuration of your App (through vite.config.js), sharing a common transformation pipeline during dev, build, and test time. Prerequisites This article assumes a solid understanding of React and frontend unit testing. Familiarity with tools like React Testing Library and JSDOM will enhance your grasp of the testing process with Vitest. Installation and configuration Let’s see how we can use Vitest for testing React custom hooks and components. But first, we will need to create a new project with Vite! If you already have an existing project, you can skip this step. ` Follow the prompts to create a new React project successfully. For testing, we need the following dependencies installed: Vitest as the unit testing framework JSDOM as the DOM environment for running our tests React Testing Library as the React testing utilities. To do so, we run the following command: ` Once we have those packages installed, we need to configure the vite.config.js file to run tests. By default, some of the extra configs we need to set up Vitest are not available in the Vite config types, so we will need the vite.config.ts file to reference Vitest types by adding /// reference types=”vitest” /> at the top of the file. Add the following code to the vite.config.ts ` We set globals to true because, by default, Vitest does not provide global APIs for explicitness. So with this set to true, we can use keywords like describe, test and it without needing to import them. To get TypeScript working with the global APIs, add vitest/globals to the types field in your tsconfig.json. ` The environment property tells Vitest which environment to run the test. We are using jsdom as the environment. The root property tells Vitest the root folder from where it should start looking for test files. We should add a script for running the test in package.json ` With all that configured, we can now start writing unit tests for customs hooks and React components. Writing test for custom hooks Let’s write a test for a simple useCounter hook that takes an initial value and returns the value, an increment function and a decrement function. ` We can write a test to check the default return values of the hook for value as below: ` To test if the hook works when we increment the value, we can use the act() method from @testing-library/react to simulate the increment function, as shown in the below test case: ` Kindly Note that you can't destructure the reactive properties of the result.current instance, or they will lose their reactivity. Testing hooks with asynchronous logic Now let’s test a more complex logic that contains asynchronous logic. Let’s write a useProducts hook that fetches data from an external api and return that value ` Now, let’s see what the test looks like: ` In the above example, we had to spy on the global fetch API, so that we can mock its return value. We wrapped that inside a beforeAll so that this runs before any test in this file. Then we added an afterAll method and called the mockRestore() to run after all test cases have been completed and return all mock implementations to their original function. We can also use the mockClear() method to clear all the mock's information, such as the number of calls and the mock's results. This method is handy when mocking the same function with different return values for different tests. We usually use mockClear() in beforeEach() or afterEach() methods to ensure our test is isolated completely. Then in our test case, we used a waitFor(), to wait for the return value to be resolved. Writing test for components Like Jest, Vitest provides assertion methods (matchers) to use with the expect methods for asserting values, but to test DOM elements easily, we will need to make use of custom matchers such as toBeInTheDocument() or toHaveTextContent(). Luckily the Vitest API is mostly compatible with the Jest API, making it possible to reuse many tools originally built for Jest. For such methods, we can install the @testing-library/jest-dom package and extend the expect method from Vitest to include the assertion methods in matchers from this package. ` After installing the jest-dom testing library package, create a file named vitest-setup.ts on the root of the project and import the following into the project to extend js-dom custom matchers: ` Since we are using typescript, we also need to include our setup file in our tsconfig.json: ` In vite.config.ts, we need to add the vitest-setup.ts file to the test.setupFiles field: ` Now let’s test the Products.tsx component: ` We start by spying and mocking the useProducts hook with vi.spyOn() method from Vitest: ` Now, we render the Products component using the render method from @testing-library/react and assert that the component renders the list of products as expected and also the product has the title as follows: ` In the above code, we use the render method from @testing-library/react to render the component and this returns some useful methods we can use to extract information from the component like getByTestId and getByText. The getByTestId method will retrieve the element whose data-testid attribute value equals product-list, and we can then assert its children to equal the length of our mocked items array. Using data-testid attribute values is a good practice for identifying a DOM element for testing purposes and avoiding affecting the component's implementation in production and tests. We also used the getByText method to find a text in the rendered component. We were able to call the toBeInTheDocument() because we extended the matchers to work with Vitest earlier. Here is what the full test looks like: ` Conclusion In this article, we delved into the world of testing React hooks and components using Vitest, a versatile JavaScript unit testing framework. We walked through the installation and configuration process, ensuring compatibility with React, JSDOM, and React Testing Library. The comprehensive guide covered writing tests for custom hooks, including handling asynchronous logic, and testing React components, leveraging custom matchers for DOM assertions. By adopting Vitest, developers can streamline the testing process for their React applications, whether powered by Vite or not. The framework's seamless integration with Vite projects simplifies the setup, reducing the complexities associated with other testing tools like Jest....

History of Mobile Web Development and the rise of PWA cover image

History of Mobile Web Development and the rise of PWA

If you're in your thirties, like me, or older, you know that mobile phones have not always been so ubiquitous. In this article, we are going to cover the history of the mobile phone, and more specifically "Web Development", by focusing on the rise and benefits of PWAs. The article is going to be divided in the following sections: - History of the Mobile Phone - The evolution of Mobile Web Development - The Rise of PWA (Progressive Web App) History of the Smart Phone It is hard to remember a time when we all lived without smart phones in our pockets. How about when mobile phones could not be called "smart" since they had a single purpose: to make calls? Let's travel in time, and cover the main milestones that shaped our beloved handsets. March 1991 Even if it feels like ancient history, the story of mobile phones starts just shy of the millenium's turn. Phones started to become everyday accessories in the last decade of the 20th Century, with the first ever phone call on GSM network being made on March 1991. 1996 During their first few years of existence, phones rapidly advanced. In 1996, Nokia released the first phone with access to the "mobile web". 1998 1998 did not have any specific technological breakthroughs, but in my opinion, it marks the creation of a new industry: premium downloadable content. You may be curiuous to know which app was the first to be downloaded, but here, we are not talking about any app, as the phones did not even have web browsers yet. The first content to be sold were ringtones. This is one of the most succesful (and annoying) ringtone of the early 2000s "crazy frog": {% youtube awAKzaGrrbY %} 1999 Right before the end of the decade, phones reached another very important milesone. In this year, the first version of a mobile specific web browser was created, and our handsets were connected to the World Wide Web. 2000-2007 If I would have to list all the great phones and enhancements of these few years, this blogpost would become a book. Phones started to get much smarter. There were multiple improvements, from the size of the devices, to the signal coverage, all the way up to improved services, such as colored screens and cameras. All of the above made consumers interested in the products, and more and more people started to use them. Making it a very profitable market to invest in. 2007 The fast growth of this market made Apple decide to move into this growing sector. In the year 2007 Steve Jobs release the company's first mobile device: the Iphone. The Iphone was the first mobile interface to be completely touch-based. This was a big evolution, not only in terms of user experience, but also on the web development side. 2007+ Following the Iphone, all major companies of the time, such as Blackberry, and Nokia, started to emulate the success of Apple, and consumers were inundated with different devices every year. By the end of this decade, Mobile Phones were common devices for adults and teenagers, and have since developed and improved to what we have today. The evolution of Mobile Web Development Now that we have covered the actual evolution of our beloved handsets in terms of hardware, it is time to go back in time again to analyze the evolution of "mobile web development". As shown from the above section, the "web" made its first apprearance on Mobile phones in 1999. WML - 1999 I never had a chance to develop a mobile site in the late 90s. If I had, I would have had to use WML (Wireless Markup Language). This language (now obsolete), started to provide powerful features (link, forms, image, etc..), and was based on XML. Mobile development was specific, as this language was specific to devices that implemented the WAP (Wireless Application Protocol). The use of these sites on desktop was limited, or required the use of browser extensions. cHTML / iHTML - 1999 The browser capabilities on mobile phones developed quite quickly. Devices started to have access to subsets of HTML (cHTML and iHTML). This allowed developers to be able to create one asset (HTML) and serve a multitude of users, both on mobile and desktop. M.dot Mobile phone resolution was quite low, and phones in this period did not have touchscreens, making it difficult to surf the wed. To help in this matter, the industry respondend by utilizing what was called M.Dot methodology. This allowed a website to have two different entities, on two separate Urls. For example, if your site was myShop.com, when accessed from a mobile phone, you would have redirected users to m.myShop.com. Having different websites, allowed the developer to "eliminate" surplus content, and create a design that was more suited for the hardware of the time. This "duplication" came, of course, with a big development cost price tag. Native - 2008 The App store, and the Google Play store, were release in 2008. These events marked the beginning of a completely new industry. Internet speed on phones was very slow, and the price of data usage was still quite high. This enabled many companies to specialize in Native App development. These apps provided a quick and smooth experience to users, but with a great cost factor in terms of development and specialization. The distinct programming languages, and methodology needed to create Native Apps, was so wide across different devices, that many companies decided to specialize in a specific platform (Android, Apple or Windows). Native applications had the possibility to "connect" with the device, in unique ways, by having access to a huge set of APIs (eg. Push notification, background sync, use device space, etc..) Responsive Web design - 2008 But with the rise of Native App, another methodology started to gain traction: Responsive Web Design. This approach allowed the same website to render well on a variety of devices. Using this approach made the use of M.Dot methodology obsolete, and helped many companies save thousands of dollars in Native development. Unfortunately, "web apps" built this way would just be simple websites, and would require the user to access the internet, and specifically access the site URL. Hybrid App development - 2010 Responsive web design never managed to fully respond to customer requests. This was most likely due to the look and feel of the app being somehow different from a Native app. As phones developed, the gap between Native and Web Based widened, as the latter was not able to use many of the in-built features. In 2010, PhoneGap was revealed (currently known as Apache Cordova). This sofware enabled the development of applications using known web skills (html, css, javascript) to build Native Applications. More software followed this trend, enabling companies to start in-house development of Native Apps, without the need to incur high costs. PWA - NOW The last decade has been a roller coaster, as companies were torn among the use of Native app, Hybrid solutions, and responsive designs. In recent years, a new contender, or more precisely described as an upgrade of the Web App, entered the ring. This is known as the Progressive Web App (PWA). The primary intent of PWAs is to reduce the gap between web development and Native apps, by enchancing the user experience. In the next section, we are going to cover why the industry is responsing so positively to PWAs, and provide you useful insight to help you get up to speed with this methodology. The Rise of PWA (Progressive Web App) As you may have probably noticed from the way I speak about PWAs, I am personally really excited about this methodology, and in this section, we are going to explain the reason behind my interest in this technology. Feels like "home" First and foremost, the main advantage of PWAs is the ability for our websites/web application to be downloaded as real applications. When a website is fully setup as a PWA, mobile users are prompted with a "install now" action. Doing this will allow specific content (manually set as part of the PWA setting) to be downloaded directly on the phone, by allowing extremely quick load times and more. Furthermore, installing a PWA will also add it directly to the main mobile interface (homescreen), making it feel like a Native App. Be connected If you own a business, you are fully aware that connecting with the customer is essential. Therefore, if your customers are using your services online, being able to interact, and catch their attention, is vital. One of the main benefits of Native and Hybrid apps, as previously mentioned, was the ability to access the multitude of APIs offered by our handset. Thanks to PWAs, and more specifically to the use of a service worker, we will be able to make use of this powerful feature. Two of the most important features available on Web applications are: - Sync notification: Ability to sync your data, even if the app is not running. This is essential to provide quick content to your user. - Push notification: Ability to provide an alert to the customer, even if the app is not running ( eg. New notification in a specific app, or a reminder to use the app) It is true that the list of avaialble APIs is still small compared to that of Native implementation, but the community is working extremely hard to reduce this gap. Write for Web, serve on mobile When we previously covered RWD, we highlighted one ot its biggest advantages: being able to develop one single interface to serve a multitude of devices. PWAs offer the same advantages, with the added feature of providing the ability to display fullscreen like a "real app". This feature (part of the display setting of PWA) allows your app to take the full screen. This not only increases the space available to your app, but it also enhances the User Experience, by making sure the customer is not distracted by the "url" bar, by providing a "native look and feel". Additionally, we should highlight that the front end industry has seen a big rise in the use of frameworks, such as Vue, React, and Angular. The development of applications with "component based" architectures has supported the rise of theUI component library which is: > A cloud-based folder that consists of all the designed/styled parts of a website or piece of software. It helps designers to work in a consistent way and becomes very time efficient when executed correctly. The use of these libraries (most available for free), have supported the development of nice looking applications across multiple devices, without the need to develop all individual elements from scratch. Ready for shopping In recent months, the Google Play Store has supported PWAs as shown by this article. This service, though still in its early stages of implementation, provides a reassuring signal for the future of PWAs. You may be thinking, what about the Apple Store? Unfortuantely, Apple has not disclosed any information about PWA adoptation, but recent signals, highlighted in this medium article, show Apple's support of PWA development. At a fraction of the cost Unfortuantely, when it comes to business, cost is usually the most important factor. To further emphasise the above point, where we shared the introduction and use of "component based" architecture for speed, we also need to talk about development cost. There are three main aspects of PWAs that help reduce cost: - Existing skills - Development speed - Re-usability Existing skills Apart from some tinkering, and the introduction of the service worker, PWAs are just simple websites. They would allow a multitude of in-house development teams to be able to carry out development and/or support mobile apps, reducing the need to pay third party companies. Development speed As already mentioned above, component based achitectures, and the multitude of available community based components, have provided frontend developers the ability to quickly build performant PWAs in record time. Re-usability Many companies fail to quantify the financial savings produced by being able to re-use existing features. In a recent project I was involved with, we were able to transition from a Native App (supported by a third party company), to a fully in-house build PWA in record time, all thanks to the reusability of their Vue domponents! Versioning I have read many different articles that introduced PWAw, but I have personally learned this last point though experience. Until now, you would have never associated the word "versioning" with a website, but thanks to PWAs, this ability is also possible for web based applications. The main reason behind the need for versioning is purely technical, but its existence within PWAs is surely favorable to the many "Native" developers wanting to swap. Conclusion The war for Mobile Application domination is still on, but I personally believe that PWAs will hold a big share of the market within the next few years. Most of the advantages that support Native and Hybrid development, such as APIs, Native-look and feel, and the ability to publish within the big stores, are slowly being added to Web App. Even if Native applications are not going anytime soon, as there are many use cases that require its full control of the handset API,I believe that in the next few years, PWAs will become the standard choice for most in the mobile industry....

The simplicity of deploying an MCP server on Vercel cover image

The simplicity of deploying an MCP server on Vercel

The current Model Context Protocol (MCP) spec is shifting developers toward lightweight, stateless servers that serve as tool providers for LLM agents. These MCP servers communicate over HTTP, with OAuth handled clientside. Vercel’s infrastructure makes it easy to iterate quickly and ship agentic AI tools without overhead. Example of Lightweight MCP Server Design At This Dot Labs, we built an MCP server that leverages the DocuSign Navigator API. The tools, like `get_agreements`, make a request to the DocuSign API to fetch data and then respond in an LLM-friendly way. ` Before the MCP can request anything, it needs to guide the client on how to kick off OAuth. This involves providing some MCP spec metadata API endpoints that include necessary information about where to obtain authorization tokens and what resources it can access. By understanding these details, the client can seamlessly initiate the OAuth process, ensuring secure and efficient data access. The Oauth flow begins when the user's LLM client makes a request without a valid auth token. In this case they’ll get a 401 response from our server with a WWW-Authenticate header, and then the client will leverage the metadata we exposed to discover the authorization server. Next, the OAuth flow kicks off directly with Docusign as directed by the metadata. Once the client has the token, it passes it in the Authorization header for tool requests to the API. ` This minimal set of API routes enables me to fetch Docusign Navigator data using natural language in my agent chat interface. Deployment Options I deployed this MCP server two different ways: as a Fastify backend and then by Vercel functions. Seeing how simple my Fastify MCP server was, and not really having a plan for deployment yet, I was eager to rewrite it for Vercel. The case for Vercel: * My own familiarity with Next.js API deployment * Fit for architecture * The extremely simple deployment process * Deploy previews (the eternal Vercel customer conversion feature, IMO) Previews of unfamiliar territory Did you know that the MCP spec doesn’t “just work” for use as ChatGPT tooling? Neither did I, and I had to experiment to prove out requirements that I was unfamiliar with. Part of moving fast for me was just deploying Vercel previews right out of the CLI so I could test my API as a Connector in ChatGPT. This was a great workflow for me, and invaluable for the team in code review. Stuff I’m Not Worried About Vercel’s mcp-handler package made setup effortless by abstracting away some of the complexity of implementing the MCP server. It gives you a drop-in way to define tools, setup https-streaming, and handle Oauth. By building on Vercel’s ecosystem, I can focus entirely on shipping my product without worrying about deployment, scaling, or server management. Everything just works. ` A Brief Case for MCP on Next.js Building an API without Next.js on Vercel is straightforward. Though, I’d be happy deploying this as a Next.js app, with the frontend features serving as the documentation, or the tools being a part of your website's agentic capabilities. Overall, this lowers the barrier to building any MCP you want for yourself, and I think that’s cool. Conclusion I'll avoid quoting Vercel documentation in this post. AI tooling is a critical component of this natural language UI, and we just want to ship. I declare Vercel is excellent for stateless MCP servers served over http....

Let's innovate together!

We're ready to be your trusted technical partners in your digital innovation journey.

Whether it's modernization or custom software solutions, our team of experts can guide you through best practices and how to build scalable, performant software that lasts.

Prefer email? hi@thisdot.co