Rutger Willems

@rut.willems

Learn to manage large Vue.js components in 4 min

Vue.js is, in my opinion, the nicest JS framework currently available. One of the features I like the most are the .vue single-file components. It can get quite hard to manage larger ones tough, especially when you start creating custom sub-components and adding static assets. Here are some things I’ve tried, you might like them too.

Figure 1: You when handling large components before reading this post.

Some quick basics

This might be common knowledge to you but just in case:

  • Use PascalCase file naming.
    Example: ComponentName.vue 
    doc reference
  • Preface base components with a default word like App, Base or V.
    Example: AppTable.vue 
    doc reference
  • Preface components with a max of one active instance with The.
    Example: TheLargeComponent.vue 
    doc reference
  • Always use multi-word names for your components. Prefacing App or The simplifies this but do this for all components. This is to avoid clashes with standard HTML tags which are always a single word.
    Example: MainModal.vue instead of Modal.vue 
    doc reference

How it is often done.

I’ve seen this all too often, and with large projects this becomes a nightmare. All components are in the components folder, all assets are in a central assets folder and single-instance child components are only indicated by prefacing the name of it’s parent (this gets super fun after 2 layers). Often this looks a little like this:

components
|--LargeComponent.vue
|--LargeComponentModal.vue
|--LargeComponentModalTextSection.vue
|--LargeComponentModalTextSectionTitle.vue
|--LargeComponentModalButton.vue
|--LargeComponentModalButtonText.vue
assets
|--img
| |--large-component-banner.png
| |--large-component-button-bg.png

OK, so this obviously gets cluttered fast, how do we fix this? Let’s get to the first option!

1. Putting the component in it’s own folder.

One of the first options I tried. Name the folder LargeComponent and put the original component in it. You can do two things here.

First you can name the component index.vue which probably works in your build system and has the great benefit of not changing your import statements. This is really really handy but a very hacky and not the most stable solution. Note: this does not work if you are specifying the file extension in your imports like LargeComponent.vue

components
|--LargeComponent
| |--index.vue
| |--components
| | |--LargeComponentModal.vue
| |--assets
| | |--img
| | | |--banner.png

Secondly you could just name it after it’s parent folder and thus keep it LargeComponent.vue which is probably the wisest choice here. This does change the import from ./components/LargeComponent to ./components/LargeComponent/LargeComponent which isn’t ideal.

Pro’s

  • All items in the components folder indicate and represent a component.
  • Easy to understand for other dev’s.
  • Sub-components and assets can be imported with clean relative imports: ./assets/img/banner.png

Secondly an approach which looks very much like this one and probably the most straightforward one:

2. Putting the folder alongside the vue component.

This solution has no problem with specifying the file extension and does not change the imports.

components
|--LargeComponent.vue
|--LargeComponent
| |--components
| | |--LargeComponentModal.vue
| |--assets
| | |--img
| | | |--banner.png

The imports in the file itself do look a bit more complex but are also very clear: ./LargeComponent/assets/img/banner.png. It also makes the main components folder look a bit more cluttered but not necessarily more unclear.

Pro’s

  • Works in every build system, very straightforward.
  • Easy to understand for other dev’s.
  • Does not change imports when creating folder for component.

Finally there is a bit more uncommon one I really like if you are using imports without file extension specified:

3. Putting an index.json in your component folder

Pretty straightforward, you just throw this index.json file in your component folder:

{
"name": "MY_COMPONENT_NAME",
"private": true,
"main": "./MY_COMPONENT_NAME.vue"
}

This takes care of resolving the import correctly. You can keep a tidy structure in your components folder with every element representing a component. You’ll end up with this folder structure:

components
|--LargeComponent
| |--index.json
| |--LargeComponent.vue
| |--components
| | |--LargeComponentModal.vue
| |--assets
| | |--img
| | | |--banner.png

This has all the advantages of the methods above but it is a bit more obscure and looses one of it’s biggest advantages when using imports with file extension specified.

Pro’s

  • Does not change imports when creating folder for component.
  • All component data contained in one folder.
  • Relative imports are cleaner.

Bonus round: Tip for Vue-Router users

When building an SPA I really like to put the single-instance components in a folder corresponding to the page they belong to, like this:

views
|--SubscribeView.vue
|--SubscribeView
| |--components
| | |--TheHeader.vue
| |--assets
| | |--header-image.png
components
|--AppButton.vue
|--AppButton
| |--components
| | |--AppButtonText.vue
| |--assets
| | |--img
| | | |--button-background.png

That’s it!

Thanks for reading, really hope this helped, if you’ve got suggestions and improvements please do leave them in the comments!

Building stuff? I love making things too, if you want to check out what I’m doing follow me on twitter!

Extra optional bonus round: More about the why!

I got a question in the comments from Kasp which I think addressed a little bit of info that might have been missing from the post. The answer got a bit long so I decided to just include the it in the post itself. The question is as follows:

Why separate components based on number of instances?
The way we’re currently doing our Vue app (which hasn’t gotten that big yet) is have a components folder and a views folder. Each view essentially being a page with one or more components. Components folder strictly contains the basic building blocks of the app.
Can you suggest when it might get bad? I’m thinking when there’s too many pages the views folder might get overwhelmed.

Well first of you probably want to separate single-instance components(SIC) from the rest. These SIC are just used to make building your page more convenient and to separate logic. I already really like to include these in a components folder coupled to the view. No other component will or should ever be using these single-instance components so there is no point in making them accessible to other views/components. Besides this there is a big advantage in making it easier for the view itself to access them and making it clearer that that is what is happening.

This starts to enable you to just use the components folder for what it sounds like it is: a folder full of reusable components that you can use anywhere in your app instead of a just a folder full of everything that ends with “.vue” and isn’t a top-level view.

But you’ll probably need assets. Certainly for your larger components. It’s quite inconvenient to place these in a general assets folder. You could just place them all in the main /static folder but I personally think it’s pretty nice and way easier to work with to have a dedicated folder for each component.

You might already be guessing where this is going but the folder you just created to hold this assets folder is the perfect place to put the single-instance children of the component you’re creating this folder for (preferably in a… you guessed it components folder!). Again just as with the views, no other component will or should every be using these and it should be as easy and straightforward as possible for the one component that will.

Thanks for asking this question and hope my answer clears things up!

Cheers!

More by Rutger Willems

Topics of interest

More Related Stories