🛠️

Nuxt 3 における script setup の基本的な使い方と FAQ

2021/10/26に公開約6,500字

Vue.js 3.2 で導入された <script setup> ですが Nuxt 3 でも利用可能です。

https://v3.ja.vuejs.org/api/sfc-script-setup.html

<script setup> の基本的な使い方

Composition API ではあらたに setup() が利用できるようになりました。
Component 作成時において props 等の解決が行われた時点で呼ばれます。
呼び出し側の Component (親 Component )で定義された情報のみアクセスでき Options API でいう this にアクセスすることはできません。

その setup() の簡易な書き方(糖衣構文)が <script setup> です。
(Vue.js 3.2 以降では <script setup> による記述が推奨されています)

components/PostList.vue
<script setup lang="ts">
const { data: posts } = await useFetch('/api/posts')
</script>

<template>
  <div>
    <h1>投稿一覧</h1>
    <PostListItem
      v-for="post in posts"
      :key="post.id"
      :post="post"
    />
  </div>
</template>

上記の <script setup> 部分を、従来の Composition API で書くと次のようになります。
(script 内のみ)

components/PostList.vue
<script lang="ts">
export default defineComponent({
  async setup() {
    const { data: posts } = await useFetch('/api/posts')
    return {
      posts,
    }
  },
})
</script>

export default defineComponent() が不要となり async setup() や最後の return も使いません。
とてもシンプルに書けますね。

Compiler macro について

<script setup> はコンパイル時に通常の構文に変換しています。
そのとき <script setup> 内でのみ使用可能な記述 Compiler macro も同様に処理します。

defineEmits, defineExpose, defineProps, withDefaults などは Vue.js が用意している Compiler macro です。

FAQ

そのほかのオプションを使いたい場合はどうしたらよいですか?

次のように併用して書くことになります。

components/PostList.vue
<script lang="ts">
export default defineComponent({
  layout: false
})
</script>

<script setup lang="ts">
const { data: posts } = await useFetch('/api/posts')
</script>

Composition API (Reactivity API) の ref() 等はどのように import しますか?

Nuxt 3 では使用頻度の高いものは import せずにグローバルに利用できるようになっています。
詳しくは .nuxt/types/auto-imports.d.ts を見てください。

pages/count.vue
<script setup lang="ts">
const counter = ref(0)
const doubled = computed(() => counter.value * 2)
const increment = () => counter.value++
</script>

<template>
  <div>
    <p>{{ counter }}</p>
    <p>{{ doubled }}</p>
    <p><button @click="increment">カウントアップ</button></p>
  </div>
</template>

Component 等はどのように import しますか?

Nuxt 3 はデフォルトで Component (components内の .vue ファイル) と Composable Function (composables内の .js, .ts ファイルの useXxx() )を読み込みます。
これらの import は記述する必要がありません。

pages/count.vue
<script setup lang="ts">
const { counter } = useCount()
counter.value++
</script>

<template>
  <div>
    <TheHeader/>
    <p>{{ counter }}</p>
  </div>
</template>
composables/useCount.ts
export const useCount = () => {
  const counter = ref(0)
  return { counter }
}
components/TheHeader.vue
<template>
  <h1>カウント</h1>
</template>

Nuxt Context はどのように利用できますか?

useXxx() のように利用できます。

components/UserProfile.vue
<script setup lang="ts">
interface User {
  name: string
  age: number
}

const nuxtApp = useNuxtApp()
const { vueApp } = nuxtApp   // 旧 app
const route = useRoute()
const router = useRouter()
const user = useState<User | null>('user', () => null)
const $config = useRuntimeConfig()

// 中略

</script>

グローバルに利用可能な関数の一覧はありますか?

npm run dev すると作成される .nuxt ディレクトリ内に .nuxt/types/auto-imports.d.ts などのファイルが生成されます。
Composition API の Reactivity API のほか defineXxx() , useXxx() , onXxx() などが含まれていることが分かります。

rc2リリース時点では次のとおりです。

Nuxt, Vue

useAsyncData, useLazyAsyncData, refreshNuxtData, defineNuxtComponent, useNuxtApp, defineNuxtPlugin, useRuntimeConfig, useState, useFetch, useLazyFetch, useCookie, useRequestHeaders, useRequestEvent, useRouter, useRoute, useActiveRoute, defineNuxtRouteMiddleware, navigateTo, abortNavigation, addRouteMiddleware, throwError, clearError, useError, defineNuxtLink, useSlots, useAttrs

<script setup> Compiler macro

withCtx, withDirectives, withKeys, withMemo, withModifiers, withScopeId,
defineEmits, defineExpose, defineProps, withDefaults, definePageMeta

Lifecycle

onActivated, onBeforeMount, onBeforeUnmount, onBeforeUpdate, onDeactivated, onErrorCaptured, onMounted, onRenderTracked, onRenderTriggered, onServerPrefetch, onUnmounted, onUpdated

Reactivity

computed, customRef, isProxy, isReactive, isReadonly, isRef, markRaw, proxyRefs, reactive, readonly, ref, shallowReactive, shallowReadonly, shallowRef, toRaw, toRef, toRefs, triggerRef, unref, watch, watchEffect, isShallow

Effect

effect, effectScope, getCurrentScope, onScopeDispose

Component

defineComponent, defineAsyncComponent, resolveComponent, getCurrentInstance, h, inject, nextTick, provide, useAttrs, useCssModule, useCssVars, useSlots, useTransitionState

Nitro

defineCachedFunction, defineCachedEventHandler, useRuntimeConfig, useStorage, useNitroApp, defineNitroPlugin, nitroPlugin, defineEventHandler, defineLazyEventHandler

h3

defineEventHandler, defineLazyEventHandler, eventHandler, lazyEventHandler, dynamicEventHandler, appendHeader, assertMethod, createError, handleCacheHeaders, isMethod, sendRedirect, useCookies, useCookie, deleteCookie, setCookie, useBody, useMethod, useQuery, useRawBody

その他

useHead, useMeta, isVue2, isVue3

外部モジュールの import はどこで行いますか?

<script setup> のなかで可能です。
次のように記述すれば、適切に使用できます。

components/PostListItem.vue
<script setup lang="ts">
import { format } from 'date-fns'

const { postId } = useRoute().params
const { data: post } = await useFetch(`/api/post/${postId}`)
const published = computed(() => format(post.value.publishedAt, 'yyyy-MM-dd'))
</script>

また <template> 内で使用することも可能です。

<script setup lang="ts">
import { capitalize } from '@/helpers'
</script>

<template>
  <div>{{ capitalize('hello') }}</div>
</template>

Reactivity API の型はどのように利用できますか?

現時点(rc2 リリース時点)では 'vue' から呼び出します。

composables/useCount.ts
import type { Ref } from 'vue'

const inc = (counter: Ref<number>) => () => counter.value++

export const useCount = () => {
  const counter = ref(0)
  return {
    counter: readonly(counter),
    inc: inc(counter),
  }
}

props, attr, slot はどのように使いますか?

Vue.js 3.x のドキュメントをご確認ください。

https://v3.ja.vuejs.org/api/sfc-script-setup.html

Discussion

ログインするとコメントできます