Skip to content

<script setup>

<script setup> হল সিঙ্গেল-ফাইল কম্পোনেন্টস (SFCs) এর মধ্যে কম্পোজিশনের API ব্যবহার করার জন্য একটি কম্পাইল-টাইম সিনট্যাকটিক সুগার। আপনি যদি SFCs এবং Composition API উভয়ই ব্যবহার করেন তবে এটি রিকোমেন্ডেড সিনট্যাক্স। এটি সাধারণ <script> সিনট্যাক্সের তুলনায় অনেক সুবিধা প্রদান করে:

  • লেস বয়লারপ্লেট সহ আরও সংক্ষিপ্ত কোড
  • পিউর টাইপস্ক্রিপ্ট ব্যবহার করে প্রপস এবং নির্গত ইভেন্ট ডিক্লেয়ার করার ক্ষমতা
  • ভাল রানটাইম পারফরম্যান্স (টেমপ্লেটটি একই সুযোগে একটি রেন্ডার ফাংশনে কম্পাইল্ড হয়, একটি মধ্যবর্তী প্রক্সি ছাড়াই)
  • আরও ভাল আইডিই টাইপ-ইনফারেন্স পারফরম্যান্স (কোড থেকে টাইপগুলি বের করতে ল্যাঙ্গুয়েজ সার্ভারের জন্য কম কাজ)

Basic Syntax

সিনট্যাক্সে opt-in করতে, <script> ব্লকে setup অ্যাট্রিবিউট যোগ করুন:

vue
<script setup>
console.log('hello script setup')
</script>

ভিতরের কোডটি কম্পোনেন্টের setup() ফাংশনের কন্টেন্ট হিসেবে কম্পাইল করা হয়। এর মানে হল যে স্বাভাবিক <script> থেকে ভিন্ন, যেটি শুধুমাত্র একবার এক্সিকিউট হয় যখন কম্পোনেন্টটি প্রথম ইম্পোর্ট করা হয়, <script setup>-এর ভিতরের কোডটি প্রতিবার কম্পোনেন্টের একটি ইন্সট্যান্স তৈরি করার সময় এক্সিকিউট করবে

Top-level bindings are exposed to template

<script setup> ব্যবহার করার সময়, <script setup>-এর ভিতরে ডিক্লেয়ারড যেকোনো টপ-লেভেল বাইন্ডিং (ভেরিয়েবল, ফাংশন ডিক্লেয়ার এবং ইম্পোর্ট সহ) সরাসরি টেমপ্লেটে ব্যবহারযোগ্য:

vue
<script setup>
// variable
const msg = 'Hello!'

// functions
function log() {
  console.log(msg)
}
</script>

<template>
  <button @click="log">{{ msg }}</button>
</template>

ইম্পোর্ট একই ধারায় উন্মুক্ত করা হয়। এর মানে হল আপনি টেমপ্লেট এক্সপ্রেশনে একটি ইম্পোর্ট করা সহায়ক ফাংশন সরাসরি ব্যবহার করতে পারেন এটিকে methods অপশনের মাধ্যমে প্রকাশ না করেই:

vue
<script setup>
import { capitalize } from './helpers'
</script>

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

Reactivity

Reactivity APIs ব্যবহার করে রিয়েক্টিভ স্টেট স্পষ্টভাবে তৈরি করা প্রয়োজন। একটি setup() ফাংশন থেকে রিটার্নড ভ্যালুগুলির অনুরূপ, টেমপ্লেটগুলিতে উল্লেখ করা হলে রেফগুলি স্বয়ংক্রিয়ভাবে unwrapped হয়:

vue
<script setup>
import { ref } from 'vue'

const count = ref(0)
</script>

<template>
  <button @click="count++">{{ count }}</button>
</template>

Using Components

<script setup> এর স্কোপ ভ্যালুগুলি সরাসরি কাস্টম কম্পোনেন্টে ট্যাগ নেইম হিসাবে ব্যবহার করা যেতে পারে:

vue
<script setup>
import MyComponent from './MyComponent.vue'
</script>

