---
title: 'NuxtJS'
description: "Pelajari cara menggunakan JSONEval-Rs di Nuxt 3, baik di sisi SSR (Nitro) maupun di sisi klien (web) secara komprehensif."
navigation:
  icon: 'i-simple-icons-nuxtdotjs'
seo:
  title: 'NuxtJS'
  description: "Pelajari cara menggunakan JSONEval-Rs di Nuxt 3, baik di sisi SSR (Nitro) maupun di sisi klien (web) secara komprehensif."
---

# Menggunakan JSONEval-Rs di NuxtJS (Nuxt 3)

Arsitektur SSR dan CSR Vue pada core Nuxt mensyaratkan pemisahan inisialisasi modul target WebAssembly via environment guard saat runtime.

## 1. Instalasi

Instal binding Node (untuk Nitro) dan juga binding Sisi Klien (Bundler untuk Vite/Webpack, Vanilla untuk Turbopack):

**Untuk Vite/Webpack (Bawaan Nuxt):**
```bash
yarn add @json-eval-rs/webcore @json-eval-rs/node @json-eval-rs/bundler
```

*(Catatan: Jika kamu memiliki pengaturan kustom menggunakan Turbopack, pakailah `@json-eval-rs/vanilla` alih-alih `@json-eval-rs/bundler`)*

## Dukungan Penuh BigInt

JavaScript seringkali kehilangan presisi pada angka bulat (integer) yang melewati batas aman `Number.MAX_SAFE_INTEGER` (2^53 - 1). JSONEval-Rs mengatasi hal ini dengan mengimplementasikan modul `json-with-bigint` secara internal pada seluruh instalasi Web dan React Native. Ini menjamin angka 64-bit raksasa (`i64`) milik engine tidak akan dikonversi menjadi tipe Float kacau, melainkan dipasangkan akurat dengan tipe standar `BigInt` JavaScript.

## 2. Penggunaan Sisi Server (API Nitro)

Untuk evaluasi di sisi backend (API route atau logika khusus server saja), gunakan target Node.js.

### Endpoint Validasi Standar

Buat endpoint di dalam direktori `server/api`:

```typescript
// server/api/validate.post.ts
import { JSONEval } from '@json-eval-rs/webcore';
import '@json-eval-rs/node'; // Otomatis terdaftar untuk penggunaan Node.js

export default defineEventHandler(async (event) => {
  const data = await readBody(event);
  const schema = {
    type: "object",
    properties: {
      username: { rules: { required: { value: true, message: "Username wajib diisi" } } }
    }
  };

  const evalInstance = new JSONEval({ schema: JSON.stringify(schema) });

  try {
    const result = await evalInstance.validate({ data: JSON.stringify(data) });
    return result;
  } finally {
    evalInstance.free(); // Wajib membersihkan memori
  }
});
```

### Mengambil Object Logika Parsial

Tidak semua router SSR wajib mencerna lalu membalikan root payload logic state seutuhnya ke FE klien. Arahkan pointer ke titik field payload yang dituju dan pangkas ukurannya dengan skip.

```typescript
// server/api/prices.post.ts
import { JSONEval } from '@json-eval-rs/webcore';
import '@json-eval-rs/node'; 

export default defineEventHandler(async (event) => {
  const data = await readBody(event);
  const evalInstance = new JSONEval({ schema: JSON.stringify(pricingSchema) });

  try {
    // Jalankan mesin evaluasi terlebih dahulu
    await evalInstance.evaluate({ data: JSON.stringify(data) });

    // Ekstrak secara presisi variabel status tertentu saja
    const computedDiscountPrice = await evalInstance.getEvaluatedSchemaByPath({
      path: "#/properties/discount_price",
      skipLayout: true
    });

    return { 
      discount: computedDiscountPrice.value, 
      applied: !computedDiscountPrice.hidden 
    };
  } finally {
    evalInstance.free(); 
  }
});
```

## 3. Penggunaan Sisi Klien (Plugin & Composables)

Untuk menggunakan JSONEval-Rs di komponen Vue pada sisi klien, bungkus inisialisasinya di dalam Nuxt Client Plugin atau Vue Composable secara dinamis untuk mencegah error SSR.

### Composable Berbasis Komponen

Buat composable yang menginisialisasi `JSONEval` saat pertama kali dipanggil. Dengan memanfaatkan impor dinamis, Nuxt tidak akan mencoba memaketkan WASM browser untuk Nitro.

```typescript
// composables/useEvaluator.ts
import { shallowRef, onBeforeUnmount } from 'vue';
import { JSONEval } from '@json-eval-rs/webcore';

export function useEvaluator(schema: any) {
  const evaluator = shallowRef<JSONEval | null>(null);
  const isReady = shallowRef(false);

  const init = async () => {
    // Hanya dijalankan di sisi klien
    if (!import.meta.client) return;
    
    // Muat modul WASM browser secara dinamis
    // Catatan: Jika menggunakan Turbopack, panggil impor '@json-eval-rs/vanilla'
    const wasmModule = await import('@json-eval-rs/bundler');
    
    const instance = new JSONEval({
      schema: JSON.stringify(schema),
      wasmModule
    });
    
    evaluator.value = instance;
    isReady.value = true;
  };

  onBeforeUnmount(() => {
    // Hapus alokasi memori Rust saat komponen dihapus (unmount)
    if (evaluator.value) evaluator.value.free();
  });

  return { evaluator, isReady, init };
}
```

