Next Talk: Clean Code is Sexy Again: Making Your Vue Project AI Ready

May 22, 2026 — MadVue, Madrid

Conference
Skip to content

The Inline Vue Composables Refactoring pattern

Published: at 

TLDR#

Group related logic in your Vue components into well-named functions inside <script setup>. The technique adapts Martin Fowler’s Extract Function pattern to keep components readable without splitting them into separate files.

Introduction#

The Composition API and <script setup> give you flexibility, which lets you cram queries, state, side effects, and business logic into one block. Components turn into a tangle.

Use Extract Function to clean up the mess. Michael Thiessen named the Vue-specific version “inline composables” in his post at michaelnthiessen.com/inline-composables.

The pattern comes from Martin Fowler’s Refactoring catalog. Fowler describes it as breaking large functions into smaller ones with descriptive names. You can read his explanation at refactoring.com/catalog/extractFunction.html.

Fowler’s example:

function printOwing(invoice) {
  printBanner();
  let outstanding = calculateOutstanding();

  // print details
  console.log(`name: ${invoice.customer}`);
  console.log(`amount: ${outstanding}`);
}

Extract the details-printing logic into its own function:

function printOwing(invoice) {
  printBanner();
  let outstanding = calculateOutstanding();
  printDetails(outstanding);

  function printDetails(outstanding) {
    console.log(`name: ${invoice.customer}`);
    console.log(`amount: ${outstanding}`);
  }
}

The top-level function now reads like a story.

Bringing Extract Function to Vue#

Apply the same principle inside Vue components with inline composables: small functions declared in your <script setup> block that own a specific piece of logic.

The example below builds on a gist from Evan You.

Before Refactoring#

The original component mixes everything in one block:

// src/components/FolderManager.vue
<script setup>
import { ref, watch } from 'vue'

async function toggleFavorite(currentFolderData) {
  await mutate({
    mutation: FOLDER_SET_FAVORITE,
    variables: {
      path: currentFolderData.path,
      favorite: !currentFolderData.favorite
    }
  })
}

const showHiddenFolders = ref(localStorage.getItem('vue-ui.show-hidden-folders') === 'true')

const favoriteFolders = useQuery(FOLDERS_FAVORITE, [])

watch(showHiddenFolders, (value) => {
  if (value) {
    localStorage.setItem('vue-ui.show-hidden-folders', 'true')
  } else {
    localStorage.removeItem('vue-ui.show-hidden-folders')
  }
})

</script>

It works, but you have to read every line to figure out what the component does.

After Refactoring with Inline Composables#

Group the logic into focused composables:

// src/components/FolderManager.vue
<script setup>
import { ref, watch } from 'vue'
import { useQuery, mutate } from 'vue-apollo'
import FOLDERS_FAVORITE from '@/graphql/folder/favoriteFolders.gql'
import FOLDER_SET_FAVORITE from '@/graphql/folder/folderSetFavorite.gql'

const { showHiddenFolders } = useHiddenFolders()
const { favoriteFolders, toggleFavorite } = useFavoriteFolders()

function useHiddenFolders() {
  const showHiddenFolders = ref(localStorage.getItem('vue-ui.show-hidden-folders') === 'true')

  watch(showHiddenFolders, (value) => {
    if (value) {
      localStorage.setItem('vue-ui.show-hidden-folders', 'true')
    } else {
      localStorage.removeItem('vue-ui.show-hidden-folders')
    }
  }, { lazy: true })

  return { showHiddenFolders }
}

function useFavoriteFolders() {
  const favoriteFolders = useQuery(FOLDERS_FAVORITE, [])

  async function toggleFavorite(currentFolderData) {
    await mutate({
      mutation: FOLDER_SET_FAVORITE,
      variables: {
        path: currentFolderData.path,
        favorite: !currentFolderData.favorite
      }
    })
  }

  return {
    favoriteFolders,
    toggleFavorite
  }
}
</script>

The top of the script now spells out the component’s responsibilities:

const { showHiddenFolders } = useHiddenFolders();
const { favoriteFolders, toggleFavorite } = useFavoriteFolders();

Each composable carries a descriptive name. The implementation details sit below, out of the way until you need them.

Best Practices#

When to Use Inline Composables#

Conclusion#

Inline composables apply Martin Fowler’s Extract Function to Vue. You get:

Pick a cluttered component in your codebase and try it. The refactor takes minutes, and you’ll thank yourself the next time you read the file.

You can see the full example in Evan You’s gist: https://gist.github.com/yyx990803/8854f8f6a97631576c14b63c8acd8f2e

Press Esc or click outside to close

Stay Updated!

Subscribe to my newsletter for more TypeScript, Vue, and web dev insights directly in your inbox.

  • Background information about the articles
  • Weekly Summary of all the interesting blog posts that I read
  • Small tips and trick
Subscribe Now

Most Related Posts