<template>
  <MyComponent />
</template>

মনে করুন MyComponent একটি ভ্যারিয়েবল হিসাবে উল্লেখ করা হচ্ছে । আপনি যদি JSX ব্যবহার করে থাকেন, তাহলে মেন্টাল মডেল এখানে একই রকম। kebab-case সমতুল্য <my-component> টেমপ্লেটেও কাজ করে - তবে PascalCase কম্পোনেন্ট ট্যাগগুলি দৃঢ়ভাবে সামঞ্জস্যের জন্য রিকোমেন্ড করা হয়। এটি নেটিভ কাস্টম কম্পোনেন্ট থেকে পার্থক্য করতে সাহায্য করে।

Dynamic Components

যেহেতু কম্পোনেন্টগুলি স্ট্রিং কীগুলির অধীনে রেজিস্ট্রাড না হয়ে ভেরিয়েবল হিসাবে উল্লেখ করা হয়েছে, তাই <script setup>-এর ভিতরে ডায়নামিক কম্পোনেন্টগুলি ব্যবহার করার সময় আমাদের ডাইনামিক :is বাইন্ডিং ব্যবহার করা উচিত:

vue
<script setup>
import Foo from './Foo.vue'
import Bar from './Bar.vue'
</script>

<template>
  <component :is="Foo" />
  <component :is="someCondition ? Foo : Bar" />
</template>

লক্ষ্য করুন কিভাবে কম্পোনেন্টগুলিকে একটি টারনারি এক্সপ্রেশনে ভেরিয়েবল হিসাবে ব্যবহার করা যেতে পারে।

Recursive Components

একটি এসএফসি তার ফাইলের নাম দিয়ে অন্তর্নিহিতভাবে নিজেকে রেফার করতে পারে। যেমন FooBar.vue নামের একটি ফাইল তার টেমপ্লেটে নিজেকে <FooBar/> হিসেবে রেফার করতে পারে।

নোট করুন এটি ইম্পোর্টেড কম্পোনেন্টের তুলনায় কম অগ্রাধিকার রয়েছে। আপনার যদি একটি নেইমড ইম্পোর্ট থাকে যা কম্পোনেন্টটির অনুমিত নামের সাথে কনফ্লিক্ট করে, আপনি ইম্পোর্টের নাম দিতে পারেন:

js
import { FooBar as FooBarChild } from './components'

Namespaced Components

আপনি অবজেক্টের প্রোপার্টির অধীনে নেস্ট করা কোম্পোনেন্টেগুলিকে উল্লেখ করতে <Foo.Bar> এর মতো ডট সহ কম্পোনেন্ট ট্যাগ ব্যবহার করতে পারেন। আপনি যখন একটি ফাইল থেকে একাধিক কম্পোনেন্ট ইম্পোর্ট করেন তখন এটি দরকারী:

vue
<script setup>
import * as Form from './form-components'
</script>

<template>
  <Form.Input>
    <Form.Label>label</Form.Label>
  </Form.Input>
</template>

Using Custom Directives

গ্লোবালি রেজিস্ট্রাড কাস্টম ডিরেক্টিভগুলো স্বাভাবিক হিসাবে কাজ করে। লোকাল কাস্টম কে <script setup>-এর সাথে স্পষ্টভাবে রেজিস্ট্রাড হওয়ার প্রয়োজন নেই, তবে তাদের অবশ্যই নেইমিং স্কিম vNameOfDirective অনুসরণ করতে হবে:

vue
<script setup>
const vMyDirective = {
  beforeMount: (el) => {
    // do something with the element
  }
}
</script>
<template>
  <h1 v-my-directive>This is a Heading</h1>
</template>

আপনি যদি অন্য কোথাও থেকে একটি ডিরেক্টিভ ইম্পোর্ট করে থাকেন, তাহলে প্রয়োজনীয় নেইমিং স্কিমের সাথে মানানসই করার জন্য এটির নাম পরিবর্তন করা যেতে পারে:

vue
<script setup>
import { myDirective as vMyDirective } from './MyDirective.js'
</script>

