# Installation

> Install @oddsquad/lit-devtools, add its Vite plugin to vite.config.ts, register the ambient types, and confirm the dev server is patching.

Install the plugin, add one line to `vite.config.ts`, and register the ambient types. If you have never used the plugin, follow the tutorial instead; it includes these steps.

Working with a coding agent? Hand it this prompt and it does the steps below, then reports which files it changed.

## Install

* npm

  ```sh
  npm i -D @oddsquad/lit-devtools
  ```

* pnpm

  ```sh
  pnpm add -D @oddsquad/lit-devtools
  ```

* yarn

  ```sh
  yarn add -D @oddsquad/lit-devtools
  ```

* bun

  ```sh
  bun add -d @oddsquad/lit-devtools
  ```

Lit and Vite stay your dependencies. [Compatibility](/reference/compatibility/) lists the versions each release supports and the one dev mode it does not.

`@oddsquad/lit-devtools` brings every part under one name: the Vite and Astro plugin, the [language server](/guides/language-server/)’s settings, and its [Oxlint rules](/guides/language-server/#check-it-in-ci-with-oxlint). Each part is also its own package, for a project that wants only one: `@oddsquad/vite-plugin-lit`, `@oddsquad/lit-language-server` and `@oddsquad/oxlint-plugin-lit`. The plugin’s imports then drop the subpath: `@oddsquad/vite-plugin-lit` in place of `@oddsquad/lit-devtools/vite`.

## Add it to Vite

Add `litPlugin()` to the `plugins` array. Nothing else moves.

```ts
import {defineConfig} from 'vite';
import {litPlugin} from '@oddsquad/lit-devtools/vite';

export default defineConfig({
  plugins: [litPlugin()],
});
```

Hot patching, the on-page indicator and the CSS import queries are on from here. The DevTools timeline and the source overlay are opt-in; the [options reference](/reference/options/) has the switches.

The patching applies to the dev server only, so a production build is untouched. The `?css-sheet` and `?hmr-url` queries resolve in dev and build alike.

### Keep dev code out of the build

`litPlugin()` doesn’t load its dev-only code until the dev server (or `vite preview`) starts. HMR, the source overlay and the DevTools panel are imported in a hook that `vite build` never calls, so a build loads only the options and the CSS plugins.

What those CSS plugins emit carries no dev code either: under `vite build`, a `?css-sheet` compiles to a sheet that is filled once, with no hot-swap callback, and a `?hmr-url` to the plain asset URL.

If you want the build to depend on less than that, use `litCss()` from the `/build` entry for builds. It carries only what a build uses: the CSS queries, Lightning CSS for `css` literals, and the no-op timeline stub.

```ts
import {defineConfig} from 'vite';
import {litPlugin} from '@oddsquad/lit-devtools/vite';
import {litCss} from '@oddsquad/lit-devtools/build';

export default defineConfig(({command}) => ({
  plugins: [command === 'serve' ? litPlugin() : litCss()],
}));
```

`litCss()` takes `cssSheetBuild` and reads `LIT_PLUGIN_CSS_SHEET_BUILD` the same way `litPlugin()` does. A unit test walks both entries’ import graphs so neither can start pulling in dev code unnoticed.

## Add the types

The import queries ship ambient declarations in `@oddsquad/lit-devtools/client`. Without them TypeScript cannot type `import sheet from './theme.css?css-sheet'`.

The `types` array replaces TypeScript’s default, so list `vite/client` next to it rather than instead of it. The rest of this file is the `lit-ts` template’s, unchanged.

```json
{
  "compilerOptions": {
    "target": "es2023",
    "experimentalDecorators": true,
    "useDefineForClassFields": false,
    "module": "esnext",
    "lib": ["ES2023", "DOM"],
    "types": ["vite/client", "@oddsquad/lit-devtools/client"],
    "allowArbitraryExtensions": true,
    "skipLibCheck": true,

    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "verbatimModuleSyntax": true,
    "moduleDetection": "force",
    "noEmit": true,

    /* Linting */
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "erasableSyntaxOnly": true,
    "noFallthroughCasesInSwitch": true
  },
  "include": ["src"]
}
```

One `.d.ts` anywhere in your `include` does the same job, if you would rather not touch `types`:

```ts
/// <reference types="@oddsquad/lit-devtools/client" />
```

## Check it works

Start the dev server and open a page that renders a Lit component.

```sh
npm run dev
```

A small indicator sits in the corner of the page. It is idle until an update arrives.

Type into an input inside a component, then edit that component’s template and save. The markup changes, what you typed stays, and the indicator pulses green. That is a hot patch: an edit applied to the running page without a reload.

If the page reloads instead, the edit hit a shape that cannot be patched in place. [Limitations](/reference/limitations/) names each one.

## Related

[Options](/reference/options/)Every option litPlugin() takes, with defaults.

[Keep state across edits](/guides/hmr/)What a hot patch preserves, and the three settings worth changing.
