🛠️

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

2021/10/26に公開

Vue.js 3.2 で導入された <script setup> ですが Nuxt 3 でも利用可能です。
https://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

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

Vue.js では、次のように併用して書くことになります。

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

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

Nuxt 3 の用意する Composable Function により、次のように書き換えることが可能です。

definePageMeta() の使用例

<script setup lang="ts">
definePageMeta({
  layout: 'custom',
});
</script>

これまでページコンポーネントに記述していた内容は基本的に definePageMeta() を使用し記述可能です。

definePageMeta(meta: PageMeta) => void

interface PageMeta {
  validate?: (route: RouteLocationNormalized) => boolean | Promise<boolean> | Partial<NuxtError> | Promise<Partial<NuxtError>>
  redirect?: RouteRecordRedirectOption
  alias?: string | string[]
  pageTransition?: boolean | TransitionProps
  layoutTransition?: boolean | TransitionProps
  key?: false | string | ((route: RouteLocationNormalizedLoaded) => string)
  keepalive?: boolean | KeepAliveProps
  layout?: false | LayoutKey | Ref<LayoutKey> | ComputedRef<LayoutKey>
  middleware?: MiddlewareKey | NavigationGuard | Array<MiddlewareKey | NavigationGuard>
  [key: string]: any
}

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

Nuxt 3 では使用頻度の高いものは import せずにグローバルに利用できるようになっています。
詳しくは自動生成される .nuxt/types/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 ファイル内で export された関数)を読み込みます。
これらの import は記述する必要がありません。

utils フォルダ直下の .js, .ts ファイル内で export された関数も自動的に読み込まれるようになりました。

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/imports.d.ts などのファイルが生成されます。
Composition API の Reactivity API のほか defineXxx() , useXxx() , onXxx() などが含まれていることが分かります。

Nuxt 3.0.0 本リリース時点では次のとおりです。

Nuxt App

useAsyncData, useLazyAsyncData, refreshNuxtData, clearNuxtData, defineNuxtComponent, useNuxtApp, defineNuxtPlugin, useRuntimeConfig, useState, useFetch, useLazyFetch, useCookie, useRequestHeaders, useRequestEvent, setResponseStatus, setPageLayout, useRouter, useRoute, defineNuxtRouteMiddleware, navigateTo, abortNavigation, addRouteMiddleware, showError, clearError, isNuxtError, useError, createError, defineNuxtLink, useAppConfig, updateAppConfig, defineAppConfig, preloadComponents, preloadRouteComponents, prefetchComponents, loadPayload, preloadPayload, isPrerendered

<script setup> Compiler macro

withCtx, withDirectives, withKeys, withMemo, withModifiers, withScopeId,

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

cachedEventHandler, cachedFunction, defineCachedEventHandler, defineCachedFunction, defineNitroPlugin, defineRenderHandler, getRouteRules, nitroPlugin, useNitroApp, useRuntimeConfig, useStorage

h3

appendHeader, appendHeaders, appendResponseHeader, appendResponseHeaders, assertMethod, callNodeListener, createApp, createAppEventHandler, createError, createEvent, createRouter, defaultContentType, defineEventHandler, defineLazyEventHandler, defineNodeListener, defineNodeMiddleware, deleteCookie, dynamicEventHandler, eventHandler, fromNodeMiddleware, getCookie, getHeader, getHeaders, getMethod, getQuery, getRequestHeader, getRequestHeaders, getResponseHeader, getResponseHeaders, getRouterParam, getRouterParams, handleCacheHeaders, isError, isEvent, isEventHandler, isMethod, isStream, lazyEventHandler, parseCookies, promisifyNodeListener, proxyRequest, readBody, readRawBody, send, sendError, sendProxy, sendRedirect, sendStream, setCookie, setHeader, setHeaders, setResponseHeader, setResponseHeaders, toEventHandler, toNodeListener, useBase, writeEarlyHints

Vue Router

onBeforeRouteLeave, onBeforeRouteUpdate, useLink

その他

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 の型はどのように利用できますか?

'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://ja.vuejs.org/api/sfc-script-setup.html

Discussion