Skip to content

Vue 3 Composition API: How to Omit `.value` in refs

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.

NOTE: The "reactivity Transform" RFC has been concluded and the team has decided not to go ahead with this. The information in the following post are informative to learn what was being discussed, but will not be usable as this feature is not going to be added within the Vue framework.

In this article, we discuss how to omit .value in VueJS refs, creating APIs by converting them into reactive variables using macros.

Introduction

When Vue 3 first came around, it introduced the Composition API. The API permitted greater code re-usability, and provided a better way to organize Vue JS code. Along with the composition API came the concept of refs. To access the value of a ref, you needed to append .value to the name of the ref variable. To tackle this, the Vue team came up with a solution (Reactivity Transform) that would allow us to create reactive variables without creating refs.

Prerequisites

This article is primarily aimed at intermediate Vue 3 developers, and assumes three things:

The functionality discussed in this article is purely opt-in, and existing behavior is unnafected.

Tools needed

For this to work, you will need to be using vue@^3.2.25 and above. No additional dependencies are required. Vue 3.2.25+ ships an implementation under the package @vue/reactivity-transform. It is also integrated (with its APIs re-exported) in @vue/compiler-sfc, so most userland projects won't need to explicitly install it.

Reactivity in Vue 3

Reactivity refers to the ability to keep track of changes that occur in our applications. One such way to achieve reactivity in Vue 3 is by using refs.

Creating Refs

The syntax for creating a ref would be something along the lines of this:

import { ref } from "vue";

// By wrapping our default value (true) with a ref, we tell Vue to keep track of changes made to it
const isReading = ref(true);

This means that when the value of isReading changes, Vue knows about it, and it can keep track of the changes. This means that the UI is automatically updated whenever the value of isReading changes. In your template file, you would access the reactive value the same way you would access any variable. For example:

<template>
  <h1>{{ isReading ? "Shhh, I'm reading" : "Talk to me" }}</h1>
</template>

Using refs

That's all fine and dandy, but when you want to access or modify the value of the refs in the script, you need to append a .value at the end of it. This is because ref() wraps the actual variable(isReading) in an object that can keep track of any changes made to it.

import { ref } from "vue";

const isReading = ref(true);

// prints an object that represents the ref object that wraps isReading
console.log(isReading);

// This is how you would need to access the value of isReading
console.log(isReading.value); // prints true

Reactivity Transform

Removing the need for .value

The new Vue 3 syntax allows you to use refs without needing to use .value. To make this work, the Vue team implemented Reactivity Transform. This allows us to create reactive variables for every API that creates refs instead of using refs. This means we can use our variables without appending .value everywhere. Reactive variables do not need .value to be accessed while refs need you to append .value.

Previously, we used to write code like this

const isReading = ref(true);

console.log(isReading.value);

which can now be written like this

// Prepending $ to ref makes $ref() a macro that wraps around the original ref()
const isReading = $ref(true);

console.log(isReading); // no need to write

Behind the scenes, Vue will unwrap the $ref() and compile into the original .value syntax we are used to writing. The only difference is that this time you don't have to write isReading.value everywhere. This is particularly useful in areas where the ref created is used in multiple places within a script.

It is also worth noting that every reactivity API that returns refs will have a $-prefixed macro equivalent. These APIs include:

ref -> $ref computed -> $computed shallowRef -> $shallowRef customRef -> $customRef toRef -> $toRef

Do you need to import $ref ?

Since $ref and equivalents are macros, they do not need to be imported. However, if you would like to import them explicitly, you can do so from vue/macros.

import { $ref } from "vue/macros";

Convert an existing ref as reactive variable using $()

In situations where we have a function that returns a ref, the Vue compiler would not be able to know that the function will return a ref ahead of time. In such cases, we can wrap the function call with $() to explicitly convert it into a reactive variable.

function getIsReadingRef() {
  return ref(true);
}

const isReading = $(getIsReadingRef());

Destructuring objects of refs

Previously, if you tried to destructure an object that was a ref, the destructured variables would lose their reactivity.

Let's go with an example ref.

const getDefaultReader = () => ref({ name: "VueJS lover", timeOnPage: 30 });
// Vue will be able to tell when any part of `reader` changes
const reader = ref(getDefaultReader());

// Vue won't be able to tell when the values of `name` and `timeOnpage` change
const { name, timeOnPage } = ref(getDefaultReader());