defineProps() & defineEmits()

সম্পূর্ণ প্রকারের অনুমান সমর্থন সহ props এবং emits এর মতো অপশন ডিক্লেয়ার করতে, আমরা defineProps এবং defineEmits এপিআই ব্যবহার করতে পারি, যা <script setup>-এর মধ্যে অটোমেটিক্লি অ্যাভাইলএবল হবে:

vue
<script setup>
const props = defineProps({
  foo: String
})

const emit = defineEmits(['change', 'delete'])
// setup code
</script>
  • defineProps এবং defineEmits হল কম্পাইলার ম্যাক্রো শুধুমাত্র <script setup>-এর মধ্যে ব্যবহারযোগ্য। সেগুলি ইম্পোর্ট করার প্রয়োজন নেই এবং <script setup> প্রক্রিয়া করা হলে কম্পাইল করা হয়।

  • defineProps props অপশনের মতো একই ভ্যালু গ্রহণ করে, যখন defineEmits emits অপশনের মতো একই ভ্যালু গ্রহণ করে।

  • defineProps এবং defineEmits পাস করা অপশনগুলির উপর ভিত্তি করে সঠিক টাইপের ইনফারেন্স প্রদান করে।

  • defineProps এবং defineEmits-এ পাস করা অপশনগুলি সেটআপের বাইরে মডিউল স্কোপে হোইস্টেড করা হবে। অতএব, অপশনগুলি সেটআপ সুযোগে ডিক্লেয়াড লোকাল ভেরিয়েবলের উল্লেখ করতে পারে না। এটি করার ফলে একটি কম্পাইল এরর হবে। যাইহোক, it can reference ইম্পোর্ট করা বাইন্ডিং যেহেতু তারা মডিউল স্কোপ রয়েছে।

Type-only props/emit declarations

'defineProps' বা 'defineEmits'-এ একটি আক্ষরিক টাইপ আর্গুমেন্ট পাস করে পিউর-টাইপ সিনট্যাক্স ব্যবহার করে প্রপস এবং ইমিট ডিক্লেয়ার করা যেতে পারে:

ts
const props = defineProps<{
  foo: string
  bar?: number
}>()

const emit = defineEmits<{
  (e: 'change', id: number): void
  (e: 'update', value: string): void
}>()

// 3.3+: alternative, more succinct syntax
const emit = defineEmits<{
  change: [id: number] // named tuple syntax
  update: [value: string]
}>()
  • defineProps বা defineEmits শুধুমাত্র রানটাইম ডিক্লেয়ার বা টাইপ ডিক্লেয়ার ব্যবহার করতে পারে। একই সময়ে উভয় ব্যবহার করার ফলে একটি কম্পাইল এরর হবে।

  • টাইপ ডিক্লেয়ারেশন ব্যবহার করার সময়, ডবল ডিক্লেয়ারেশনের প্রয়োজনীয়তা দূর করতে এবং সঠিক রানটাইম বেহ্যিভিয়ার নিশ্চিত করতে স্ট্যাটিক বিশ্লেষণ থেকে সমতুল্য রানটাইম ঘোষণা স্বয়ংক্রিয়ভাবে তৈরি হয়।

    • ডেভ মোডে, কম্পাইলার টাইপগুলি থেকে সংশ্লিষ্ট রানটাইম ভ্যালিডেশন ইনফার করার চেষ্টা করবে। উদাহরণস্বরূপ এখানে foo: String ইনফারড করা হয়েছে foo: string প্রকার থেকে। যদি টাইপটি একটি ইম্পোর্ট করা টাইপের রেফারেন্স হয়, তাহলে ইনফারড করা ফলাফল হবে foo: null (any টাইপের সমান) যেহেতু কম্পাইলারের কাছে এক্সটারনাল ফাইলের তথ্য নেই।

    • প্রোড মোডে, কম্পাইলার বান্ডেলের সাইজ কমাতে অ্যারে ফরম্যাট ডিক্লারেইশন তৈরি করবে (এখানে প্রপগুলি ['foo', 'বার'] এ কম্পাইল করা হবে)

  • সংস্করণ 3.2 এবং নীচে, defineProps()-এর জন্য জেনেরিক টাইপ প্যারামিটার একটি লিটারাল টাইপ বা লোকাল ইন্টারফেসের একটি রেফারেন্সের মধ্যে সীমাবদ্ধ ছিল।

    এই সীমাবদ্ধতা 3.3 এ সমাধান করা হয়েছে। Vue-এর সর্বশেষ সংস্করণটি টাইপ প্যারামিটার পজিশনে ইম্পোর্ট করা রেফারেন্সিং এবং জটিল টাইপের একটি সীমিত সেট সমর্থন করে। যাইহোক, যেহেতু রানটাইম কনভারশেন ধরনটি এখনও AST-ভিত্তিক, কিছু কমপ্লেক্স টাইপের প্রকৃত টাইপ অ্যানালাইসিস প্রয়োজন, যেমন কন্ডিশনাল টাইপ, সমর্থিত নয়। আপনি একটি সিঙ্গেল প্রপের ধরণের জন্য শর্তসাপেক্ষ টাইপগুলি ব্যবহার করতে পারেন, তবে সম্পূর্ণ প্রপস অবজেক্ট নয়।

