Understanding Vue.js Single-File Components (SFCs)
Tags: vue, javascript, webdev, beginners
Published: 2023-03-29 23:39:10

---
title: Understanding Vue.js Single-File Components (SFCs)
published: true
description: An in-depth guide into understanding Vue.js Single-File Components, including their syntax and the script setup sugar.
tags: vue, javascript, webdev, beginners
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f3lrnn9asf2f1rezpnk3.png
series: A beginner's guide to Vue.js
canonical_url: https://vuenoob.com/posts/understanding-vue-js-single-file-components-sfcs/
---

If you have been reading these posts in chronological order, you know that up to this point, we’ve been creating and running our Vue.js apps inside HTML pages as part of page scripts.
Vue.js gives us the freedom to create apps in this way, depending on the extent of features we are expecting our Vue.js apps to have within the apps we are building.

We have seen that, Vue.js can serve the purpose of adding atomic features within other apps/HTML pages, for example, it can be used in the search bar section of a website only, sending search requests, and displaying results per the inserted queries.

But, there are cases where we need to build fully-fledged Vue.js apps with whole sets of features such as routing, state management, etc. Such apps normally involve writing a lot of Vue.js code, and, as it's expected in such instances, we get large files containing lots of code which normally leads to all sorts of code maintenance issues down the line.