With Reactivity transform, you can destructure the objects of refs and maintain reactivity. You do so by wrapping the value with a $().

// Vue will now be able to tell when the values of `name` and `timeOnpage` change
const { name, timeOnPage } = $(getDefaultReader());

The above code will compile to:

const __temp = getDefaultReader(),
  name = toRef(__temp, "name");
timeOnPage = toRef(__temp, "timeOnPage");

Reactive props destructuring

This example is from the original Reactivity Transform RFC.

There are two pain points with the current defineProps() usage in <script setup>

  • Similar to .value, you need to always access props as props.x in order to retain reactivity. This means you cannot destructure defineProps because the resulting destructured variables are not reactive and will not update.
  • When using the type-only props declaration, there is no easy way to declare default values for the props. We introduced the withDefaults() API for this exact purpose, but it's still clunky to use.
<script setup lang="ts">
interface Props {
  msg: string;
  count?: number;
  foo?: string;
}

const {
  msg,
  // default value just works
  count = 1,
  // local aliasing also just works
  // here we are aliasing `props.foo` to `bar`
  foo: bar,
} = defineProps<Props>();

watchEffect(() => {
  // will log whenever the props change
  console.log(msg, count, bar);
});
</script>

The above will be combined to the following in runtime.

export default {
  props: {
    msg: { type: String, required: true },
    count: { type: Number, default: 1 },
    foo: String,
  },
  setup(props) {
    watchEffect(() => {
      console.log(props.msg, props.count, props.foo);
    });
  },
};

Using $$() to retain reactivity

To get around reactivity loss in certain scenarios, the $$() macro can be used.

Retaining reactivity when passing refs as function arguments

Consider a situation where you have a function that needs to accept a reactive variable as an argument.

function trackChange(isReading: Ref<boolean>) {
  watch(isReading, (isReading) => {
    console.log("isReading changed!", isReading);
  });
}

let isReading = $ref(true);

// This will not work
trackChange(isReading);

In such a case, reactivity is lost.The reason for this is that the isReading ref is actually unwrapped into isReading.value when being passed in as the argument for trackChange, while trackChange expects an actual ref. The above code compiles to this:

import { ref } from "vue";

let isReading = ref(true);

// This is what is actually happening
trackChange(isReading.value);

To get around this, we can wrap the ref in $$(), which tells the compiler not to append a .value to it.

// This will work
trackChange($$(isReading));

The above example compiles to this:

import { ref } from "vue";

let isReading = ref(true);

// This is what we want - the isReading variable should be passed as a ref
trackChange(isReading);

Retaining reactivity when returning inside function scope

Another scenario where reactivity is lost is when we are returning reactive variables from within a function.

function useMouse() {
  let x = $ref(0);
  let y = $ref(0);

  // listen to mousemove...

  // doesn't work!
  return {
    x,
    y,
  };
}

Similar to the example with passing refs as arguments, the above return statement compiles to:

return {
  x: x.value,
  y: y.value,
};

In order to maintain the reactivity of x and y, we can wrap the entire return statement with the $$() macro.

function useMouse() {
  let x = $ref(0);
  let y = $ref(0);

  // listen to mousemove...

  // This works
  return $$({
    x,
    y,
  });
}

Retaining reactivity on destructured props

$$() works on destructured props since they are reactive variables as well. The compiler will convert it with toRef for efficiency:

const { count } = defineProps<{ count: number }>();

passAsRef($$(count));

compiles to:

setup(props) {
  const __props_count = toRef(props, 'count')
  passAsRef(__props_count)
}

TypeScript & Tooling Integration

Vue will provide typings for these macros (available globally) and all types will work as expected. There are no incompatibilities with standard TypeScript semantics, so the syntax would work with all existing tooling.

This also means the macros can work in any files where valid JS/TS are allowed - not just inside Vue SFCs.

Since the macros are available globally, their types need to be explicitly referenced (e.g. in a env.d.ts file):

/// <reference types="vue/macros-global" />

When explicitly importing the macros from vue/macros, the type will work without declaring the globals.

Conclusion

By taking advantage of the macros added to Vue 3, you can drastically clean up your codebase by getting rid of .value usage. You also get to preserve reactivity within your application when destructuring reactive variables as well as props when using the Composition API and defineProps().

If you'd like to read more on the same, you can do so in the official Vue JS RFC discussion for the feature.