Default props values when using type declaration

টাইপ-অনলি defineProps ডিক্লারেশন একটি এরর হল যে এটিতে প্রপসের জন্য ডিফল্ট ভ্যালু প্রদান করার কোনো উপায় নেই। এই সমস্যাটি সমাধান করার জন্য, একটি 'withDefaults' কম্পাইলার ম্যাক্রোও প্রদান করা হয়েছে:

ts
export interface Props {
  msg?: string
  labels?: string[]
}

const props = withDefaults(defineProps<Props>(), {
  msg: 'hello',
  labels: () => ['one', 'two']
})

এটি সমতুল্য রানটাইম প্রপস default অপশনের কম্পাইল করা হবে। উপরন্তু, withDefaults হেল্পার ডিফল্ট ভ্যালুগুলির জন্য টাইপ চেক প্রদান করে এবং নিশ্চিত করে যে প্রত্যাবর্তিত props টাইপটিতে ডিফল্ট ভ্যালু ডিক্লারড বৈশিষ্ট্যগুলির জন্য অপশনাল ফ্ল্যাগগুলি রিমুভ করা হয়েছে।

defineExpose()

<script setup> ব্যবহার করা কম্পোনেন্টগুলি ডিফল্টরূপে বন্ধ থাকে - যেমন কম্পোনেন্টের সর্বজনীন উদাহরণ, যা টেমপ্লেট রেফ বা $parent চেইনের মাধ্যমে পুনরুদ্ধার করা হয়, ডিক্লারড কোনো বাইন্ডিং কে প্রকাশ করবে না <script setup> এর ভিতরে।

একটি <script setup> কম্পোনেন্টে প্রোপার্টিগুলি স্পষ্টভাবে প্রকাশ করতে, defineExpose কম্পাইলার ম্যাক্রো ব্যবহার করুন:

vue
<script setup>
import { ref } from 'vue'

const a = 1
const b = ref(2)

defineExpose({
  a,
  b
})
</script>

যখন একটি প্যারেন্ট টেমপ্লেট রেফের মাধ্যমে এই কম্পোনেন্টটির একটি ইন্সট্যান্স পান, তখন পুনরুদ্ধারকৃত ইন্সট্যান্স { a: number, b: number } আকারের হবে (রেফগুলি স্বয়ংক্রিয়ভাবে স্বাভাবিক উদাহরণের মতোই unwrapped হয়)।

defineOptions()

এই ম্যাক্রোটি একটি পৃথক <script> ব্লক ব্যবহার না করে সরাসরি <script setup> এর ভিতরে কম্পোনেন্ট অপশন ডিক্লেয়ার করতে ব্যবহার করা যেতে পারে:

vue
<script setup>
defineOptions({
  inheritAttrs: false,
  customOptions: {
    /* ... */
  }
})
</script>
  • শুধুমাত্র 3.3+ এ সমর্থিত।
  • এটি একটি ম্যাক্রো. অপশনগুলি মডিউল স্কোপে হোইস্টেড করা হবে এবং <script setup>-এ লোকাল ভেরিয়েবল অ্যাক্সেস করতে পারবে না যা লিটারাল কনসট্যান্ট নয়।

defineSlots()

স্লট নেইম এবং প্রপস টাইপ চেকিংয়ের জন্য IDE-কে টাইপ হিন্টিং দিতে এই ম্যাক্রো ব্যবহার করা যেতে পারে।

defineSlots() শুধুমাত্র একটি টাইপ প্যারামিটার রিসিভ করে এবং কোনো রানটাইম আর্গুমেন্ট নেই। টাইপ প্যারামিটার একটি টাইপ লিটারাল হওয়া উচিত যেখানে প্রোপার্টি কী-টি স্লটের নাম এবং ভ্যালুর টাইপটি স্লট ফাংশন। ফাংশনের প্রথম আর্গুমেন্ট হল প্রপস যা স্লট পাওয়ার আশা করে এবং এর টাইপটি টেমপ্লেটের স্লট প্রপসের জন্য ব্যবহার করা হবে। রিটার্নের টাইপটি বর্তমানে উপেক্ষা করা হয়েছে এবং এটি any হতে পারে, তবে আমরা ভবিষ্যতে স্লট সামগ্রী চেক করার জন্য এটির সুবিধা নিতে পারি।

এটি slots অবজেক্টও রিটার্ন দেয়, যা সেটআপ প্রসঙ্গে প্রকাশিত slots অবজেক্টের সমতুল্য অথবা useSlots() দ্বারা রিটার্নড হয়।

vue
<script setup lang="ts">
const slots = defineSlots<{
  default(props: { msg: string }): any
}>()
</script>
  • শুধুমাত্র 3.3+ এ সমর্থিত।

useSlots() & useAttrs()

<script setup>-এর ভিতরে slots এবং attrs-এর ব্যবহার তুলনামূলকভাবে বিরল হওয়া উচিত, কারণ আপনি টেমপ্লেটে $slots এবং $attrs হিসেবে সরাসরি অ্যাক্সেস করতে পারবেন। বিরল ক্ষেত্রে যেখানে আপনার প্রয়োজন হয়, যথাক্রমে useSlots এবং useAttrs হেল্পার ব্যবহার করুন:

vue
<script setup>
import { useSlots, useAttrs } from 'vue'

const slots = useSlots()
const attrs = useAttrs()
</script>

useSlots এবং useAttrs হল প্রকৃত রানটাইম ফাংশন যা setupContext.slots এবং setupContext.attrs এর সমতুল্য রিটার্ন করে। এগুলি সাধারণ কম্পোজিশন API ফাংশনেও ব্যবহার করা যেতে পারে।

Usage alongside normal <script>

