DEV Community

Cover image for Using two script blocks in Vue Single File Components
Jakub Andrzejewski
Jakub Andrzejewski

Posted on

Using two script blocks in Vue Single File Components

Hey there!

I recently encountered an issue while developing Vue components - I wanted to create a component with logic and UI and export from it TypeScript specific entities like interface or enum. The first part I have implemented using the script setup syntax. I didn't know what to do but my friend shared with me a solution to my problem.

Interestingly, this is not some dirty trick but a fully supported and documented feature of Vue that you can read more about here.

In this article, I would like to show you how you can use two script blocks in one Vue component so that you can solve similar problem if you encounter it.

Enjoy!

🟒 Using two script blocks in Vue components

As an example, let's take a look at the following component that will be responsible for creating an element that will be a div with a letter. It will accept two props letter and size.

<template>
  <div :class="classList">{{ letter }}</div>
</template>

<script lang="ts">
  export enum LetterSize {
    SM = 'sm',
    BASE = 'base',
    LG = 'lg',
    XL = 'xl',
  }
</script>

<script lang="ts" setup>
  import { computed } from 'vue';

  const props = defineProps({
    letter: {
      type: String,
      default: '',
    },
    size: {
      type: String as PropType<`${LetterSize}`>,
      default: LetterSize.BASE,
    },
  });

  const classList = computed(() => {
    const classes = {
      [LetterSize.SM]: ['w-[20px] h-[20px] text-[12px]'],
      [LetterSize.BASE]: ['w-[24px] h-[24px] text-[14px]'],
      // others
    };

    return classes[props.size];
  });
</script>
Enter fullscreen mode Exit fullscreen mode

There is a lot of code but let's discuss each part individually:

  1. In the template section, we have a div that will output the letter and computed class list based on size.
  2. In the first script section, we are declaring an enum for letter size
  3. In the second script section (setup), we are importing the utilities from vue, declaring component props, and creating a computed property to calculate the right size of the letter based on the prop.

Thanks to this approach, we could import both the component and the enum in another component like following:

  import Letter, { LetterSize } from '@/components/atoms/Letter.vue';
Enter fullscreen mode Exit fullscreen mode

And then use it in the template like so:

<Letter
  :size="LetterSize.XL"
  letter="X"
/>
Enter fullscreen mode Exit fullscreen mode

There might be also other cases when you may want to use this feature like:

  • Use the Options API to declare options that cannot be expressed in <script setup>, for example, inheritAttrs or custom options enabled via plugins.
  • Run side effects or create objects that should only execute once because setup() is run for every component.
  • Declare named exports which allow exporting multiple things from one file.

Read more about this feature here.

πŸ“– Learn more

If you would like to learn more about Vue, Nuxt, JavaScript or other useful technologies, checkout VueSchool by clicking this link or by clicking the image below:

Vue School Link

It covers most important concepts while building modern Vue or Nuxt applications that can help you in your daily work or side projects πŸ˜‰

βœ… Summary

Well done! You have just learned how to use two script blocks in Vue Single File Components!

Take care and see you next time!

And happy coding as always πŸ–₯️

Top comments (1)

Collapse
 
richardevcom profile image
richardevcom

While it is supported, it is strongly discouraged.

  • Do NOT use a separate <script> section for options that can already be defined using <script setup>, such as props and emits.

  • Variables created inside <script setup> are not added as properties to the component instance, making them inaccessible from the Options API. Mixing APIs in this way is strongly discouraged.