I do hope you find this helpful in reducing your code footprint, and making your general life easier. The next time you think of using .value for your refs, remember that you don't have to. With that, thanks for stopping by!

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

Understanding Vue's Reactive Data cover image

Understanding Vue's Reactive Data

Introduction Web development has always been about creating dynamic experiences. One of the biggest challenges developers face is managing how data changes over time and reflecting these changes in the UI promptly and accurately. This is where Vue.js, one of the most popular JavaScript frameworks, excels with its powerful reactive data system. In this article, we dig into the heart of Vue's reactivity system. We unravel how it perfectly syncs your application UI with the underlying data state, allowing for a seamless user experience. Whether new to Vue or looking to deepen your understanding, this guide will provide a clear and concise overview of Vue's reactivity, empowering you to build more efficient and responsive Vue 3 applications. So, let’s kick off and embark on this journey to decode Vue's reactive data system. What is Vue's Reactive Data? What does it mean for data to be ”'reactive”? In essence, when data is reactive, it means that every time the data changes, all parts of the UI that rely on this data automatically update to reflect these changes. This ensures that the user is always looking at the most current state of the application. At its core, Vue's Reactive Data is like a superpower for your application data. Think of it like a mirror - whatever changes you make in your data, the user interface (UI) reflects these changes instantly, like a mirror reflecting your image. This automatic update feature is what we refer to as “reactivity”. To visualize this concept, let's use an example of a simple Vue application displaying a message on the screen: ` In this application, 'message' is a piece of data that says 'Hello Vue!'. Let's say you change this message to 'Goodbye Vue!' later in your code, like when a button is clicked. ` With Vue's reactivity, when you change your data, the UI automatically updates to 'Goodbye Vue!' instead of 'Hello Vue!'. You don't have to write extra code to make this update happen - Vue's Reactive Data system takes care of it. How does it work? Let's keep the mirror example going. Vue's Reactive Data is the mirror that reflects your data changes in the UI. But how does this mirror know when and what to reflect? That's where Vue's underlying mechanism comes into play. Vue has a behind-the-scenes mechanism that helps it stay alerted to any changes in your data. When you create a reactive data object, Vue doesn't just leave it as it is. Instead, it sends this data object through a transformation process and wraps it up in a Proxy. Proxy objects are powerful and can detect when a property is changed, updated, or deleted. Let's use our previous example: ` Consider our “message” data as a book in a library. Vue places this book (our data) within a special book cover (the Proxy). This book cover is unique - it's embedded with a tracking device that notifies Vue every time someone reads the book (accesses the data) or annotates a page (changes the data). In our example, the reactive function creates a Proxy object that wraps around our state object. When you change the 'message': ` The Proxy notices this (like a built-in alarm going off) and alerts Vue that something has changed. Vue then updates the UI to reflect this change. Let’s look deeper into what Vue is doing for us and how it transforms our object into a Proxy object. You don't have to worry about creating or managing the Proxy; Vue handles everything. ` In the example above, we encapsulate our object, in this case, “state”, converting it into a Proxy object. Note that within the second argument of the Proxy, we have two methods: a getter and a setter. The getter method is straightforward: it merely returns the value, which in this instance is “state.message” equating to 'Hello Vue!' Meanwhile, the setter method comes into play when a new value is assigned, as in the case of “state.message = ‘Hey young padawan!’”. Here, “value” becomes our new 'Hey young padawan!', prompting the property to update. This action, in turn, triggers the reactivity system, which subsequently updates the DOM. Venturing Further into the Depths If you have been paying attention to our examples above, you might have noticed that inside the Proxy method, we call the functions track and trigger to run our reactivity. Let’s try to understand a bit more about them. You see, Vue 3 reactivity data is more about Proxy objects. Let’s create a new example: ` In this example, when you click on the button, the message's value changes. This change triggers the effect function to run, as it's actively listening for any changes in its dependencies. How does the effect property know when to be called? Vue 3 has three main functions to run our reactivity: effect, track, and trigger. The effect function is like our supervisor. It steps in and takes action when our data changes – similar to our effect method, we will dive in more later. Next, we have the track function. It notes down all the important data we need to keep an eye on. In our case, this data would be state.message. Lastly, we've got the trigger function. This one is like our alarm bell. It alerts the effect function whenever our important data (the stuff track is keeping an eye on) changes. In this way, trigger, track, and effect work together to keep our Vue application reacting smoothly to changes in data. Let’s go back to them: ` Tracking (Dependency Collection) Tracking is the process of registering dependencies between reactive objects and the effects that depend on them. When a reactive property is read, it's "tracked" as a dependency of the current running effect. When we execute track(), we essentially store our effects in a Set object. But what exactly is an "effect"? If we revisit our previous example, we see that the effect method must be run whenever any property changes. This action — running the effect method in response to property changes — is what we refer to as an "Effect"! (computed property, watcher, etc.) > Note: We'll outline a basic, high-level overview of what might happen under the hood. Please note that the actual implementation is more complex and optimized, but this should give you an idea of how it works. Let’s see how it works! In our example, we have the following reactive object: ` We need a way to reference the reactive object with its effects. For that, we use a WeakMap. Which type is going to look something like this: ` We are using a WeakMap to set our object state as the target (or key). In the Vue code, they call this object targetMap. Within this targetMap object, our value is an object named depMap of Map type. Here, the keys represent our properties (in our case, that would be message and showSword), and the values correspond to their effects – remember, they are stored in a Set that in Vue 3 we refer to as dep. Huh… It might seem a bit complex, right? Let's make it more straightforward with a visual example: With the above explained, let’s see what this Track method kind of looks like and how it uses this targetMap. This method essentially is doing something like this: ` At this point, you have to be wondering, how does Vue 3 know what activeEffect should run? Vue 3 keeps track of the currently running effect by using a global variable. When an effect is executed, Vue temporarily stores a reference to it in this global variable, allowing the track function to access the currently running effect and associate it with the accessed reactive property. This global variable is called inside Vue as activeEffect. Vue 3 knows which effect is assigned to this global variable by wrapping the effects functions in a method that invokes the effect whenever a dependency changes. And yes, you guessed, that method is our effect method. ` This method behind the scenes is doing something similar to this: ` The handling of activeEffect within Vue's reactivity system is a dance of careful timing, scoping, and context preservation. Let’s go step by step on how this is working all together. When we run our Effect method for the first time, we call the get trap of the Proxy. ` When running the get trap, we have our activeEffect so we can store it as a dependency. ` This coordination ensures that when a reactive property is accessed within an effect, the track function knows which effect is responsible for that access. Trigger Method Our last method makes this Reactive system to be complete. The trigger method looks up the dependencies for the given target and key and re-runs all dependent effects. ` Conclusion Diving into Vue 3's reactivity system has been like unlocking a hidden superpower in my web development toolkit, and honestly, I've had a blast learning about it. From the rudimentary elements of reactive data and instantaneous UI updates to the intricate details involving Proxies, track and trigger functions, and effects, Vue 3's reactivity is an impressively robust framework for building dynamic and responsive applications. In our journey through Vue 3's reactivity, we've uncovered how this framework ensures real-time and precise updates to the UI. We've delved into the use of Proxies to intercept and monitor variable changes and dissected the roles of track and trigger functions, along with the 'effect' method, in facilitating seamless UI updates. Along the way, we've also discovered how Vue ingeniously manages data dependencies through sophisticated data structures like WeakMaps and Sets, offering us a glimpse into its efficient approach to change detection and UI rendering. Whether you're just starting with Vue 3 or an experienced developer looking to level up, understanding this reactivity system is a game-changer. It doesn't just streamline the development process; it enables you to create more interactive, scalable, and maintainable applications. I love Vue 3, and mastering its reactivity system has been enlightening and fun. Thanks for reading, and as always, happy coding!...

