> ## Documentation Index
> Fetch the complete documentation index at: https://inertiajs-vi.tuantq.online/llms.txt
> Use this file to discover all available pages before exploring further.

# Thiết lập phía client

export const VueSpecific = ({children}) => {
  const [code, setCode] = useState(() => {
    if (typeof window === "undefined") {
      return "Vue";
    }
    return localStorage.getItem("code")?.replace(/"/g, "") || "Vue";
  });
  useEffect(() => {
    const handler = event => {
      if (event.detail?.key === "code") {
        setCode(event.detail.value?.replace(/"/g, ""));
      }
    };
    window.addEventListener("localStorageUpdate", handler);
    return () => window.removeEventListener("localStorageUpdate", handler);
  }, []);
  if (code !== "Vue") {
    return null;
  }
  return children;
};

export const SvelteSpecific = ({children}) => {
  const [code, setCode] = useState(() => {
    if (typeof window === "undefined") {
      return null;
    }
    return localStorage.getItem("code")?.replace(/"/g, "") || null;
  });
  useEffect(() => {
    const handler = event => {
      if (event.detail?.key === "code") {
        setCode(event.detail.value?.replace(/"/g, ""));
      }
    };
    window.addEventListener("localStorageUpdate", handler);
    return () => window.removeEventListener("localStorageUpdate", handler);
  }, []);
  if (!code?.includes("Svelte")) {
    return null;
  }
  return children;
};

export const ReactSpecific = ({children}) => {
  const [code, setCode] = useState(() => {
    if (typeof window === "undefined") {
      return null;
    }
    return localStorage.getItem("code")?.replace(/"/g, "") || null;
  });
  useEffect(() => {
    const handler = event => {
      if (event.detail?.key === "code") {
        setCode(event.detail.value?.replace(/"/g, ""));
      }
    };
    window.addEventListener("localStorageUpdate", handler);
    return () => window.removeEventListener("localStorageUpdate", handler);
  }, []);
  if (code !== "React") {
    return null;
  }
  return children;
};

Sau khi đã [cấu hình server-side framework](/v3/installation/server-side-setup), bạn cần thiết lập client-side framework. Inertia hiện hỗ trợ React, Vue và Svelte.

<Card icon="laravel" title="Laravel Starter Kit" href="https://laravel.com/docs/starter-kits" arrow="true" cta="Bắt đầu xây dựng">
  Các starter kit của Laravel cung cấp scaffold sẵn dùng cho ứng dụng Inertia mới.

  Đây là cách nhanh nhất để bắt đầu dự án Inertia mới bằng Laravel và Vue hoặc React. Tuy nhiên, nếu muốn cài Inertia thủ công vào ứng dụng, hãy xem tài liệu bên dưới.
</Card>

## Điều kiện tiên quyết

Inertia yêu cầu client-side framework và [Vite plugin](https://laravel.com/docs/vite#vue) tương ứng được cài đặt và cấu hình. Bạn có thể bỏ qua phần này nếu ứng dụng đã thiết lập sẵn.

<CodeGroup>
  ```bash Vue icon="vuejs" theme={null}
  npm install vue @vitejs/plugin-vue
  ```

  ```bash React icon="react" theme={null}
  npm install react react-dom @vitejs/plugin-react
  ```

  ```bash Svelte icon="s" theme={null}
  npm install svelte @sveltejs/vite-plugin-svelte
  ```
</CodeGroup>

Sau đó, thêm plugin của framework vào file `vite.config.js`.

<CodeGroup>
  ```js Vue icon="vuejs" theme={null}
  import { defineConfig } from 'vite'
  import laravel from 'laravel-vite-plugin'
  import vue from '@vitejs/plugin-vue'

  export default defineConfig({
      plugins: [
          laravel({
              input: ['resources/js/app.js'],
              refresh: true,
          }),
          vue(),
      ],
  })
  ```

  ```js React icon="react" theme={null}
  import { defineConfig } from 'vite'
  import laravel from 'laravel-vite-plugin'
  import react from '@vitejs/plugin-react'

  export default defineConfig({
      plugins: [
          laravel({
              input: ['resources/js/app.jsx'],
              refresh: true,
          }),
          react(),
      ],
  })
  ```

  ```js Svelte icon="s" theme={null}
  import { defineConfig } from 'vite'
  import laravel from 'laravel-vite-plugin'
  import { svelte } from '@sveltejs/vite-plugin-svelte'

  export default defineConfig({
      plugins: [
          laravel({
              input: ['resources/js/app.js'],
              refresh: true,
          }),
          svelte(),
      ],
  })
  ```
</CodeGroup>

Để biết thêm về cấu hình các plugin này, hãy xem [tài liệu Vite](https://laravel.com/docs/vite#vue) của Laravel.

## Cài đặt

Plugin `@inertiajs/vite` hỗ trợ Vite 7 và Vite 8.

<Steps>
  <Step title="Install dependencies">
    Cài Inertia client-side adapter và Vite plugin.

    <CodeGroup>
      ```bash Vue icon="vuejs" theme={null}
      npm install @inertiajs/vue3 @inertiajs/vite
      ```

      ```bash React icon="react" theme={null}
      npm install @inertiajs/react @inertiajs/vite
      ```

      ```bash Svelte icon="s" theme={null}
      npm install @inertiajs/svelte @inertiajs/vite
      ```
    </CodeGroup>
  </Step>

  <Step title="Configure Vite">
    Thêm plugin Inertia vào file `vite.config.js`.

    ```js vite.config.js theme={null}
    import inertia from '@inertiajs/vite'
    import laravel from 'laravel-vite-plugin'
    import { defineConfig } from 'vite'

    export default defineConfig({
        plugins: [
            laravel({
                input: ['resources/js/app.js'],
                refresh: true,
            }),
            inertia(),
        ],
    })
    ```
  </Step>

  <Step title="Initialize the Inertia app">
    Cập nhật file JavaScript chính để boot ứng dụng Inertia. Vite plugin tự động xử lý page resolution và mounting, vì vậy chỉ cần entry point tối thiểu.

    <CodeGroup>
      ```js Vue icon="vuejs" theme={null}
      import { createInertiaApp } from '@inertiajs/vue3'

      createInertiaApp()
      ```

      ```jsx React icon="react" theme={null}
      import { createInertiaApp } from '@inertiajs/react'

      createInertiaApp()
      ```

      ```js Svelte icon="s" theme={null}
      import { createInertiaApp } from '@inertiajs/svelte'

      createInertiaApp()
      ```
    </CodeGroup>

    Plugin tạo resolver mặc định tìm page trong cả thư mục `./pages` và `./Pages`, đồng thời tự động mount ứng dụng.
  </Step>
</Steps>

### React Strict Mode

React adapter hỗ trợ bật [Strict Mode](https://react.dev/reference/react/StrictMode) của React qua tùy chọn `strictMode`.

```jsx theme={null}
createInertiaApp({
    strictMode: true,
    // ...
})
```

### Cú pháp rút gọn Pages

Bạn có thể dùng shorthand `pages` để tùy chỉnh thư mục tìm page component.

<CodeGroup>
  ```js Vue icon="vuejs" theme={null}
  createInertiaApp({
      pages: './AppPages',
      // ...
  })
  ```

  ```jsx React icon="react" theme={null}
  createInertiaApp({
      pages: './AppPages',
      // ...
  })
  ```

  ```js Svelte icon="s" theme={null}
  createInertiaApp({
      pages: './AppPages',
      // ...
  })
  ```
</CodeGroup>

Bạn cũng có thể truyền object để kiểm soát chi tiết hơn cách page được resolve. Chỉ cần cung cấp các option muốn tùy chỉnh.

```js theme={null}
createInertiaApp({
    pages: {
        path: './Pages',
        extension: '.tsx',
        lazy: true,
        transform: (name, page) => name.replace('/', '-'),
    },
})
```

| Tùy chọn    | Mô tả                                                                                                              |
| ----------- | ------------------------------------------------------------------------------------------------------------------ |
| `path`      | Thư mục dùng để tìm page component.                                                                                |
| `extension` | Chuỗi hoặc mảng phần mở rộng file (ví dụ `'.tsx'` hoặc `['.tsx', '.jsx']`). Mặc định dùng extension của framework. |
| `lazy`      | Có lazy-load page component hay không. Mặc định là `true`. Xem [code splitting](/v3/advanced/code-splitting).      |
| `transform` | Callback nhận tên page và page object rồi trả tên đã biến đổi.                                                     |

## Tùy chỉnh ứng dụng

Đôi khi bạn muốn tùy chỉnh app instance, ví dụ đăng ký plugin, bọc bằng provider hoặc đặt context value. Truyền callback `withApp` vào `createInertiaApp` để tùy chỉnh app trước khi render.

<CodeGroup>
  ```js Vue icon="vuejs" theme={null}
  import { createInertiaApp } from '@inertiajs/vue3'
  import { createI18n } from 'vue-i18n'

  const i18n = createI18n({
      // ...
  })

  createInertiaApp({
      withApp(app) {
          app.use(i18n)
      },
  })
  ```

  ```jsx React icon="react" theme={null}
  import { createInertiaApp } from '@inertiajs/react'
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query'

  const queryClient = new QueryClient()

  createInertiaApp({
      withApp(app) {
          return (
              <QueryClientProvider client={queryClient}>
                  {app}
              </QueryClientProvider>
          )
      },
  })
  ```

  ```js Svelte icon="s" theme={null}
  import { createInertiaApp } from '@inertiajs/svelte'

  createInertiaApp({
      withApp(context) {
          context.set('theme', 'dark')
      },
  })
  ```
</CodeGroup>

<VueSpecific>
  Callback nhận Vue app instance, cho phép gọi `app.use()`, `app.provide()`, `app.component()` và các app-level method khác.
</VueSpecific>

<ReactSpecific>
  Callback nhận React element và phải trả về element mới. Đây là nơi bạn có thể bọc ứng dụng bằng context provider.
</ReactSpecific>

<SvelteSpecific>
  Callback nhận `Map` đóng vai trò component context của Svelte. Giá trị đặt ở đây có thể được component truy cập bằng `getContext()`.
</SvelteSpecific>

Đối số thứ hai cung cấp môi trường render hiện tại qua `ssr`, cho phép áp dụng logic có điều kiện dựa trên nơi ứng dụng đang chạy.

<CodeGroup>
  ```js Vue icon="vuejs" theme={null}
  createInertiaApp({
      withApp(app, { ssr }) {
          app.use(i18n)

          if (!ssr) {
              app.use(browserOnlyPlugin)
          }
      },
  })
  ```

  ```jsx React icon="react" theme={null}
  createInertiaApp({
      withApp(app, { ssr }) {
          if (!ssr) {
              return <BrowserProvider>{app}</BrowserProvider>
          }

          return app
      },
  })
  ```

  ```js Svelte icon="s" theme={null}
  createInertiaApp({
      withApp(context, { ssr }) {
          context.set('theme', 'dark')

          if (!ssr) {
              context.set('analytics', createAnalytics())
          }
      },
  })
  ```
</CodeGroup>

Đối số thứ hai cũng chứa object `page` hiện tại, cho phép truy cập component name, URL, version và shared props trước khi app render. Điều này hữu ích để cấu hình plugin hoặc provider bằng state do server cung cấp, chẳng hạn locale của người dùng.

<CodeGroup>
  ```js Vue icon="vuejs" theme={null}
  createInertiaApp({
      withApp(app, { page }) {
          const i18n = createI18n({ locale: page.props.locale })

          app.use(i18n)
      },
  })
  ```

  ```jsx React icon="react" theme={null}
  createInertiaApp({
      withApp(app, { page }) {
          const i18n = createI18n({ locale: page.props.locale })

          return <I18nProvider i18n={i18n}>{app}</I18nProvider>
      },
  })
  ```

  ```js Svelte icon="s" theme={null}
  createInertiaApp({
      withApp(context, { page }) {
          context.set('locale', page.props.locale)
      },
  })
  ```
</CodeGroup>

## AI Assistant và tích hợp IDE

AI assistant và tích hợp IDE thường ghi state file vào root project. Khi bật `refresh: true` của `laravel-vite-plugin`, các thao tác ghi này có thể gây full-page reload ngoài ý muốn vì watcher của Vite mặc định chỉ bỏ qua `node_modules` và `.git`.

Bạn có thể mở rộng tùy chọn `server.watch.ignored` của Vite để loại các path này.

```js vite.config.js theme={null}
export default defineConfig({
    server: {
        watch: {
            ignored: [
                '**/.junie/**',
                '**/.cursor/**',
                '**/.claude/**',
            ],
        },
    },
    // ...
})
```

Điều chỉnh danh sách phù hợp với các tool đã cài. Xem tài liệu [server.watch](https://vite.dev/config/server-options.html#server-watch) của Vite để biết thêm tùy chọn.

## Thiết lập thủ công

Nếu không muốn dùng Vite plugin, bạn có thể tự cung cấp callback `resolve` và `setup`. Callback `resolve` cho Inertia biết cách tải page component và nhận component name cùng full [page object](/v3/core-concepts/the-protocol). Callback `setup` khởi tạo client-side framework.

<Note>Callback `setup` thủ công khiến Vite plugin không thể tự sinh xử lý [SSR](/v3/advanced/server-side-rendering). Bạn nên tạo [SSR entry point riêng](/v3/advanced/server-side-rendering#ssr-entry-point) và cập nhật app để dùng [client-side hydration](/v3/advanced/server-side-rendering#client-side-hydration).</Note>

<CodeGroup>
  ```js Vue icon="vuejs" theme={null}
  import { createApp, h } from 'vue'
  import { createInertiaApp } from '@inertiajs/vue3'

  createInertiaApp({
      resolve: name => {
          const pages = import.meta.glob('./Pages/**/*.vue')
          return pages[`./Pages/${name}.vue`]()
      },
      setup({ el, App, props, plugin }) {
          createApp({ render: () => h(App, props) })
              .use(plugin)
              .mount(el)
      },
  })
  ```

  ```jsx React icon="react" theme={null}
  import { createInertiaApp } from '@inertiajs/react'
  import { createRoot } from 'react-dom/client'

  createInertiaApp({
      resolve: name => {
          const pages = import.meta.glob('./Pages/**/*.jsx')
          return pages[`./Pages/${name}.jsx`]()
      },
      setup({ el, App, props }) {
          createRoot(el).render(<App {...props} />)
      },
  })
  ```

  ```js Svelte icon="s" theme={null}
  import { createInertiaApp } from '@inertiajs/svelte'
  import { mount } from 'svelte'

  createInertiaApp({
      resolve: name => {
          const pages = import.meta.glob('./Pages/**/*.svelte')
          return pages[`./Pages/${name}.svelte`]()
      },
      setup({ el, App, props }) {
          mount(App, { target: el, props })
      },
  })
  ```
</CodeGroup>

Mặc định, page component được lazy-load, tách mỗi page thành bundle riêng. Để eager bundle mọi page vào một file duy nhất, xem tài liệu [code splitting](/v3/advanced/code-splitting).

Package `laravel-vite-plugin` cũng cung cấp helper [`resolvePageComponent`](https://laravel.com/docs/vite#inertia) có thể dùng để resolve page component.

<CodeGroup>
  ```js Vue icon="vuejs" theme={null}
  import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers'

  resolve: name => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob('./Pages/**/*.vue')),
  ```

  ```js React icon="react" theme={null}
  import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers'

  resolve: name => resolvePageComponent(`./Pages/${name}.jsx`, import.meta.glob('./Pages/**/*.jsx')),
  ```

  ```js Svelte icon="s" theme={null}
  import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers'

  resolve: name => resolvePageComponent(`./Pages/${name}.svelte`, import.meta.glob('./Pages/**/*.svelte')),
  ```
</CodeGroup>

## Cấu hình giá trị mặc định

Bạn có thể truyền object `defaults` vào `createInertiaApp()` để cấu hình giá trị mặc định cho nhiều tính năng. Không cần truyền mặc định cho mọi key, chỉ cần những key bạn muốn điều chỉnh.

```js theme={null}
createInertiaApp({
  defaults: {
    form: {
      recentlySuccessfulDuration: 5000,
    },
    prefetch: {
      cacheFor: "1m",
      hoverDelay: 150,
    },
    visitOptions: (href, options) => {
      return {
        headers: {
          ...options.headers,
          "X-Custom-Header": "value",
        },
      };
    },
  },
  // ...
});
```

Callback `visitOptions` nhận target URL và visit option hiện tại, rồi nên trả object chứa option cần override. Để biết thêm về các cấu hình có sẵn, xem tài liệu [forms](/v3/the-basics/forms#form-errors), [prefetching](/v3/data-props/prefetching) và [manual visits](/v3/the-basics/manual-visits#global-visit-options).

### Cập nhật cấu hình khi runtime

Bạn cũng có thể cập nhật giá trị cấu hình khi runtime bằng instance `config` được export. Điều này đặc biệt hữu ích khi cần điều chỉnh setting dựa trên preference của người dùng hoặc state ứng dụng.

<CodeGroup>
  ```js Vue icon="vuejs" theme={null}
  import { config } from "@inertiajs/vue3";

  // Set a single value using dot notation...
  config.set("form.recentlySuccessfulDuration", 1000);
  config.set("prefetch.cacheFor", "5m");

  // Set multiple values at once...
  config.set({
    "form.recentlySuccessfulDuration": 1000,
    "prefetch.cacheFor": "5m",
  });
  ```

  ```js React icon="react" theme={null}
  import { config } from "@inertiajs/react";

  // Set a single value using dot notation...
  config.set("form.recentlySuccessfulDuration", 1000);
  config.set("prefetch.cacheFor", "5m");

  // Set multiple values at once...
  config.set({
    "form.recentlySuccessfulDuration": 1000,
    "prefetch.cacheFor": "5m",
  });

  // Get a configuration value...
  const duration = config.get("form.recentlySuccessfulDuration");
  ```

  ```js Svelte icon="s" theme={null}
  import { config } from "@inertiajs/svelte";

  // Set a single value using dot notation...
  config.set("form.recentlySuccessfulDuration", 1000);
  config.set("prefetch.cacheFor", "5m");

  // Set multiple values at once...
  config.set({
    "form.recentlySuccessfulDuration": 1000,
    "prefetch.cacheFor": "5m",
  });

  // Get a configuration value...
  const duration = config.get("form.recentlySuccessfulDuration");
  ```
</CodeGroup>

## Định nghĩa root element

Mặc định, Inertia giả định root template của ứng dụng có root element với `id` là `app`. Nếu root element của ứng dụng có `id` khác, bạn có thể cung cấp nó bằng thuộc tính `id`.

```js theme={null}
createInertiaApp({
  id: "my-app",
  // ...
});
```

Nếu thay `id` của root element, hãy nhớ cập nhật cả [phía server](/v3/installation/server-side-setup#root-template).

## Content Security Policy

Với ứng dụng dùng [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) hạn chế inline style, bạn có thể truyền `nonce` vào `createInertiaApp()`. Nonce được áp dụng cho inline style mà Inertia inject cho [progress bar](/v3/advanced/progress-indicators) và [error modal](/v3/advanced/error-handling), cho phép chúng vượt qua CSP.

```js theme={null}
createInertiaApp({
  nonce: "your-csp-nonce",
  // ...
});
```

## HTTP client

Khác Inertia 2 trở về trước, Inertia 3 dùng XHR client tích hợp cho mọi request. Không cần thư viện HTTP bổ sung như Axios.

### Sử dụng Axios

Bạn có thể cung cấp `axiosAdapter` làm tùy chọn `http` khi tạo ứng dụng Inertia. Điều này hữu ích khi ứng dụng cần custom Axios instance.

```js theme={null}
import { axiosAdapter } from '@inertiajs/core'

createInertiaApp({
  http: axiosAdapter(),
  // ...
})
```

Bạn cũng có thể truyền custom Axios instance cho adapter.

```js theme={null}
import axios from 'axios'
import { axiosAdapter } from '@inertiajs/core'

const instance = axios.create({
  // ...
})

createInertiaApp({
  http: axiosAdapter(instance),
  // ...
})
```

### Interceptor

XHR client tích hợp hỗ trợ interceptor để sửa request, kiểm tra response hoặc xử lý error. Các interceptor áp dụng cho mọi HTTP request do Inertia tạo, bao gồm từ router, `useForm`, `<Form>` và `useHttp`.

<CodeGroup>
  ```js Vue icon="vuejs" theme={null}
  import { http } from '@inertiajs/vue3'

  const removeRequestHandler = http.onRequest((config) => {
    config.headers['X-Custom-Header'] = 'value'
    return config
  })

  const removeResponseHandler = http.onResponse((response) => {
    console.log('Response status:', response.status)
    return response
  })

  const removeErrorHandler = http.onError((error) => {
    console.error('Request failed:', error)
  })

  // Remove a handler when it's no longer needed...
  removeRequestHandler()
  ```

  ```js React icon="react" theme={null}
  import { http } from '@inertiajs/react'

  const removeRequestHandler = http.onRequest((config) => {
    config.headers['X-Custom-Header'] = 'value'
    return config
  })

  const removeResponseHandler = http.onResponse((response) => {
    console.log('Response status:', response.status)
    return response
  })

  const removeErrorHandler = http.onError((error) => {
    console.error('Request failed:', error)
  })

  // Remove a handler when it's no longer needed...
  removeRequestHandler()
  ```

  ```js Svelte icon="s" theme={null}
  import { http } from '@inertiajs/svelte'

  const removeRequestHandler = http.onRequest((config) => {
    config.headers['X-Custom-Header'] = 'value'
    return config
  })

  const removeResponseHandler = http.onResponse((response) => {
    console.log('Response status:', response.status)
    return response
  })

  const removeErrorHandler = http.onError((error) => {
    console.error('Request failed:', error)
  })

  // Remove a handler when it's no longer needed...
  removeRequestHandler()
  ```
</CodeGroup>

Mỗi method `on*` trả cleanup function để xóa handler khi được gọi. Request handler nhận request config và phải trả lại config đó, dù có sửa hay không. Response handler nhận response và cũng phải trả response. Handler có thể là bất đồng bộ.

### Custom HTTP client

Để toàn quyền kiểm soát cách request được thực hiện, bạn có thể cung cấp HTTP client hoàn toàn tùy chỉnh qua tùy chọn `http`. Custom client phải implement phương thức `request`, nhận `HttpRequestConfig` và trả promise resolve thành `HttpResponse`. Xem source [xhrHttpClient.ts](https://github.com/inertiajs/inertia/blob/3.x/packages/core/src/xhrHttpClient.ts) làm implementation tham chiếu.

***

## Tài liệu chính thức

Bài dịch này được đối chiếu từ [tài liệu Inertia.js v3 chính thức](https://inertiajs.com/docs/v3/installation/client-side-setup). Nếu có khác biệt do phiên bản hoặc cập nhật mới, hãy ưu tiên tài liệu chính thức làm nguồn tham chiếu.