<script setup> সাধারণ <script> এর সাথে ব্যবহার করা যেতে পারে। একটি নরমাল <script> প্রয়োজন হতে পারে যেই ক্ষেত্রে আমাদের প্রয়োজন:

  • যে অপশনগুলি <script setup>-এ প্রকাশ করা যায় না সেগুলি ডিক্লেয়ার করুন, উদাহরণস্বরূপ inheritAttrs বা প্লাগইনগুলির মাধ্যমে এনাবল করা কাস্টম অপশনগুলি (3.3-এ [defineOptions](/api/sfc-script-setup#defineoptions দ্বারা প্রতিস্থাপিত হতে পারে) +)।
  • নেইমড এক্সপোর্ট ডিক্লেয়ার করা।
  • সাইড ইফেক্ট চালান বা এমন অবজেক্ট তৈরি করুন যা শুধুমাত্র একবার এক্সিকিউট করা উচিত।
vue
<script>
// normal <script>, executed in module scope (only once)
runSideEffectOnce()

// declare additional options
export default {
  inheritAttrs: false,
  customOptions: {}
}
</script>

<script setup>
// executed in setup() scope (for each instance)
</script>

একই কম্পোনেন্টে <script setup> এবং <script> একত্রিত করার জন্য সাপোর্টেড, উপরে বর্ণিত পরিস্থিতিতে সীমাবদ্ধ। বিশেষভাবে:

  • NOT অপশনগুলির জন্য একটি পৃথক <script> সেকশন ব্যবহার করবেন না যা <script setup> ব্যবহার করে ইতিমধ্যেই ডিফাইনড করা যেতে পারে, যেমন props এবং emits
  • <script setup>-এর মধ্যে তৈরি ভেরিয়েবলগুলিকে কম্পোনেন্ট ইন্সট্যান্সে প্রপার্টি হিসেবে যোগ করা হয় না, যা অপশন এপিআই থেকে অ্যাক্সেসযোগ্য করে তোলে। এইভাবে Mixing API গুলিকে দৃঢ়ভাবে নিরুৎসাহিত করা হয়৷

আপনি যদি সাপোর্টেড নয় এমন পরিস্থিতিতে নিজেকে খুঁজে পান তাহলে <script setup> ব্যবহার করার পরিবর্তে আপনার একটি স্পষ্ট setup() ফাংশনে স্যুইচ করার কথা বিবেচনা করা উচিত।

Top-level await

টপ-লেভেল await ব্যবহার করা যেতে পারে <script setup> এর মধ্যে। ফলস্বরূপ কোডটি async setup() হিসাবে কম্পাইল করা হবে:

vue
<script setup>
const post = await fetch(`/api/post/1`).then((r) => r.json())
</script>

উপরন্তু, প্রতীক্ষিত এক্সপ্রেশনটি স্বয়ংক্রিয়ভাবে একটি ফরম্যাটে সংকলিত হবে যা await এর পরে কারেন্ট কম্পোনেন্ট উদাহরণের কনটেক্স সংরক্ষণ করে।

নোট

async setup() অবশ্যই Suspense এর সাথে ব্যবহার করতে হবে, যা বর্তমানে একটি পরীক্ষামূলক ফিচার। আমরা ভবিষ্যতের রিলিজে এটি চূড়ান্ত এবং নথিভুক্ত করার পরিকল্পনা করছি - তবে আপনি যদি এখনই আগ্রহী হন তবে আপনি এটির টেস্টস দেখুন কিভাবে এটি কাজ করে।

Generics

জেনেরিক টাইপ প্যারামিটারগুলি <script> ট্যাগে generic অ্যাট্রিবিউট ব্যবহার করে ডিক্লেয়ার করা যেতে পারে:

vue
<script setup lang="ts" generic="T">
defineProps<{
  items: T[]
  selected: T
}>()
</script>

টাইপস্ক্রিপ্টে <...>-এর মধ্যে প্যারামিটার লিস্টের মতোই generic-এর ভ্যালু ঠিক একইভাবে কাজ করে। উদাহরণস্বরূপ, আপনি একাধিক প্যরামিটার, extends সীমাবদ্ধতা, ডিফল্ট টাইপস এবং রেফারেন্স ইম্পোর্টেড করা টাইপগুলি ব্যবহার করতে পারেন:

vue
<script
  setup
  lang="ts"
  generic="T extends string | number, U extends Item"
>
import type { Item } from './types'
defineProps<{
  id: T
  list: U[]
}>()
</script>

Restrictions

  • মডিউল এক্সিকিউশন semantics পার্থক্যের কারণে, <script setup>-এর ভিতরের কোড একটি SFC-এর প্রসঙ্গে নির্ভর করে। বাহ্যিক .js বা .ts ফাইলে সরানো হলে, এটি ডেভেলপার এবং টুল উভয়ের জন্যই বিভ্রান্তির কারণ হতে পারে। অতএব, <script setup> src অ্যাট্রিবিউটের সাথে ব্যবহার করা যাবে না।
  • <script setup> ইন-ডোম রুট কম্পোনেন্ট টেমপ্লেট সমর্থন করে না।(সম্পর্কিত আলোচনা)
<script setup> has loaded