Getting started with Vitepress cover image

Getting started with Vitepress

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! 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 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: ` 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. ` 2) Update the action buttons. ` 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". 3) 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: ` The homepage is now completed and updated and it should look like this: 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: ` 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: ` 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. Enable Search 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. ` With just a simple config change, our site will now have a full site search working as shown below: 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 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: ` we would define the following head config: ` 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: ` 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: ` After saving, our development environment will show the following results: Let's add a couple of headings and a table of contents to our document using [[toc]] to the top of our page: ` The above will produce an unordered list with all our links. 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: ` The output of this will be: 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. ` 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. ` 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. ` 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 tag, we can load a tag and update our styles: ` The completed file will look like this: ` 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: 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....

Nuxt 3 Demo App with Prerender and SSR cover image

Nuxt 3 Demo App with Prerender and SSR

Introduction The quest for an optimal web application involves numerous factors, such as performance, user experience, and search engine optimization (SEO). Nuxt 3 provides excellent features out-of-the-box that can help you tackle these aspects efficiently. This article will guide you in creating a Nuxt 3 application using Server Side Rendering (SSR) and pre-rendering capabilities. We'll craft an application that offers a seamless user experience, superior performance, and improved SEO. Server Side Rendering in Nuxt 3 Enhancing User Experience and SEO with SSR In the world of web development, Server Side Rendering (SSR) has gained significant traction. It refers to the server rendering the webpage upon each request rather than the client. With SSR, your web page arrives fully formed at the client's doorstep, reducing the time for the first painting. The advantage of SSR extends beyond just performance and user experience. It's also a darling of search engine crawlers, which find it easier to index your website with fully formed page content at the time of their crawl. In simple terms, it's like providing a tour guide to lead the search engine around your website, ensuring they get all the spots! The Power of SSR in Nuxt 3 Nuxt 3 has built-in support for SSR by default. It allows you to optimize your application by loading the data before rendering the page. To take advantage of SSR, you simply build your application as you usually would. In this case, using the fetch() method to load some. ` In this example, the fetchData function fetches the data before rendering the page. The data then gets displayed within the tag. Sidenote, if you wanted to disable SSR in your Nuxt application, you would do so in your nuxt.config.ts file: `` More details on how this works can be found in the rendering modes section in the official Nuxt 3 documentation. Pre-rendering in Nuxt 3 Amplifying Application Performance with Pre-rendering While SSR has its advantages, another superhero in our story is pre-rendering. Pre-rendering refers to the process of generating the static HTML pages of a site in advance. It's like preparing a feast before the guests arrive so you can serve them promptly. Like SSR, pre-rendering enhances SEO, as search engines can index fully rendered pages. Especially for content-heavy applications, pre-rendering can give a turbo boost to performance, leading to better user engagement and retention. Leverage Pre-rendering with Nuxt 3 Nuxt 3 supports SSR and Static Site Generation (SSG), including pre-rendering. To enable prerendering, you need to export your routes in nuxt.config.ts: ` These routes will be pre-rendered during the build phase, allowing for swift navigation. Let's update our application to pre-render the users' list: ` In the nuxt.config.ts, include the users' route for pre-rendering: ` Going beyond with Nuxt 3 While SSR and pre-rendering are significant for performance and SEO, Nuxt 3 offers more advanced features like hot module replacement, Vue 3 integration, improved error handling, and more. Nuxt 3 also has different kinds of rendering modes for different applications; in our SSR case, we used the default Universal rendering mode. Leveraging these features allows you to develop robust, high-performance, and user-friendly applications. Conclusion In this article, we delved into the concepts of SSR and pre-rendering in Nuxt 3. We explored how these techniques contribute to enhancing performance, user experience, and SEO. You can create exceptional web applications by integrating Vue 3's capabilities with Nuxt 3's robust features. A well-structured, performant, and SEO-friendly application not only attract users but also retains them. Embrace the power of Nuxt 3 and Vue 3 in your development journey. Happy coding!...