### Penggunaan di Dalam Komponen Vue

Gunakan composable tersebut di dalam komponenmu, pastikan memanggil `init()` di dalam hook `onMounted`:

```vue
<!-- components/Validator.vue -->
<template>
  <div>
    <div v-if="!isReady">Memuat WASM Evaluator...</div>
    <div v-else>
      <input v-model="username" @input="runValidation" placeholder="Masukkan username" />
      <ul v-if="validation?.has_error" style="color: red;">
        <li v-for="err in validation.errors" :key="err.path">{{ err.message }}</li>
      </ul>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue';

const schema = {
  type: "object",
  properties: {
    username: { rules: { required: { value: true, message: "Username wajib diisi." } } }
  }
};

// ... Inisialisasi logika state
const { evaluator, isReady, init } = useEvaluator(schema);

onMounted(async () => {
  await init();
});

const runValidation = async () => {
  if (!evaluator.value) return;
  
  const result = await evaluator.value.validate({
    data: JSON.stringify({ username: username.value })
  });
  
  validation.value = result;
};
</script>
```

### Batas Optimasi Array Loop

Re-evaluasi skema multiarray root yang memberatkan RAM Vue CSR di bypass memakai target subform object untuk rendering responsif per-field.

```typescript
const evaluateSingleRow = async (rowIndex: number, rowData: any) => {
  if (!evaluator.value) return;

  const arrayObjPath = "#/properties/shopping_cart";

  if (await evaluator.value.hasSubform(arrayObjPath)) {
    // Taruh evaluasi spesifik khusus dari sub-objek ini
    await evaluator.value.evaluateSubform({
      subformPath: arrayObjPath,
      data: JSON.stringify(rowData)
    });

    // Panggil statik bagian yang terevaluasi berdasarkan properti jalur (path)
    const itemTotal = await evaluator.value.getEvaluatedSchemaByPathSubform({
      subformPath: arrayObjPath,
      path: "#/properties/row_total"
    });

    console.log(`Total terkini disesuaikan untuk baris ${rowIndex}: ${itemTotal.value}`);
  }
};
```

### Non-Blocking Web Workers

Cegah tab browser not-responding akibat kalkulasi WASM berat di main loop thread (UI Vue Reaktif) dengan mengirim job memory pointer ke Web Worker terisolasi.

**1. Buat File Worker (`workers/eval.worker.ts`)**
```typescript
import { JSONEval } from '@json-eval-rs/webcore';

let evaluator: JSONEval | null = null;

self.onmessage = async (e: MessageEvent) => {
  const { type, payload } = e.data;

  if (type === 'INIT') {
    const wasmModule = await import('@json-eval-rs/bundler');
    evaluator = new JSONEval({ schema: payload.schema, wasmModule });
    self.postMessage({ type: 'READY' });
  }

  if (type === 'VALIDATE' && evaluator) {
    const result = await evaluator.validate({ data: payload.data });
    self.postMessage({ type: 'RESULT', payload: result });
  }
};
```

**2. Gunakan Worker di dalam Komponen Vue**
```vue
<template>
  <div>
    <button :disabled="!isReady" @click="runValidation">
      Validasi Melalui Worker
    </button>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';

const isReady = ref(false);
let worker: Worker | null = null;

onMounted(() => {
  // Sintaks Vite Web Worker yang didukung otomatis di Nuxt versi 3 ke atas
  worker = new Worker(new URL('~/workers/eval.worker.ts', import.meta.url), { type: 'module' });

  worker.onmessage = (e) => {
    if (e.data.type === 'READY') isReady.value = true;
    if (e.data.type === 'RESULT') console.log("Hasil Validasi:", e.data.payload);
  };

  worker.postMessage({
    type: 'INIT',
    payload: { schema: JSON.stringify({ /* schema kamu */ }) }
  });
});

onUnmounted(() => {
  worker?.terminate();
});

const runValidation = () => {
  worker?.postMessage({
    type: 'VALIDATE',
    payload: { data: JSON.stringify({ input: "data" }) }
  });
};
</script>
```

## Konfigurasi Vite yang Penting

Nuxt 3 menggunakan Vite secara bawaan. Kamu perlu mengaktifkan dukungan WASM di Vite. Perbarui `nuxt.config.ts` milikmu untuk menyertakan `vite-plugin-wasm` atau tambahkan top-level await jika diperlukan:

```typescript
// nuxt.config.ts
import wasm from "vite-plugin-wasm";
import topLevelAwait from "vite-plugin-top-level-await";

export default defineNuxtConfig({
  vite: {
    plugins: [
      wasm(),
      topLevelAwait()
    ]
  }
})
```

Kamu perlu menginstalnya terlebih dahulu:
```bash
yarn add -D vite-plugin-wasm vite-plugin-top-level-await
```