To avoid these imminent time and resource-consuming troubles, we normally break down code into smaller manageable and dependent chunks as we’ve seen with [the Vue.js components](https://vuenoob.com/posts/vuejs-components-reusing-code-in-vue/).

But, the scenario we’re referring to here goes beyond breaking down Vue.js apps into smaller components, but further into independent files called Vue.js Single-File Components (SFCs) that are by themselves fully-fledged and pluggable Vue.js apps.

Here are some of the benefits of using Vue.js SFC files:
- The improvement to developer experience, by encouraging the use of build tools that do the heavy lifting for us aiding in the automation of tasks such as code prettifying, linting, and minification for production to facilitate the making of light deployment bundles, best practices and so forth.
- We can easily re-use SFCs within other apps where we would want to re-implement related features and avoid re-writing code.
- We can bundle components and create sharable plugins, facilitating the sharing of code with other developers. This is a very beneficial practice in software development since when fixes are made or features are added they are easily distributed to all apps these plugins are used in.
- The grouping of all code (logic, template, and styling) related to a single function within a single file simplifies the management of our apps and their independent features.

The Vue.js SFC files have a unique `.vue` file extension which is supported by all major IDEs, text editors, and several plugins that help highlight the Vue.js code and apply code intellisense to it.

## Working with Vue.js Single-File Components(SFCs)

To see the syntax and work with Vue.js SFCs, you’ll first need to scaffold a Vue.js project that’s [managed with a build tool](/how-to/run-vue-js-code-locally/#with-build-tools) called [Vite](https://vitejs.dev).

We’ll work with Vite but won’t place much focus on it in this post, more of its specifics will be learned in the future, for now, all we need is to understand that it’s a build tool for front-end JavaScript frameworks.

> Before proceeding make sure that you have the [latest LTS version of node.js](https://nodejs.org/en/download) installed into your system.

Run the following command on the terminal to create a new Vue.js project directory.

```sh
mkdir vue-sfc-app
```

When this command terminates, well should have a new directory named `vue-sfc-app`. Switch the active terminal location into it by running `cd vue-sfc-app`.

Inside the project directory, run `npm init -y` to make this directory the root of a new JavaScript project. This command adds a `package.json` file, which simply is a project’s metadata file that keeps a manifest of our dependencies, scripts, etc. To read more about this file, you can visit its [docs](http://docs.npmjs.com/cli/v6/configuring-npm/package.json).

So far, this will be the project’s directory layout:

```sh
.
├── package.json
```

Here’s what’s contained in the `package.json` file so far.

```json
{
  “name”: “vue-sfc-app”,
  “version”: “1.0.0”,
  “description”: “”,
  “main”: “index.js”,
  “scripts”: {
    “test”: “echo \”Error: no test specified\” && exit 1”
  },
  “keywords”: [],
  “author”: “”,
  “license”: “ISC”
}
```

Add a `”type”: “module”` property to this file and keep in mind of what is contained in it.

Run the following commands on the terminal.

```sh
npm install vue

npm install -D vite @vitejs/plugin-vue
```

The first command installs the Vue.js npm package (providing us with the Vue.js library code). The second command installs Vite and its plugin for Vue.js. The two latter dependencies will handle our local development environment with tasks such as compiling the SFC files and serving the app locally so that we can only focus on building our app.

After these two files have been installed, you should notice a new directory: `node_modules` that has been added to your project. This is where the dependencies' source code is stored, we usually don’t make modifications to anything within it.

When you go back to the `package.json` file, you will notice some changes, two new sections `dependencies` and `devDependencies` with the respective dependencies and their installed versions will have been added.

```json
  ...
  “devDependencies”: {
    “@vitejs/plugin-vue”: “^[SEMANTIC-VERSION]”,
    “vite”: “^[SEMANTIC-VERSION]”
  },
  “dependencies”: {
    “vue”: “^[SEMANTIC-VERSION]”
  }
  ...
```

Add three files to our project - `index.html`,  `index.js`, and `vite.config.js`. Place the following code within these files respectively.

```html
<!-- index.html -->
<html>
    <head>
        <title>Vue SFC App</title>
    </head>
    <body>
        <div id=“app”></div>
        <script type=“module” src=“/index.js”></script>
    </body>
</html>
```

```js
// index.js
import { createApp } from “vue”;
import App from “./App.vue”

const app = createApp(App).mount(“#app”)
```

```js
// vite.config.js
import { defineConfig } from “vite”;
import vue from “@vitejs/plugin-vue”;

export default defineConfig({
    plugins: [vue()]
});
```

In the `index.js` file, we have initiated the Vue.js app in a familiar format, passing a Vue.js SFC file - `App.vue` inside the `createApp()` function.

In the `index.html` file, we have normal HTML markup out-sourcing the JavaScript code from the `index.js` file.

The `vite.config.js` file is a special file in projects managed with Vite where the configuration of the tool can be done. What we’ve done in this file is pass the plugin file so that Vite knows what to do when it encounters Vue.js code and files within the project.

We need to add a script inside the `package.json` to fire up the local server using commands provided by Vite and view what our project looks like.

Inside the `scripts` section of the `package.json` file, add a new `dev` script as follows.

```json
  “scripts”: {
    “test”: “echo \”Error: no test specified\” && exit 1”,
    “dev”: “vite”
  },
```

Now, run `npm run dev --port 3000` on the terminal. This should launch a local server on the `3000` port if it’s not occupied - `localhost:3000`. Try visiting it on the browser. 

If you see the following error, then everything went to plan. 

![Vue.js missing component error.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1dg8ay90qzi99hswqh4a.jpg)

In this error, Vite is simply telling us that it failed to find the `App.vue` SFC file, which is true since we never created it.

Go ahead and create it. Adding the following code inside.

```jsx
<template>
    <div>
        He{{ 1 + ‘1’ }}o World!
    </div>
</template>
```

Vite will handle hot-reloading for our website, and we should see “He11o World!” on our browser.

## Anatomy of a Vue.js SFC file

Vue.js SFCs are just HTML files without the `<head>` section and with a `<template>` section replacing the familiar HTML `<body>`.
In general, they are made up of 3 sections, a `<template>` where the UI markup would be placed (Like in the example above), the component’s JavaScript logic placed between the `<script>` tags, and a `<style>` section where the component's styles would be placed.

We have seen something close to this syntax when learning about [Vue.js components](https://vuenoob.com/posts/vuejs-components-reusing-code-in-vue/) because in context, this is the same thing but within an independent file.

Let’s place the `1 + ‘1’` in a computed variable to see the component’s JavaScript section’s syntax.

```html
<script>
export default {
    computed: {
        doubleL() {
            return 1 + ‘1’;
        }
    }
}
</script>
```

When the page refreshes, no changes would have been made to the page since we’re still employing the same logic.

Let’s see another example.
Add the following button to the template.

```html
<button @click=“increment()”>Clicks {{ count }}</button>
```

And, update the `<script>` section by adding the `data` and `methods` options.

```js
    data() {
        return {
            count: 0
        }
    },
    methods: {
        increment(){
            this.count++
        }
    }
```

We should now see the following on our page.

![Counting button clicks](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0nay5w9adld92fsr0kj6.gif)

To add a bit of space between our HTML blocks, we can add some styling to the component inside the `<style>` section like this.

```html
<style scoped>
div, button{
    padding: 5px;
    margin: 5px
}
button{
    color: red;
    font-weight: 800;
}
</style>
```

And, this is how the page would look afterward.

![Styled component](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h1igb3cn6zt7d592eu5r.gif)

The `scoped` attribute on the `<style>` tag above instructs Vue.js to apply the styles within this component only and not elsewhere, when not placed, this component's style will be applied to the global context of the app.


## The `<script setup>` sugar syntax in Vue.js SFCs

With Vue.js 3 (and v2.7), Vue introduced a new API to the framework - the [composition API](https://vuejs.org/guide/extras/composition-api-faq.html#what-is-composition-api), which is a set of APIs that allows us to author Vue.js components using imported functions instead of declaring options, a practice we’ve been doing when authoring our Vue.js components up to this moment. The [Options API](https://vuejs.org/guide/typescript/options-api.html#typing-component-props) is still available for use as we’ve demonstrated in all our examples.

With the Composition API, options such as `data` within our components would be replaced by the `ref()` or `reactive()` functions, native javaScript functions would be favored in place of the `methods` and `filters` options, and `computed` would be replaced with the `onComputed()` function. All the hooks would be placed with functions prefixed with `on` in the camel-case format, for example, the `mounted`, `beforeUpdate`, and `unmounted` hooks would be replaced with `onMounted()`, `onBeforeUpdate()`, and `onUnmounted()` composition functions respectively.

The `<script setup>` sugar was later introduced to facilitate a more succinct and ergonomic syntax for SFCs.

Let’s see an example by converting our `App.vue` component above.

```js
import {computed, ref} from “vue”
let count = ref(0)
const doubleL = computed(() => 1 + ‘1’)

function increment(){
    count.value++
}
```

The `ref()` function, as demonstrated above, is used to make variables reactive. To test out the reactivity, try replacing the `ref(0)` with `0` and `count.value++` with `count++` to see if the count would increment on button clicks.

`ref()` takes an inner value passed to it and returns a reactive and mutable ref object that has a single property - `.value` that points to the inner value. This is the reason we are using `count.value` and not `count` inside the `increment()` function to mutate count.
Inside the template, we do not need to use `.value` as Vue.js automatically handles that.

For our computed variable `doubleL` we pass a getter function that also returns a reactive `ref` object, meaning, if we were to access its value within the JavaScript section of our app, we would use `.value`.

We can refactor `doubleL` in this instance, to free up resources used by using a constant instead of the computed property, since its value is not mutated or needed as a dependency somewhere else.

```js
Const doubleL = 1 + ‘1’
```

Some obvious benefits we see in the conversion of the `App.vue` component to the Composition API are the reduction in the code footprint, and more application of native JavaScript, though, we do lose a bit of structure.
For more on the Composition API, you can read the [Vue.js official docs on the topic](https://vuejs.org/guide/extras/composition-api-faq.html#what-is-composition-api).

### Binding SFC component state to styles

With Vue.js SFCs, we can link CSS values to the reactive component state using the `v-bind()` CSS function.

Let’s bind `count` to the margin value within our styles.

```css
div, button{
    padding: 5px;
    margin: v-bind(count + “px”)
}
```

When clicking the button we should see the following effect.

![Binding CSS values to component state](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ntqm29sqt1851wlw7z28.gif)

N.B., To see the source code for the Vue.js SFC project we’ve just created visit [this GitHub repository](https://github.com/vuenoob/vue-sfc-app).

## Summary

To summarise, we’ve learned the following in this post:
- Setting up a Vue.js project using build tools, in this case - Vite.
- Creating and working with Vue.js’ Single-File Components (SFCs).
- Understood the syntax and functionality within each section of an SFC. 
- We’ve been introduced to Vue.js composition API and some popular functions we’ll be using while building interfaces with Vue.js 3.
- Learned about how to use the `<script setup>` sugar within Vue.js SFC files.
- We’ve also seen how we can bind the component state to CSS values to render creative effects within our UIs.

For more on Vue.js Single-File Components, read the [official Vue.js docs](https://vuejs.org/api/sfc-spec.html).