Introduction to Vercel’s Flags SDK cover image

Introduction to Vercel’s Flags SDK

Introduction to Vercel’s Flags SDK In this blog, we will dig into Vercel’s Flags SDK. We'll explore how it works, highlight its key capabilities, and discuss best practices to get the most out of it. You'll also understand why you might prefer this tool over other feature flag solutions out there. And, despite its strong integration with Next.js, this SDK isn't limited to just one framework—it's fully compatible with React and SvelteKit. We'll use Next.js for examples, but feel free to follow along with the framework of your choice. Why should I use it? You might wonder, "Why should I care about yet another feature flag library?" Unlike some other solutions, Vercel's Flags SDK offers unique, practical features. It offers simplicity, flexibility, and smart patterns to help you manage feature flags quickly and efficiently. It’s simple Let's start with a basic example: ` This might look simple — and it is! — but it showcases some important features. Notice how easily we can define and call our flag without repeatedly passing context or configuration. Many other SDKs require passing the flag's name and context every single time you check a flag, like this: ` This can become tedious and error-prone, as you might accidentally use different contexts throughout your app. With the Flags SDK, you define everything once upfront, keeping things consistent across your entire application. By "context", I mean the data needed to evaluate the flag, like user details or environment settings. We'll get into more detail shortly. It’s flexible Vercel’s Flags SDK is also flexible. You can integrate it with other popular feature flag providers like LaunchDarkly or Statsig using built-in adapters. And if the provider you want to use isn’t supported yet, you can easily create your own custom adapter. While we'll use Next.js for demonstration, remember that the SDK works just as well with React or SvelteKit. Latency solutions Feature flags require definitions and context evaluations to determine their values — imagine checking conditions like, "Is the user ID equal to 12?" Typically, these evaluations involve fetching necessary information from a server, which can introduce latency. These evaluations happen through two primary functions: identify and decide. The identify function gathers the context needed for evaluation, and this context is then passed as an argument named entities to the decide function. Let's revisit our earlier example to see this clearly: ` You could add a custom evaluation context when reading a feature flag, but it’s not the best practice, and it’s not usually recommended. Using Edge Config When loading our flags, normally, these definitions and evaluation contexts get bootstrapped by making a network request and then opening a web socket listening to changes on the server. The problem is that if you do this in Serverless Functions with a short lifespan, you would need to bootstrap the definitions not just once but multiple times, which could cause latency issues. To handle latency efficiently, especially in short-lived Serverless Functions, you can use Edge Config. Edge Config stores flag definitions at the Edge, allowing super-fast retrieval via Edge Middleware or Serverless Functions, significantly reducing latency. Cookies For more complex contexts requiring network requests, avoid doing these requests directly in Edge Middleware or CDNs, as this can drastically increase latency. Edge Middleware and CDNs are fast because they avoid making network requests to the origin server. Depending on the end user’s location, accessing a distant origin can introduce significant latency. For example, a user in Tokyo might need to connect to a server in the US before the page can load. Instead, a good pattern that the Flags SDK offers us to avoid this is cookies. You could use cookies to store context data. The browser automatically sends cookies with each request in a standard format, providing consistent (no matter if you are in Edge Middleware, App Router or Page Router), low-latency access to evaluation context data: ` You can also encrypt or sign cookies for additional security from the client side. Dedupe Dedupe helps you cache function results to prevent redundant evaluations. If multiple flags rely on a common context method, like checking a user's region, Dedupe ensures the method executes only once per runtime, regardless of how many times it's invoked. Additionally, similar to cookies, the Flags SDK standardizes headers, allowing easy access to them. Let's illustrate this with the following example: ` Server-side patterns for static pages You can use feature flags on the client side, but that will lead to unnecessary loaders/skeletons or layout shifts, which are never that great. Of course, it brings benefits, like static rendering. To maintain static rendering benefits while using server-side flags, the SDK provides a method called precompute. Precompute Precompute lets you decide which page version to display based on feature flags and then we can cache that page to statically render it. You can precompute flag combinations in Middleware or Route Handlers: ` Next, inside a middleware (or route handler), we will precompute these flags and create static pages per each combination of them. ` The user will never notice this because, as we use “rewrite”, they will only see the original URL. Now, on our page, we “invoke” our flags, sending the code from the params: ` By sending our code, we are not really invoking the flag again but getting the value right away. Our middleware is deciding which variation of our pages to display to the user. Finally, after rendering our page, we can enable Incremental Static Regeneration (ISR). ISR allows us to cache the page and serve it statically for subsequent user requests: ` Using precompute is particularly beneficial when enabling ISR for pages that depend on flags whose values cannot be determined at build time. Headers, geo, etc., we can’t know their value at build, so we use precompute() so the Edge can evaluate it on the fly. In these cases, we rely on Middleware to dynamically determine the flag values, generate the HTML content once, and then cache it. At build time, we simply create an initial HTML shell. Generate Permutations If we prefer to generate static pages at build-time instead of runtime, we can use the generatePermutations function from the Flags SDK. This method enables us to pre-generate static pages with different combinations of flags at build time. It's especially useful when the flag values are known beforehand. For example, scenarios involving A/B testing and a marketing site with a single on/off banner flag are ideal use cases. ` ` Conclusion Vercel’s Flags SDK stands out as a powerful yet straightforward solution for managing feature flags efficiently. With its ease of use, remarkable flexibility, and effective patterns for reducing latency, this SDK streamlines the development process and enhances your app’s performance. Whether you're building a Next.js, React, or SvelteKit application, the Flags SDK provides intuitive tools that keep your application consistent, responsive, and maintainable. Give it a try, and see firsthand how it can simplify your feature management workflow!...

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