Writing multiple Vue components in a single file
Tags: vue, javascript, showdev
Published: 2018-09-27 12:46:23

---
title: Writing multiple Vue components in a single file
published: true
tags: vue, javascript, showdev
canonical_url: https://codewithhugo.com/writing-multiple-vue-components-in-a-single-file/
---

Writing multiple components in one file is a pattern from React where some files contain multiple components.

Some of those components are “private” to the file/exported component since no other component needs to consume them.

Here’s Swizec complaining about it:

> Creating new tiny Vue components is cumbersome, so it leads to duplicated code like this 🤨  
>   
> Booking description should be a tiny component that just gets stuff from props and maybe even lives in the same file as the Real Component.  
>   
> Used twice, but not reusable or an atom 🤔 [pic.twitter.com/6WzEO5knen](https://t.co/6WzEO5knen)
> 
> — Swizec Teller (@Swizec) [6 September 2018](https://twitter.com/Swizec/status/1037496451671019520?ref_src=twsrc%5Etfw)

<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

Since I don’t have the full code for the above, we’re just going to use the default “Hello World” component from a project scaffolded using `vue-cli` as an example.

By default there are two files, one for `App` and one for `HelloWorld` (at `src/App.vue` and `components/HelloWorld.vue`). `HelloWorld` takes a `msg` prop and renders it.

To write these in a single file, using React it might look something like this:

```jsx
const HelloWorld = ({ msg }) => (<div>
  <h1>Hello world</h1>
  <div>{msg}</div>
</div>);

const App = () => (<div id="app">
  <HelloWorld msg="Welcome to Your React App" />
</div>);

export default App;
```

Since React is “Just JavaScript” you can have multiple component definitions in one file, not export some of them (just to keep the exported component DRY).

In Vue, it’s still possible, but it’s a tiny bit more complicated since there is more than one way to achieve this:

- [Using a render function](#using-a-render-function)
- [Using Vue.component and a template](#using-vuecomponent-and-a-t    emplate)
- [Using a template and no Vue.component](#using-a-template-and-no    -vuecomponent)
  - [Vue CLI 3+](#vue-cli-3)
  - [Vue CLI < 3.0](#vue-cli--30)

Examples repo at [github.com/HugoDF/vue-multiple-components-in-sfc](https://github.com/HugoDF/vue-multiple-components-in-sfc).

## Using a render function

```html
<template>
  <div id="app">
    <HelloWorld msg="Welcome to Your Vue.js App"/>
  </div>
</template>
<script>
// inline component
const HelloWorld = {
  props: ['msg'],
  render(h) {
    return h('div', [
      h('h1', 'Hello world'),
      h('div', this.msg)
    ])
  }
};
export default {
  name: 'app',
  components: {
    HelloWorld
  }
}
</script>
<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
```

![](https://d2mxuefqeaa7sj.cloudfront.net/s_C77B3833CA1DF6A1ECE1A6427FA5D87D901D3E0465D27B32C42538222EBFCCF1_1536749104796_Screen+Shot+2018-09-12+at+11.44.47.png)

## Using Vue.component and a template

```html
<template>
  <div id="app">
    <HelloWorld msg="Welcome to Your Vue.js App"/>
  </div>
</template>
<script>
import Vue from 'vue';
// inline component with template string :+1:
const HelloWorld = Vue.component('hello-world', {
  props: ['msg'],
  template: `<div>
    <h1>Hello world</h1>
    <div>{{ this.msg }}</div>
  </div>`
});
export default {
  name: 'app',
  components: {
    HelloWorld
  }
}
</script>
<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
```

Does this work if the runtime isn’t included?

**NOPE**

```
[Vue warn]: You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.

found in

---> <HelloWorld>
        <App>
          <Root>

```

Thankfully, we can fix it using a build with the template compiler (see [https://code.luasoftware.com/tutorials/vuejs/vue-cli-3-include-runtime-compiler/):](https://code.luasoftware.com/tutorials/vuejs/vue-cli-3-include-runtime-compiler/):)Pretty much, create (if it doesn’t exist) `vue.config.js` and add:

```js
module.exports = {
  runtimeCompiler: true
};

```

As pointed out in the linked article, this adds the Vue template compiler to your bundle… which is around 10KB.Restart the dev server: `npm run serve`:

![](https://d2mxuefqeaa7sj.cloudfront.net/s_C77B3833CA1DF6A1ECE1A6427FA5D87D901D3E0465D27B32C42538222EBFCCF1_1536749628943_Screen+Shot+2018-09-12+at+11.44.47.png)

## Using a template and no Vue.component

```html
<template>
  <div id="app">
    <HelloWorld msg="Welcome to Your Vue.js App"/>
  </div>
</template>
<script>
// inline component with template string :+1:
const HelloWorld = {
  props: ['msg'],
  template: `<div>
    <h1>Hello world</h1>
    <div>{{ this.msg }}</div>
  </div>`
};
export default {
  name: 'app',
  components: {
    HelloWorld
  }
}
</script>
<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
```

Still works (if we have the right `vue.config.js` with `runtimeCompiler` enabled):

![](https://d2mxuefqeaa7sj.cloudfront.net/s_C77B3833CA1DF6A1ECE1A6427FA5D87D901D3E0465D27B32C42538222EBFCCF1_1536749695600_Screen+Shot+2018-09-12+at+11.44.47.png)

Since I don’t have the full code for the above, w# Using JSX (compiled to render functions)

We can rewrite our initial example of a render function with JSX:`App.js`:

```jsx
<template>
  <div id="app">
    <HelloWorld msg="Welcome to Your Vue.js App"/>
  </div>
</template>
<script>
// inline component with JSX
const HelloWorld = {
  props: ['msg'],
  render() {
    return (<div>
      <h1>Hello world</h1>
      <div>{this.msg}</div>
    </div>);
  } 
};

export default {
  name: 'app',
  components: {
    HelloWorld
  }
}
</script>
<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
```

### Vue CLI 3+

If you use Vue-cli greater or equal to version 3.0 you are in luck as JSX is supported.[https://scotch.io/tutorials/using-jsx-with-vue-and-why-you-should-care](https://scotch.io/tutorials/using-jsx-with-vue-and-why-you-should-care)

### Vue CLI < 3.0

You’ll need to dig around and have a look at [babel-plugin-transform-vue-jsx](https://github.com/vuejs/babel-plugin-transform-vue-jsx#usage).

I will probably involve installing the following packages:

```
npm install\
  babel-plugin-syntax-jsx\
  babel-plugin-transform-vue-jsx\
  babel-helper-vue-jsx-merge-props\
  babel-preset-env\
  --save-dev
```

Again examples repo at [github.com/HugoDF/vue-multiple-components-in-sfc](https://github.com/HugoDF/vue-multiple-components-in-sfc).

Feel free to tweet at me [@hugo\_\_df](https://twitter.com/hugo__df).

This was originally published at [https://codewithhugo.com](https://codewithhugo.com/writing-multiple-vue-components-in-a-single-file)

[Raymond Rasmusson](https://unsplash.com/@raymondrasmusson?utm_medium=referral&utm_campaign=photographer-credit&utm_content=creditBadge "Download free do whatever you want high-resolution photos from Raymond Rasmusson")