---
title: 'NuxtJS'
description: "Learn how to use JSONEval-Rs in Nuxt 3, handling both SSR (Nitro) and client-side web environments comprehensively."
navigation:
  icon: 'i-simple-icons-nuxtdotjs'
seo:
  title: 'NuxtJS'
  description: "Learn how to use JSONEval-Rs in Nuxt 3, handling both SSR (Nitro) and client-side web environments comprehensively."
---

# Using JSONEval-Rs in NuxtJS (Nuxt 3)

Like Next.js, Nuxt handles both server-side (Nitro backend) and client-side rendering. To use JSONEval-Rs cleanly, we recommend isolating WebAssembly loading based on the environment.

## 1. Installation

Install both the Node bindings (for Nitro) and your Client-side bindings (Bundler for Vite/Webpack, Vanilla for Turbopack):

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

*(Note: If you have a custom setup utilizing Turbopack, you must use `@json-eval-rs/vanilla` instead of `@json-eval-rs/bundler`)*

## Built-in BigInt Support

JavaScript natively loses precision for integers extending beyond `Number.MAX_SAFE_INTEGER` (2^53 - 1). JSONEval-Rs utilizes `json-with-bigint` internally across both the Web packages and React Native bindings. This ensures that any deep 64-bit integers (`i64`) returned by the rules engine map seamlessly to JavaScript's native `BigInt` type without precision loss.

## 2. Server-Side Usage (Nitro API)

For backend evaluations (API routes or server-side only logic), you use the Node.js target.

### Standard Endpoint Validation

Create an endpoint inside your `server/api` directory:

```typescript
// server/api/validate.post.ts
import { JSONEval } from '@json-eval-rs/webcore';
import '@json-eval-rs/node'; // Registers for Node.js usage automatically

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

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

  try {
    const result = await evalInstance.validate({ data: JSON.stringify(data) });
    return result;
  } finally {
    evalInstance.free(); // Mandatory memory cleanup
  }
});
```

### Fetching Evaluated Schema by Path

Sometimes your Nitro server needs to evaluate complex dependencies hidden within the schema without validating the whole structure. 

```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 {
    // Run evaluation engine first
    await evalInstance.evaluate({ data: JSON.stringify(data) });

    // Extract exactly the field you care about
    const computedDiscountPrice = await evalInstance.getEvaluatedSchemaByPath({
      path: "#/properties/discount_price",
      skipLayout: true
    });

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

## 3. Client-Side Usage (Plugins/Composables)

To use JSONEval-Rs in Vue components on the client, wrap its initialization in a Nuxt Client Plugin or a Vue Composable dynamically to prevent SSR errors.

### A Component-Based Composable

Create a composable that initializes `JSONEval` lazily. By relying on dynamic imports, Nuxt won't attempt to bundle the browser WASM for 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 () => {
    // Only execute on client side
    if (!import.meta.client) return;
    
    // Dynamically load browser WASM bundler
    // Note: If using Turbopack instead of Vite, import '@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(() => {
    // Free Rust memory allocation when component unmounts
    if (evaluator.value) evaluator.value.free();
  });

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

### Usage Inside a Vue Component

Now use the composable in your components, making sure to call `init()` inside an `onMounted` hook:

```vue
<!-- components/Validator.vue -->
<template>
  <div>
    <div v-if="!isReady">Loading WASM Evaluator...</div>
    <div v-else>
      <input v-model="username" @input="runValidation" placeholder="Enter 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 is required." } } }
  }
};

const username = ref('');
const validation = ref<any>(null);

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>
```

### Subform Optimization

If you are dealing with arrays or tables (e.g. repeated structures), running evaluations over massive JSON payloads is inefficient. Nuxt can utilize the subform functionalities exactly as in the standard Web ecosystem.

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

  const arrayObjPath = "#/properties/shopping_cart";

  if (await evaluator.value.hasSubform(arrayObjPath)) {
    // Evaluate just this specific sub-object
    await evaluator.value.evaluateSubform({
      subformPath: arrayObjPath,
      data: JSON.stringify(rowData)
    });

    // Check specific evaluated path states
    const itemTotal = await evaluator.value.getEvaluatedSchemaByPathSubform({
      subformPath: arrayObjPath,
      path: "#/properties/row_total"
    });

    console.log(`Updated Row Total for row ${rowIndex}: ${itemTotal.value}`);
  }
};
```

### Using Web Workers for Non-Blocking UI

For evaluating extraordinarily large schemas on the client without blocking Vue's reactivity system during heavy interactions, you can offload the WASM evaluator to a Web Worker.

**1. Create the Worker File (`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. Use the Worker in your Component**
```vue
<template>
  <div>
    <button :disabled="!isReady" @click="runValidation">
      Validate in Worker
    </button>
  </div>
</template>

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

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

onMounted(() => {
  // Vite Web Worker syntax utilized natively in Nuxt
  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("Validation Result:", e.data.payload);
  };

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

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

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

## Important Vite Configuration

Nuxt 3 uses Vite by default. You need to enable WASM support in Vite. Update your `nuxt.config.ts` to include the `vite-plugin-wasm` or simply add top-level await if needed:

```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()
    ]
  }
})
```

You'll need to install them:
```bash
yarn add -D vite-plugin-wasm vite-plugin-top-level-await
```
