## 1. Project Overview & Quickstart (antfu/skills)

## File: README.md

# Anthony Fu's Skills

A curated collection of [Agent Skills](https://agentskills.io/home) reflecting [Anthony Fu](https://github.com/antfu)'s preferences, experience, and best practices, along with usage documentation for the tools.

> [!IMPORTANT]
> This is a proof-of-concept project for generating agent skills from source documentation and keeping them in sync.
> I haven't fully tested how well the skills perform in practice, so feedback and contributions are greatly welcome.

## Installation

```bash
pnpx skills add antfu/skills --skill='*'
```

or to install all of them globally:

```bash
pnpx skills add antfu/skills --skill='*' -g
```

Learn more about the CLI usage at [skills](https://github.com/vercel-labs/skills).

## Skills

This collection is aim to be a one-stop collection of you are mainly working on Vite/Nuxt. It includes skills from different sources with different scopes.

### Hand-maintained Skills

> Opinionated

Manually maintained by Anthony Fu with his preferred tools, setup conventions, and best practices.

| Skill | Description |
|-------|-------------|
| [antfu](skills/antfu) | Anthony Fu's preferences and best practices for app/library projects (eslint, pnpm, vitest, vue, etc.) |
| [antfu-design](skills/antfu-design) | UnoCSS-centered design principles, semantic tokens, and UI presentation patterns from Anthony Fu's tooling UIs |

### Skills Generated from Official Documentation

> Unopinionated but with tilted focus (e.g. TypeScript, ESM, Composition API, and other modern stacks)

Generated from official documentation and fine-tuned by Anthony.

| Skill | Description | Source |
|-------|-------------|--------|
| [vue](skills/vue) | Vue.js core - reactivity, components, composition API | [vuejs/docs](https://github.com/vuejs/docs) |
| [nuxt](skills/nuxt) | Nuxt framework - file-based routing, server routes, modules | [nuxt/nuxt](https://github.com/nuxt/nuxt) |
| [pinia](skills/pinia) | Pinia - intuitive, type-safe state management for Vue | [vuejs/pinia](https://github.com/vuejs/pinia) |
| [vite](skills/vite) | Vite build tool - config, plugins, SSR, library mode | [vitejs/vite](https://github.com/vitejs/vite) |
| [vitepress](skills/vitepress) | VitePress - static site generator powered by Vite | [vuejs/vitepress](https://github.com/vuejs/vitepress) |
| [vitest](skills/vitest) | Vitest - unit testing framework powered by Vite | [vitest-dev/vitest](https://github.com/vitest-dev/vitest) |
| [unocss](skills/unocss) | UnoCSS - atomic CSS engine, presets, transformers | [unocss/unocss](https://github.com/unocss/unocss) |
| [pnpm](skills/pnpm) | pnpm - fast, disk space efficient package manager | [pnpm/pnpm.io](https://github.com/pnpm/pnpm.io) |

### Vendored Skills

Synced from external repositories that maintain their own skills.

| Skill | Description | Source |
|-------|-------------|--------|
| [slidev](skills/slidev) (Official) | Slidev - presentation slides for developers | [slidevjs/slidev](https://github.com/slidevjs/slidev) |
| [tsdown](skills/tsdown) (Official) | tsdown - TypeScript library bundler powered by Rolldown | [rolldown/tsdown](https://github.com/rolldown/tsdown) |
| [turborepo](skills/turborepo) (Official) | Turborepo - high-performance build system for monorepos | [vercel/turborepo](https://github.com/vercel/turborepo) |
| [vueuse-functions](skills/vueuse-functions) (Official) | VueUse - 200+ Vue composition utilities | [vueuse/skills](https://github.com/vueuse/skills) |
| [vue-best-practices](skills/vue-best-practices) | Vue 3 + TypeScript best practices | [vuejs-ai/skills](https://github.com/vuejs-ai/skills) |
| [vue-router-best-practices](skills/vue-router-best-practices) | Vue Router best practices | [vuejs-ai/skills](https://github.com/vuejs-ai/skills) |
| [vue-testing-best-practices](skills/vue-testing-best-practices) | Vue testing best practices | [vuejs-ai/skills](https://github.com/vuejs-ai/skills) |
| [web-design-guidelines](skills/web-design-guidelines) | Web design guidelines for building beautiful interfaces | [vercel-labs/agent-skills](https://github.com/vercel-labs/agent-skills) |

## FAQ

### What Makes This Collection Different?

This collection is opinionated, but the key difference is that it uses git submodules to directly reference source documentation. This provides more reliable context and allows the skills to stay up-to-date with upstream changes over time. If you primarily work with Vue/Vite/Nuxt, this aims to be a comprehensive one-stop collection.

The project is also designed to be flexible - you can use it as a template to generate your own skills collection.

### Skills vs llms.txt vs AGENTS.md

To me, the value of skills lies in being **shareable** and **on-demand**.

Being shareable makes prompts easier to manage and reuse across projects. Being on-demand means skills can be pulled in as needed, scaling far beyond what any agent's context window could fit at once.

You might hear people say "AGENTS.md outperforms skills". I think that's true — AGENTS.md loads everything upfront, so agents always respect it, whereas skills can have false negatives where agents don't pull them in when you'd expect. That said, I see this more as a gap in tooling and integration that will improve over time. Skills are really just a standardized format for agents to consume—plain markdown files at the end of the day. Think of them as a knowledge base for agents. If you want certain skills to always apply, you can reference them directly in your AGENTS.md.

## Generate Your Own Skills

Fork this project to create your own customized skill collection.

1. Fork or clone this repository
2. Install dependencies: `pnpm install`
3. Update `meta.ts` with your own projects and skill sources
4. Run `pnpm start cleanup` to remove existing submodules and skills
5. Run `pnpm start init` to clone the submodules
6. Run `pnpm start sync` to sync vendored skills
7. Ask your agent to `Generate skills for \` (recommended one at a time to manage token usage)

See [AGENTS.md](AGENTS.md) for detailed generation guidelines.

## Sponsors



## License

Skills and the scripts in this repository are [MIT](LICENSE.md) licensed.

Vendored skills from external repositories retain their original licenses - see each skill directory for details.

---

## File: skills/tsdown/references/README.md

# tsdown Skill References

This directory contains detailed reference documentation for the tsdown skill.

## Created Files (35 total)

### Core Guides (3)
- ✅ `guide-getting-started.md` - Installation, first bundle, CLI basics
- ✅ `guide-migrate-from-tsup.md` - Migration guide from tsup
- ✅ `guide-introduction.md` - Introduction and key features

### Configuration Options (20)
- ✅ `option-config-file.md` - Config file formats, loaders, workspace
- ✅ `option-entry.md` - Entry point configuration with globs
- ✅ `option-output-format.md` - Output formats (ESM, CJS, IIFE, UMD)
- ✅ `option-output-directory.md` - Output directory and extensions
- ✅ `option-dts.md` - TypeScript declaration generation
- ✅ `option-target.md` - Target environment (ES2020, ESNext, etc.)
- ✅ `option-platform.md` - Platform (node, browser, neutral)
- ✅ `option-dependencies.md` - External and inline dependencies
- ✅ `option-sourcemap.md` - Source map generation
- ✅ `option-minification.md` - Minification (`boolean | 'dce-only' | MinifyOptions`)
- ✅ `option-tree-shaking.md` - Tree shaking configuration
- ✅ `option-cleaning.md` - Output directory cleaning
- ✅ `option-watch-mode.md` - Watch mode configuration
- ✅ `option-shims.md` - ESM/CJS compatibility shims
- ✅ `option-package-exports.md` - Auto-generate package.json exports
- ✅ `option-css.md` - CSS handling (experimental, full pipeline: preprocessors, Lightning CSS, PostCSS, code splitting)
- ✅ `option-unbundle.md` - Preserve directory structure
- ✅ `option-cjs-default.md` - CommonJS default export handling
- ✅ `option-log-level.md` - Logging configuration
- ✅ `option-lint.md` - Package validation (publint & attw)

### Executable (1)
- ✅ `option-exe.md` - Standalone executable bundling (Node.js SEA)

### Advanced Topics (6)
- ✅ `advanced-plugins.md` - Rolldown, Rollup, Unplugin support
- ✅ `advanced-hooks.md` - Lifecycle hooks system
- ✅ `advanced-programmatic.md` - Node.js API usage
- ✅ `advanced-rolldown-options.md` - Pass options to Rolldown
- ✅ `advanced-ci.md` - CI environment detection and CI-aware options

### Advanced (continued)
- ✅ `advanced-benchmark.md` - Performance benchmarks

### Framework Recipes (5)
- ✅ `recipe-react.md` - React library setup with JSX
- ✅ `recipe-vue.md` - Vue library setup with SFC
- ✅ `recipe-solid.md` - Solid.js library setup
- ✅ `recipe-svelte.md` - Svelte component libraries
- ✅ `recipe-wasm.md` - WASM module support

### Reference (1)
- ✅ `reference-cli.md` - Complete CLI command reference

## Coverage Status

**Created:** 35 files (100% complete)

## Current Skill Features

The tsdown skill now includes comprehensive coverage of:

### ✅ Core Functionality
- Getting started and installation
- Entry points and glob patterns
- Output formats (ESM, CJS, IIFE, UMD)
- TypeScript declarations
- Configuration file setup
- CLI reference

### ✅ Build Options
- Target environment configuration
- Platform selection
- Dependency management
- Source maps
- Minification
- Tree shaking
- Output cleaning
- Watch mode

### ✅ Advanced Features
- Plugins (Rolldown, Rollup, Unplugin)
- Lifecycle hooks
- ESM/CJS shims
- Package exports generation
- Package validation (publint, attw)
- Programmatic API (Node.js)
- Output directory customization
- CSS handling and modules
- Unbundle mode
- CI environment detection and CI-aware options

### ✅ Framework & Runtime Support
- React with JSX/TSX
- React Compiler integration
- Vue with SFC support
- Vue type generation (vue-tsc)
- WASM module bundling (rolldown-plugin-wasm)

### ✅ Migration
- Complete migration guide from tsup
- Compatibility notes

## Usage

The skill is now ready for use with comprehensive coverage of core features. Additional files can be added incrementally as needed.

## File Naming Convention

Files are prefixed by category:
- `guide-*` - Getting started guides and tutorials
- `option-*` - Configuration options
- `advanced-*` - Advanced topics (plugins, hooks, programmatic API)
- `recipe-*` - Framework-specific recipes
- `reference-*` - CLI and API reference

## Creating New Reference Files

When creating new reference files:

1. **Read source documentation** from `/docs` directory
2. **Simplify for AI consumption** - concise, actionable content
3. **Include code examples** - practical, copy-paste ready
4. **Add cross-references** - link to related options
5. **Follow naming convention** - use appropriate prefix
6. **Keep it focused** - one topic per file

## Updating Existing Files

When documentation changes:

1. Check git diff: `git diff <sha>..HEAD -- docs/`
2. Update affected reference files
3. Update SKILL.md if needed
4. Update GENERATION.md with new SHA

See `skills/GENERATION.md` for detailed update instructions.

---

## File: skills/tsdown/README.md

# tsdown Skills

Agent skills that help AI coding agents understand and work with [tsdown](https://tsdown.dev), the elegant library bundler.

## Installation

```bash
npx skills add rolldown/tsdown
```

This will install all tsdown skills (including the migration skill). To install only the tsdown skill:

```bash
npx skills add rolldown/tsdown --skill tsdown
```

## What's Included

The tsdown skill provides Claude Code with knowledge about:

- **Core Concepts** - What tsdown is, why use it, key features
- **Configuration** - Config file formats, options, multiple configs, workspace support
- **Build Options** - Entry points, output formats, type declarations, targets
- **Dependency Handling** - External/inline dependencies, auto-externalization
- **Output Enhancement** - Shims, CJS defaults, package exports
- **Framework Support** - React, Vue, Solid, Svelte integration
- **Advanced Features** - Plugins, hooks, programmatic API, Rolldown options
- **CLI Commands** - All CLI options and usage patterns
- **Migration** - Migrating from tsup to tsdown

## Usage

Once installed, Claude Code will automatically use tsdown knowledge when:

- Building TypeScript/JavaScript libraries
- Configuring bundlers for library projects
- Setting up type declaration generation
- Working with multi-format builds (ESM, CJS, IIFE, UMD)
- Migrating from tsup
- Building framework component libraries

### Example Prompts

```
Set up tsdown to build my TypeScript library with ESM and CJS formats
```

```
Configure tsdown to generate type declarations and bundle for browsers
```

```
Add React support to my tsdown config with Fast Refresh
```

```
Help me migrate from tsup to tsdown
```

```
Set up a monorepo build with tsdown workspace support
```

## Related Skills

- **[tsdown-migrate](https://github.com/rolldown/tsdown/tree/main/skills/tsdown-migrate)** - Dedicated skill for migrating from tsup to tsdown, with complete option mappings, config transformations, and troubleshooting guidance.

## Documentation

- [tsdown Documentation](https://tsdown.dev)
- [GitHub Repository](https://github.com/rolldown/tsdown)
- [Rolldown](https://rolldown.rs)
- [Migration Guide](https://tsdown.dev/guide/migrate-from-tsup)

## License

MIT

---

## File: skills/slidev/README.md

# Slidev Skills for Claude Code

Agent skills that help Claude Code understand and work with [Slidev](https://sli.dev) presentations.

## Installation

```bash
npx skills add slidevjs/slidev
```

This will add the Slidev skill to your Claude Code configuration.

## What's Included

The Slidev skill provides Claude Code with knowledge about:

- **Core Syntax** - Markdown syntax, slide separators, frontmatter
- **Animations** - Click animations, transitions, motion effects
- **Code Features** - Line highlighting, Monaco editor, code groups, magic-move
- **Diagrams** - Mermaid, PlantUML, LaTeX math
- **Layouts** - Built-in layouts, slots, global layers
- **Presenter Mode** - Recording, timer, remote access
- **Exporting** - PDF, PPTX, PNG, SPA hosting

## Usage

Once installed, Claude Code will automatically use Slidev knowledge when:

- Creating new presentations
- Adding slides with code examples
- Setting up animations and transitions
- Configuring themes and layouts
- Exporting presentations

### Example Prompts

```
Create a Slidev presentation about TypeScript generics with code examples
```

```
Add a two-column slide with code on the left and explanation on the right
```

```
Set up click animations to reveal bullet points one by one
```

```
Configure the presentation for PDF export with speaker notes
```

## Documentation

- [Slidev Documentation](https://sli.dev)
- [Theme Gallery](https://sli.dev/resources/theme-gallery)
- [Showcases](https://sli.dev/resources/showcases)

## License

MIT

## 2. Official Technical Reference & Guides (antfu/website)

## File: README.md

# SWC Website

## Built Using

- [Next.js](https://nextjs.org?utm_source=swc)
- [Nextra](https://nextra.vercel.app)
- [Vercel](https://vercel.com?utm_source=swc)

[](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fswc-project%2Fwebsite)

---

## File: pages/docs/configuration/bundling.mdx

import Callout from 'nextra-theme-docs/callout'

# Bundling Configuration

<Callout emoji="🚧">
  This feature is still under construction.
</Callout>

SWC is able to bundle multiple JavaScript or TypeScript files into one.

This feature is currently named `spack`, but will be renamed to `swcpack` in `v2`. `spack.config.js` will be deprecated for `swcpack.config.js`.

View a [basic example of bundling](https://github.com/swc-project/cli/tree/master/examples/spack-basic).

## Configuration

You can configure bundling using `spack.config.js` with similar options to webpack. In the future, we are exploring a webpack compatible plugin system.

```js
// spack.config.js

module.exports = {
  entry: {
    web: __dirname + "/src/index.ts",
  },
  output: {
    path: __dirname + "/lib",
  },
};
```

> Note: CommonJS is currently required. In the future, ES Modules will be supported.

If you want auto-completion or type checking for configuration, you can wrap the export with a `config` function from `@swc/core/spack`. It's an identity function with type annotation.

```ts
const { config } = require("@swc/core/spack");

module.exports = config({
  entry: {
    web: __dirname + "/src/index.ts",
  },
  output: {
    path: __dirname + "/lib",
  },
});
```

### mode

Possible values: `production`, `debug`, `none`.

Currently this value is not used, but it will behave similarly to webpack.

### entry

Determines the entry of bundling. You may specify a file or a map of bundle name to file path.

> Note: Currently this should be absolute path. You can use `__dirname` to create one.
>
> In the future, SWC will support using relative paths and will resolve files relative to `spack.config.js`.

### output

You can change destination directory of the bundler using `output`.

```ts
const { config } = require("@swc/core/spack");

module.exports = config({
  output: {
    path: __dirname + "/lib",
    // Name is optional.
    name: "index.js",
  },
});
```

### options

Used to control the behavior of SWC. This field is optional.

---

## File: pages/docs/configuration/compilation.md

# Compilation

Compilation works out of the box with SWC and does not require customization. Optionally, you can override the configuration. Here are the defaults:

```json
{
  "jsc": {
    "parser": {
      "syntax": "ecmascript",
      "jsx": false,
      "dynamicImport": false,
      "privateMethod": false,
      "functionBind": false,
      "exportDefaultFrom": false,
      "exportNamespaceFrom": false,
      "decorators": false,
      "decoratorsBeforeExport": false,
      "topLevelAwait": false,
      "importMeta": false,
      "preserveAllComments": false
    },
    "transform": null,
    "target": "es5",
    "loose": false,
    "externalHelpers": false,
    // Requires v1.2.50 or upper and requires target to be es2016 or upper.
    "keepClassNames": false
  },
  "isModule": false
}
```

## jsc.externalHelpers

```json
{
  "jsc": {
    "externalHelpers": true
  }
}
```

The output code may depend on helper functions to support the target environment. By default, a helper function is inlined into the output files where it is required.

You can use helpers from an external module by enabling `externalHelpers` and the helpers code will be imported by the output files from `node_modules/@swc/helpers`.

While bundling, this option will greatly reduce your file size.

You must add `@swc/helpers` as a dependency in addition to `@swc/core`.

## jsc.parser

### typescript

```json
{
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "tsx": false,
      "decorators": false,
      "dynamicImport": false
    }
  }
}
```

### ecmascript

```json
{
  "jsc": {
    "parser": {
      "syntax": "ecmascript",
      "jsx": false,
      "dynamicImport": false,
      "privateMethod": false,
      "functionBind": false,
      "classPrivateProperty": false,
      "exportDefaultFrom": false,
      "exportNamespaceFrom": false,
      "decorators": false,
      "decoratorsBeforeExport": false,
      "importMeta": false
    }
  }
}
```

## jsc.target

Starting from `@swc/core` v1.0.27, you can specify the target environment by using the field.

```json
{
  "jsc": {
    // Disable es3 / es5 / es2015 transforms
    "target": "es2016"
  }
}
```

## jsc.loose

Starting from `@swc/core` v1.1.4, you can enable "loose" transformations by enabling `jsc.loose` which works like `babel-preset-env` [loose mode](https://2ality.com/2015/12/babel6-loose-mode.html).

```json
{
  "jsc": {
    "loose": true
  }
}
```

## jsc.transform

```json
{
  "jsc": {
    "transform": {
      "react": {
        "pragma": "React.createElement",
        "pragmaFrag": "React.Fragment",
        "throwIfNamespace": true,
        "development": false,
        "useBuiltins": false
      },
      "optimizer": {
        "globals": {
          "vars": {
            "__DEBUG__": "true"
          }
        }
      }
    }
  }
}
```

### jsc.transform.legacyDecorator

You can use the legacy (stage 1) class decorators syntax and behavior.

```json
{
  "jsc": {
    "parser": {
      "syntax": "ecmascript",
      "decorators": true
    },
    "transform": {
      "legacyDecorator": true
    }
  }
}
```

### jsc.transform.decoratorMetadata

This feature requires `v1.2.13+`.

If you are using typescript and decorators with `emitDecoratorMetadata` enabled, you can use `swc` for faster iteration:

```json
{
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "decorators": true
    },
    "transform": {
      "legacyDecorator": true,
      "decoratorMetadata": true
    }
  }
}
```

### jsc.transform.react

#### jsc.transform.react.runtime

Possible values: `automatic`, `classic`. This affects how JSX source code will be compiled.

- Use `runtime: automatic` to use a JSX runtime module (e.g. `react/jsx-runtime` introduced in React 17).
- Use `runtime: classic` to use `React.createElement` instead - with this option, you must ensure that `React` is in scope when using JSX.

[Learn more here](https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html).

#### jsc.transform.react.importSource

- Defaults to `react`.
- When using `runtime: automatic`, determines the runtime library to import.
- This option can be overrided with `@jsxImportSource foo`.

#### jsc.transform.react.pragma

- Defaults to `React.createElement`.
- When using `runtime: classic`, replaces the function used when compiling JSX expressions.
- This option can be overrided with `@jsx foo`.

#### jsc.transform.react.pragmaFrag

- Defaults to `React.Fragment`
- Replace the component used when compiling JSX fragments.
- This option can be overrided with `@jsxFrag foo`.

#### jsc.transform.react.throwIfNamespace

Toggles whether or not to throw an error if an XML namespaced tag name is used. For example: `<f:image />`

Though the JSX spec allows this, it is disabled by default since React's JSX does not currently have support for it.

#### jsc.transform.react.development

Toggles debug props `__self` and `__source` on elements generated from JSX, which are used by development tooling such as React Developer Tools.

This option is set automatically based on the Webpack `mode` setting when used with `swc-loader`. See [Using swc with webpack](/docs/usage-swc-loader/).

#### jsc.transform.react.useBuiltins

Use `Object.assign()` instead of `_extends`. Defaults to false.

#### jsc.transform.react.refresh

Enable [react-refresh](https://www.npmjs.com/package/react-refresh) related transform. Defaults to `false` as it's considered experimental.

Pass `refresh: true` to enable this feature, or an object with the following:

```ts
interface ReactRefreshConfig {
  refreshReg: String;
  refreshSig: String;
  emitFullSignatures: boolean;
}
```

### jsc.transform.constModules

```json
{
  "jsc": {
    "transform": {
      "constModules": {
        "globals": {
          "@ember/env-flags": {
            "DEBUG": "true"
          },
          "@ember/features": {
            "FEATURE_A": "false",
            "FEATURE_B": "true"
          }
        }
      }
    }
  }
}
```

Then, source code like:

```js
import { DEBUG } from "@ember/env-flags";
import { FEATURE_A, FEATURE_B } from "@ember/features";

console.log(DEBUG, FEATURE_A, FEATURE_B);
```

is transformed to:

```js
console.log(true, false, true);
```

### jsc.transform.optimizer

The SWC optimizier assumes:

- It's a module or wrapped in an iife.
- Accessing (get) global variables does not have a side-effect. It is the same assumption as the google closure compiler.
- You don't add fields to literals like a numeric literal, regular expression or a string literal.
- Files are served as gzipped.

SWC will not focus on reducing the size of non-gzipped file size.

Setting this to `undefined` skips optimizer pass.

#### jsc.transform.optimizer.simplify

> Requires `v1.2.101+`

You can set this to `false` to use `inline_globals` while skipping optimizations.

```json
{
  "jsc": {
    "transform": {
      "optimizer": {
        "simplify": false,
        "globals": {
          "vars": {
            "__DEBUG__": "true"
          }
        }
      }
    }
  }
}
```

#### jsc.transform.optimizer.globals

> Requires `v1.2.101+`

- `vars` - Variables to inline.
- `typeofs` - If you set `{ "window": "object" }`, `typeof window` will be replaced with `"object"`.

```json
{
  "jsc": {
    "transform": {
      "optimizer": {
        "globals": {
          "vars": {
            "__DEBUG__": "true"
          }
        }
      }
    }
  }
}
```

Then, you can use it like `npx swc '__DEBUG__' --filename input.js`.

#### jsc.transform.optimizer.jsonify

> Requires `v1.1.1+`

- `minCost` - If cost of parsing a pure object literal is larger than this value, the object literal is converted to `JSON.parse('{"foo": "bar"}')`. Defaults to 1024.

```json
{
  "jsc": {
    "transform": {
      "optimizer": {
        "jsonify": {
          "minCost": 0
        }
      }
    }
  }
}
```

This will change all **pure** object literals to `JSON.parse("")`.

## jsc.keepClassNames

> Requires `v1.2.50+` and target to be es2016 or higher

Enabling this option will make swc preserve original class names.

## jsc.paths

> Requires `v1.2.62+`

Syntax is identical as it of `tsconfig.json`: [learn more](https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping).

Requires `jsc.baseUrl`. See below.

## jsc.baseUrl

[Learn more](https://www.typescriptlang.org/docs/handbook/module-resolution.html#base-url).

## jsc.minify

> Requires `v1.2.67+`

See [the documentation for minification](/docs/configuration/minification) for more details.

## jsc.experimental

### jsc.experimental.keepImportAssertions

Preserve import assertions.
This is experimental because import assertions are not covered by ecmascript specifications yet.

### jsc.experimental.plugins

It follows resolving rule of node.js,.

Specify the plugin name like

```json
{
  "jsc": {
    "experimental": {
      "plugins": [
        ["@swc/plugin-styled-jsx", {}]
      ]
    }
  }
}
```

`styled-jsx` works because it's published as `@swc/plugin-styled-jsx`.

## jsc.preserveAllComments

Indicate that all comments should be preserved during compilation. Comments from source may be shifted in order to preserve thier relative location from source
to compiled output.
This feature is useful for transpilation that requires comments remain relatively close to the source: e.g. files under test with istanbul-ignore coverage
annotations.

## Multiple Entries

> Requires `v1.0.47+`

```json
[
  {
    "test": ".*.js$",
    "module": {
      "type": "commonjs"
    }
  },
  {
    "test": ".*.ts$",
    "module": {
      "type": "amd"
    }
  }
]
```

This make SWC compile JavaScript files as CommonJS modules and compile TypeScript files as AMD modules.

Note that `test` option can be used to transcompile only typescript files, like

```json
{
  "test": ".*.ts$",
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "tsx": false,
      "decorators": true,
      "dynamicImport": true
    }
  }
}
```

## test

Type: `Regex / Regex[]`

```json
{
  "test": ".*.ts$",
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "tsx": false,
      "decorators": true,
      "dynamicImport": true
    }
  }
}
```

## exclude

Type: `Regex / Regex[]`

```json
{
  "exclude": [".*.js$", ".*.map$"],
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "tsx": false,
      "decorators": true,
      "dynamicImport": true
    }
  }
}
```

## sourceMaps

> Requires `v1.2.50+`

Enable source map by adding `sourceMaps: true` or `sourceMaps: 'inline'` to the `.swcrc`.

```json
{
  "sourceMaps": true
}
```

## inlineSourcesContent

> Requires `v1.2.101+`

Defaults to `true`. If you want to make `swc` store contents of files into sourcemap, you can set `inlineSourcesContent` to `true`.

```json
{
  "sourceMaps": true,
  "inlineSourcesContent": true
}
```

## isModule

Possible values: `true`, `false`, `"unknown"`

Used to treat input as a module or script.
If this is set to `unknown`, it will be `Module` if it's esm and `Script` otherwise.

---

## File: pages/docs/configuration/minification.mdx

import Callout from "nextra-theme-docs/callout";

# Minification

Starting with `v1.2.67`, you can configure SWC to minify your code by enabling `minify` in your `.swcrc` file:

```json
{
  // Enable minification
  "minify": true,
  // Optional, configure minifcation options
  "jsc": {
    "minify": {
      "compress": {
        "unused": true
      },
      "mangle": true
    }
  }
}
```

## Configuration

### Note about comments

If you set `jsc.minify.compress` to `true` or `{}`, SWC will remove all comments.
If you don't want this, modify `jsc.minify.format`.

### `jsc.minify.compress`

Type: `boolean | object`.

Similar to [the compress option](https://terser.org/docs/api-reference.html#compress-options) of `terser`.

```json
{
  "jsc": {
    "minify": {
      "compress": true // equivalent to {}
    }
  }
}
```

- `arguments`, defaults to `false`.
- `arrows`, defaults to `true`.
- `booleans`, defaults to `true`.
- `booleans_as_integers`, defaults to `false`.
- `collapse_vars`, defaults to `true`.
- `comparisons`, defaults to `true`.
- `computed_props`, defaults to `true`.
- `conditionals`, defaults to `true`.
- `dead_code`, defaults to `false`.
- `defaults`, defaults to `true`.
- `directives`, defaults to `true`.
- `drop_console`, defaults to `false`.
- `drop_debugger`, defaults to `true`.
- `ecma`, defaults to `5`.
- `evaluate`, defaults to `true`.
- `global_defs`, defaults to `{}`.
- `hoist_funs`, defaults to `false`.
- `hoist_props`, defaults to `true`.
- `hoist_vars`, defaults to `false`.
- `ie8`, Ignored.
- `if_return`, defaults to `true`.
- `inline`, defaults to ``.
- `join_vars`, defaults to `true`.
- `keep_classnames`, defaults to `false`.
- `keep_fargs`, defaults to `false`.
- `keep_infinity`, defaults to `false`.
- `loops`, defaults to `true`.
- `negate_iife`, defaults to `true`.
- `passes`, defaults to `0`, which means no limit.
- `properties`, defaults to `true`.
- `pure_getters`, defaults to ``.
- `pure_funcs`, defaults to `[]`. Type is an array of string.
- `reduce_funcs`, defaults to `false`.
- `reduce_vars`, defaults to `false`.
- `sequences`, defaults to `true`.
- `side_effects`, defaults to `true`.
- `switches`, defaults to `true`.
- `top_retain`, defaults to ``.
- `toplevel`, defaults to `true`.
- `typeofs`, defaults to `true`.
- `unsafe`, defaults to `false`.
- `unsafe_arrows`, defaults to `false`.
- `unsafe_comps`, defaults to `false`.
- `unsafe_Function`, defaults to `false`.
- `unsafe_math`, defaults to `false`.
- `unsafe_symbols`, defaults to `false`.
- `unsafe_methods`, defaults to `false`.
- `unsafe_proto`, defaults to `false`.
- `unsafe_regexp`, defaults to `false`.
- `unsafe_undefined`, defaults to `false`.
- `unused`, defaults to `true`.
- `module`, Ignored. Currently, all files are treated as module.

### `jsc.minify.mangle`

Type: `boolean | object`.

Similar to [the mangle option](https://terser.org/docs/api-reference.html#mangle-options) of `terser`.

```json
{
  "jsc": {
    "minify": {
      "mangle": true // equivalent to {}
    }
  }
}
```

- `properties`, Defaults to `false`, and `true` is identical to `{}`.
- `topLevel`, Defaults to `true`. Aliased as `toplevel` for compatibility with `terser`.
- `keepClassnames`, Defaults to `false`. Aliased as `keep_classnames` for compatibility with `terser`.
- `keepFnames`, Defaults to `false`.
- `keepPrivateProps`, Defaults to `false`. Aliased as `keep_private_props` for compatibility with `terser`.
- `reserved`, Defaults to `[]`
- `ie8`, Ignored.
- `safari10`, Not implemented yet.

#### `jsc.minify.mangle.properties`

Type: `object`.

Similar to [the mangle properties option](https://terser.org/docs/api-reference.html#mangle-properties-options) of `terser`.

```json
{
  "jsc": {
    "minify": {
      "mangle":{
        "properties":{
          "reserved": ["foo", "bar"],
          "undeclared":false,
          "regex":"rust regex"
        }
      }
    }
  }
}
```

- `reserved`: Don't use these names as properties.

- `undeclared`: Mangle properties even if it's not delcared.

- `regex`: Mangle properties only if it matches this regex

### `jsc.minify.format`

These properties are mostly not implemented yet, but it exists to support passing terser config to swc minify without modification.

- `asciiOnly`, Defaults to `false`. Implemented as `v1.2.184` and aliased as `ascii_only` for compatibility with `terser`.
- `beautify`, Defaults to `false`. Currently noop.
- `braces`, Defaults to `false`. Currently noop.
- `comments`, Defaults to `false`.
  - `false` removes all comments
  - `'some'` preserves some comments
  - `'all'` preserves all comments
- `ecma`, Defaults to 5. Currently noop.
- `indentLevel`, Currently noop and aliases as `indent_level` for compatibility with `terser`.
- `indentStart`, Currently noop and aliases as `indent_start` for compatibility with `terser`.
- `inlineScript`, Currently noop and aliases as `inline_script` for compatibility with `terser`.
- `keepNumbers`, Currently noop and aliases as `keep_numbers` for compatibility with `terser`.
- `keepQuotedProps`, Currently noop and aliases as `keep_quoted_props` for compatibility with `terser`.
- `maxLineLen`, Currently noop, and aliases as `max_line_len` for compatibility with `terser`.
- `preamble`, Currently noop
- `quoteKeys`, Currently noop and aliases as `quote_keys` for compatibility with `terser`.
- `quoteStyle`, Currently noop and aliases as `quote_style` for compatibility with `terser`.
- `preserveAnnotations`, Currently noop and aliases as `preserve_annotations` for compatibility with `terser`.
- `safari10`, Currently noop.
- `semicolons`, Currently noop.
- `shebang`, Currently noop.
- `webkit`, Currently noop.
- `wrapIife`, Currently noop and aliases as `wrap_iife` for compatibility with `terser`.
- `wrapFuncArgs`, Currently noop and aliases as `wrap_func_args` for compatibility with `terser`.

## @swc/core Usage

### swc.minify(code, options)

This API is asynchronous and all of parsing, minification, and code generation will be done in background thread. The `options` argument is same as `jsc.minify` object. For example:

```js
import swc from "@swc/core";

const { code, map } = await swc.minify(
  "import foo from '@src/app'; console.log(foo)",
  {
    compress: false,
    mangle: true,
  }
);

expect(code).toMatchInlineSnapshot(`"import a from'@src/app';console.log(a);"`);
```

Returns `Promise<{ code: string, map: string }>`.

### swc.minifySync(code, options)

This API exists on `@swc/core`, `@swc/wasm`, `@swc/wasm-web`.

```js
import swc from "@swc/core";

const { code, map } = swc.minifySync(
  "import foo from '@src/app'; console.log(foo)",
  {
    compress: false,
    mangle: true,
  }
);

expect(code).toMatchInlineSnapshot(`"import a from'@src/app';console.log(a);"`);
```

Returns `{ code: string, map: string }`.

## APIs for WebAssembly

### Replacing Terser

You can reduce build time and override Terser without needing a library to update their dependencies through [yarn resolutions](https://classic.yarnpkg.com/lang/en/docs/selective-version-resolutions/). Example `package.json` would include:

```json
{
  "resolutions": { "terser": "npm:@swc/core" }
}
```

This will use the SWC minifier instead of Terser for all nested dependencies. Ensure you remove your lockfile and re-install your dependencies.

```sh
$ rm -rf node_modules yarn.lock
$ yarn
```

---

## File: pages/docs/configuration/modules.mdx

import Callout from 'nextra-theme-docs/callout'

# Modules

SWC can transpile your code using ES Modules to CommonJS or UMD/AMD. By default, module statements will remain untouched.

## CommonJS

To emit a CommonJS module, change the `type` in `.swcrc`:

```json
{
  "$schema": "http://json.schemastore.org/swcrc",
  "module": {
    "type": "commonjs",

    // These are defaults.
    "strict": false,
    "strictMode": true,
    "lazy": false,
    "noInterop": false
  }
}
```

## ES6

To emit a ES6 module, change the `type` in `.swcrc`:

```json
{
  "module": {
    "type": "es6",

    // These are defaults.
    "strict": false,
    "strictMode": true,
    "lazy": false,
    "noInterop": false
  }
}
```

## AMD

To emit an AMD module, change the `type` in `.swcrc`:

```json
{
  "module": {
    "type": "amd",
    // Optional. If specified, swc emits named AMD module.
    "moduleId": "foo",

    // These are defaults.
    "strict": false,
    "strictMode": true,
    "lazy": false,
    "noInterop": false
  }
}
```

## UMD

To emit an UMD module, change the `type` in `.swcrc`:

```json
{
  "module": {
    "type": "umd",
    "globals": {},

    // These are defaults.
    "strict": false,
    "strictMode": true,
    "lazy": false,
    "noInterop": false
  }
}
```

## Shared Options

These options are shared by `commonjs` / `es6` / `umd` / `amd` inside `.swcrc`:

```json
{
  "module": {
    // You can specify "commonjs", "es6", "amd", "umd"
    "type": "commonjs",
    "strict": false,
    "strictMode": true,
    "lazy": false,
    "noInterop": false,
    "ignoreDynamic": false
  }
}
```

### strict

Defaults to `false`. By default, when using exports with SWC, a non-enumerable `__esModule` property is exported. In some cases, this property is used to determine if the import is the default export or if it contains the default export.

To prevent the `__esModule` property from being exported, you can set the strict option to `true`.

### strictMode

Defaults to `true`. If true, swc emits 'use strict' directive.

### lazy

Defaults to `false`. This option changes Babel's compiled `import` statements to be lazily evaluated when their imported bindings are used for the first time. This can improve the initial load time of your module because evaluating dependencies upfront is sometimes entirely unnecessary. This is especially the case when implementing a library module.

The value of `lazy` has a few possible effects:

- `false` - No lazy initialization of any imported module.
- `true` - Do not lazy-initialize local `./foo` imports, but lazy-init `foo` dependencies. Local paths are much more likely to have circular dependencies, which may break if loaded lazily, so they are not lazy by default, whereas dependencies between independent modules are rarely cyclical.
- `Array<string>` - Lazy-initialize all imports with source matching one of the given strings.

The two cases where imports can never be lazy are:

- `import "foo";`
  Side-effect imports are automatically non-lazy since their very existence means that there is no binding to later kick-off initialization.
- `export from "foo"`
  Re-exporting all names requires up-front execution because otherwise there is no
  way to know what names need to be exported.

### noInterop

Defaults to `false`. By default, when using exports with swc a non-enumerable \_\_esModule property is exported.
This property is then used to determine if the import is the default export or if it contains the default export.

In cases where the auto-unwrapping of default is not needed, you can set the noInterop option to true to avoid the usage of the interopRequireDefault helper (shown in inline form above).

### ignoreDynamic

If set to `true`, dynamic imports will be preserved.

---

## File: pages/docs/configuration/supported-browsers.mdx

import Callout from 'nextra-theme-docs/callout'

# Supported Browsers

Starting with `v1.1.10`, you can now use `browserslist` to automatically configure supported browsers.

## Usage

First, install `browserslist`. Then, update your `.swcrc`:

```json
{
  "env": {
    "targets": {
      "chrome": "79"
    },
    "mode": "entry",
    "coreJs": "3.22"
  }
}
```

## Options

### browserslist

If you want to use [browserlists](https://github.com/browserslist/browserslist) with SWC, omit `targets` in your `.swcrc`:

```json
{
  "env": {
    "coreJs": "3.22"
  }
}
```

`browserlists` can be configured in multiple ways:

- `.browserslistrc`
- `browserslist` field in package.json

You can use [path](#path) to specify a custom path to load these configuration files.

### targets

`string | Array<string> | { [string]: string }`, defaults to `{}`.

Describes the environments you support/target for your project. This can either be a [browserslist-compatible](https://github.com/ai/browserslist) query:

```json
{
  "env": {
    "targets": "> 0.25%, not dead"
  }
}
```

Or an object of minimum environment versions to support:

```json
{
  "env": {
    "targets": {
      "chrome": "58",
      "ie": "11"
    }
  }
}
```

Example environments:

- `chrome`
- `opera`
- `edge`
- `firefox`
- `safari`
- `ie`
- `ios`
- `android`
- `node`
- `electron`

If `targets` is not specified, SWC uses `browserslist` to get target information.

### path

- `string`, defaults to current directory.
- `path` specifies the directory to load the `browserslist` module and any browserslist configuration files. For example, `.browserslistrc` or `browserslist` field in package.json. This can be useful if your build system isn't in the root of your project.

### mode

- `string`, defaults to `undefined`.
- Possible values: `usage`, `entry`, `undefined` (this matches [`useBuiltIns`](https://babeljs.io/docs/en/babel-preset-env#usebuiltins) from Babel)

<Callout emoji="⚠️">
  The `usage` mode is currently not as efficient as Babel, yet.
</Callout>

### skip

Define ES features to skip to reduce bundle size. For example, your `.swcrc` could be:

```json
{
  "env": {
    "skip": ["core-js/modules/foo"]
  }
}
```

### coreJs

- `string`, defaults to `undefined`.
- `coreJs` specifies the version of `core-js` to use, can be any core-js versions supported by swc. E.g., `"3.22"`.

The option has an effect when used alongside `mode: "usage"` or `mode: "entry"`. It is recommended to specify the minor version (E.g. `"3.22"`) otherwise `"3"` will be interpreted as `"3.0"` which may not include polyfills for the latest features.

## Additional Options

- `debug`: (_boolean_) defaults to `false`.
- `dynamicImport`: (_boolean_) defaults to `false`.
- `loose`: (_boolean_) defaults to `false`. Enable [loose transformations](http://2ality.com/2015/12/babel6-loose-mode.html) for any plugins that allow them.
- `include`: (_string[]_) can be a `core-js` module (`es.math.sign`) or an SWC pass (`transform-spread`).
- `exclude`: (_string[]_) can be a `core-js` module (`es.math.sign`) or an SWC pass (`transform-spread`).
- `shippedProposals`: (_boolean_) defaults to `false`.
- `forceAllTransforms`: (_boolean_) defaults to `false`. Enable all possible transforms.

---

## File: pages/docs/configuration/swcrc.mdx

import Callout from 'nextra-theme-docs/callout'

# Configuring SWC

SWC can be configured with an `.swcrc` file.

## Compilation

Compilation works out of the box with SWC and does not require customization. Optionally, you can override the configuration. Here are the defaults:

```jsonc
{
  "$schema": "https://json.schemastore.org/swcrc",
  "jsc": {
    "parser": {
      "syntax": "ecmascript",
      "jsx": false,
      "dynamicImport": false,
      "privateMethod": false,
      "functionBind": false,
      "exportDefaultFrom": false,
      "exportNamespaceFrom": false,
      "decorators": false,
      "decoratorsBeforeExport": false,
      "topLevelAwait": false,
      "importMeta": false
    },
    "transform": null,
    "target": "es5",
    "loose": false,
    "externalHelpers": false,
    // Requires v1.2.50 or upper and requires target to be es2016 or upper.
    "keepClassNames": false
  },
  "minify": false
}
```

Read more about [configuring compilation](/docs/configuration/compilation).

## Supported Browsers

Starting with `v1.1.10`, you can now use `browserslist` to automaticallly configure supported browsers.

### Usage

First, install `browserslist`. Then, update your `.swcrc`:

```json
{
  "env": {
    "targets": {
      "chrome": "79"
    },
    "mode": "entry",
    "coreJs": "3.22"
  }
}
```

Read more about [configuring supported browsers](/docs/configuration/supported-browsers).

## Modules

Read more about [configuring modules](/docs/configuration/modules).

## Minification

Starting with `v1.2.67`, you can configure SWC to minify your code by enabling `minify` in your `.swcrc` file:

```json
{
  "minify": true
}
```

Read more about [configuring the JavaScript minifier](/docs/configuration/minification).

---

## File: pages/docs/plugin/ecmascript/cheatsheet.mdx

import Callout from "nextra-theme-docs/callout";

# Plugin cheatsheet

<Callout>
    This page describes the known hard points for implementing plugins for ecmascript.
</Callout>

## Understanding types

### `JsWord`

`String` allocates, and 'text'-s of source code has a special trait.
Those are lots of duplicates. Obviously, if your variable is named `foo`, you need to use `foo` multiple times.
So SWC interns the string to reduce the number of allocations.

`JsWord` is a string type that is interned.
You can create a `JsWord` from `&str`, or from a `String`.
Use `.into()` to convert to `JsWord`.

### `Ident`, `Id`, `Mark`, `SyntaxContext`

SWC uses a special system for managing variables.
See [the rustdoc for `Ident`](https://rustdoc.swc.rs/swc_ecma_ast/struct.Ident.html) for details.

## Common issues

### Getting AST representation of input

[SWC Playground](https://play.swc.rs) supports getting AST from the input code.

### Variable management of SWC

### Error reporting

See [rustdoc for `swc_common::errors::Handler`](https://rustdoc.swc.rs/swc_common/errors/struct.Handler.html).

### Comparing `JsWord` with `&str`

If you don't know what `JsWord` is, see [the rustdoc for swc_atoms](https://rustdoc.swc.rs/swc_atoms/).

You can create `&str` by doing `&val` where `val` is a variable of type `JsWord`.

### Matching `Box<T>`

You will need to use `match` to match on various nodes, including `Box<T>`.
For performance reason, all expressions are stored in a boxed form. (`Box<Expr>`)

SWC stores callee of call expressions as a `Callee` enum, and it has `Box<Expr>`.

```rust
use swc_core::ast::*;
use swc_core::visit::{VisitMut, VisitMutWith};

struct MatchExample;

impl VisitMut for MatchExample {
    fn visit_mut_callee(&mut self, callee: &mut Callee) {
        callee.visit_mut_children_with(self);

        if let Callee::Expr(expr) = callee {
            // expr is `Box<Expr>`
            if let Expr::Ident(i) = &mut **expr {
                i.sym = "foo".into();
            }
        }
    }
}


```

### Changing AST type

If you want to change `ExportDefaultDecl` to `ExportDefaultExpr`, you should do it from `visit_mut_module_decl`.

### Inserting new nodes

If you want to inject a new `Stmt`, you need to store the value in the sturct, and inject it from `visit_mut_stmts` or `visit_mut_module_items`.
See [a destructuring core transform](https://github.com/swc-project/swc/blob/6416c675de14b3acec558ab7b4ec69afcd71fa11/crates/swc_ecma_transforms_compat/src/es2015/destructuring.rs#L1025-L1034).

```rust
struct MyPlugin {
    stmts: Vec<Stmt>,
}

```

## Tips

### Apply `resolver` while testing

SWC applies plugin after applying [`resolver`](https://rustdoc.swc.rs/swc_ecma_transforms_base/fn.resolver.html), so it's better to test your transform with it.
As written in the rustdoc for the `resolver`, you have to use correct `SyntaxContext` if you need to reference global variable (e.g. `__dirname`, `require`) or top-level bindings written by the user.

```rust
fn tr() -> impl Fold {
    chain!(
        resolver(Mark::new(), Mark::new(), false),
        // Most of transform does not care about globals so it does not need `SyntaxContext`
        your_transform()
    )
}

test!(
    Syntax::default(),
    |_| tr(),
    basic,
    // input
    "(function a ([a]) { a });",
    // output
    "(function a([_a]) { _a; });"
);

```

### Make your handlers stateless

Let's say we are going to handle all array expressions in a function expression.
You can add a flag to the visitor to check if we are in a function expression.
You will be tempted to do

```rust

struct Transform {
    in_fn_expr: bool
}

impl VisitMut for Transform {
    noop_visit_mut_type!();

    fn visit_mut_fn_expr(&mut self, n: &mut FnExpr) {
        self.in_fn_expr = true;
        n.visit_mut_children_with(self);
        self.in_fn_expr = false;
    }

    fn visit_mut_array_lit(&mut self, n: &mut ArrayLit) {
        if self.in_fn_expr {
            // Do something
        }
    }
}
```

but this cannot handle

```js

const foo = function () {
    const arr = [1, 2, 3];

    const bar = function () {};

    const arr2 = [2, 4, 6];
}

```

After visiting `bar`, `in_fn_expr` is `false`.
You have to do

```rust

struct Transform {
    in_fn_expr: bool
}

impl VisitMut for Transform {
    noop_visit_mut_type!();

    fn visit_mut_fn_expr(&mut self, n: &mut FnExpr) {
        let old_in_fn_expr = self.in_fn_expr;
        self.in_fn_expr = true;

        n.visit_mut_children_with(self);

        self.in_fn_expr = old_in_fn_expr;
    }

    fn visit_mut_array_lit(&mut self, n: &mut ArrayLit) {
        if self.in_fn_expr {
            // Do something
        }
    }
}
```

instead.

### Test with `@swc/jest`

You can test your transform with `@swc/jest` by adding your plugin to your `jest.config.js`.

```js
module.exports = {
  rootDir: __dirname,
  moduleNameMapper: {
    "css-variable$": "../../dist",
  },
  transform: {
    "^.+\\.(t|j)sx?$": [
      "@swc/jest",
      {
        jsc: {
          experimental: {
            plugins: [
              [
                require.resolve(
                  "../../swc/target/wasm32-wasi/release/swc_plugin_css_variable.wasm"
                ),
                {
                  basePath: __dirname,
                  displayName: true,
                },
              ],
            ],
          },
        },
      },
    ],
  },
};

```

See https://github.com/jantimon/css-variable/blob/main/test/swc/jest.config.js

### `Path` is one of unix, while FileName can be one of host OS

This is because linux version of `Path` code is used while compiling to wasm.
So you may need to replace `\\` with `/` in your plugin.
As `/` is a valid path separator in windows, it's valid thing to do.

## Ownership model (of rust)

> This section is not about `swc` itself. But this is described at here because it's the cause of almost all trickyness of APIs.

In rust, only one variable can _own_ a data, and there's at most one mutable reference to it.
Also, you need to _own_ the value or have a mutable reference to it if you want to modify the data.

But there's at most one owner/mutable reference, so it means if you have a mutable reference to a value, other code cannot modify the value.
Every update operation should performed by the code which _owns_ the value or has a mutable reference to it.
So, some of babel APIs like `node.delete` is super tricky to implement.
As your code has ownership or mutable refernce to _some_ part of AST, SWC cannot modify the AST.

## Tricky operations

### Deleting node

You can delete a node in two step.

Let's say, we want to drop the variable named `bar` in the code below.

```js
var foo = 1;
var bar = 1;
```

There are two ways to do this.

#### Mark & Delete

The first way is to mark it as _invalid_ and delete it later.
This is typically more convinient.

```
/* Detailed source-code truncated for AI context efficiency. */
```

#### Delete from the parent handler

Another way to delete the node is deleting it from the parent handler.
This can be useful if you want to delete the node only if the parent node is specific type.

e.g. You don't want to touch the variables in for loops while deleting free variable statements.

```rust
use swc_core::ast::*;
use swc_core::visit::{VisitMut,VsiitMutWith};

struct Remover;

impl VisitMut for Remover {
    fn visit_mut_stmt(&mut self, s: &mut Stmt) {
        // This is not required in this example, but just to show that you typically need this.
        s.visit_mut_children_with(self);

        match s {
            Stmt::Decl(Decl::Var(var)) => {
                if var.decls.len() == 1 {
                    match var.decls[0].name {
                        Pat::Ident(i) => {
                            if &*i.sym == "bar" {
                                s.take();
                            }
                        }
                    }
                }
            }
            _ => {}
        }
    }


    fn visit_mut_stmts(&mut self, stmts: &mut Vec<Stmt>) {
        stmts.visit_mut_children_with(self);

        // We do same thing here.
        stmts.retain(|s| {
            !matches!(s, Stmt::Empty(..))
        });
    }

    fn visit_mut_module_items(&mut self, stmts: &mut Vec<ModuleItem>) {
        stmts.visit_mut_children_with(self);

        // We do same thing here.
        stmts.retain(|s| {
            !matches!(s, ModuleItem::Stmt(Stmt::Empty(..)))
        });
    }
}

```

### Referencing parent node from handler of child node

This includes usage of `paths` and `scope`.

### Caching some information about an AST node

You have two way to use informantion from a parent node.
For first, you can precompute information from the parent node handler.
Alternatively, you can clone the parent node and use it in the child node handler.

## Alternatives for babel APIs

### `generateUidIdentifier`

This returns a unique identifier with a monotonically increasing integer suffix.
`swc` does not provide API to do this, because there's a very easy way to do this.
You can store an integer field in transformer type and use it while calling `quote_ident!` or `private_ident!`.

```rust

struct Example {
    // You don't need to share counter.
    cnt: usize
}

impl Example {
    /// For properties, it's okay to use `quote_ident`.
    pub fn next_property_id(&mut self) -> Ident {
        self.cnt += 1;
        quote_ident!(format!("$_css_{}", self.cnt))
    }

    /// If you want to create a safe variable, you should use `private_ident`
    pub fn next_variable_id(&mut self) -> Ident {
        self.cnt += 1;
        private_ident!(format!("$_css_{}", self.cnt))
    }
}


```

### `path.find`

Upward traversal is not supported by `swc`.
It's because upward traversal requires storing information about parent at children nodes, which requires using types like `Arc` or `Mutex` in rust.

Instead of traversing upward, you should make it top-down.
For example, if you want to infer name of a jsx component from variable assignments or assignments, you can store `name` of component while visiting `VarDecl` and/or `AssignExpr` and use it from the component handler.

### `state.file.get`/`state.file.set`

You can simply store the value in the transform struct as an instance of transform struct only process one file.

---

## File: pages/docs/plugin/ecmascript/getting-started.mdx

import Callout from 'nextra-theme-docs/callout'

# Implementing a plugin

## Setup environment

### Install required toolchain

As plugin is written in the rust programming language and built as a `.wasm` file, you need to install rust toolchain and wasm target.

#### Install rust

You can follow instructions at ['Install Rust' page from the official rust website](https://www.rust-lang.org/tools/install)

#### Add wasm target to rust

SWC supports two kinds of `.wasm` files.
Those are

- wasm32-wasi
- wasm32-unknown-unknown

In this guide, we will use `wasm-wasi` as a target.

#### Install `swc_cli`

You can install a rust-based CLI for SWC by doing

```sh
cargo install swc_cli
```

#### Configuring IDE

If you are going to use vscode, it's recommended to install `rust-analyzer` extension.
`rust-analyzer` is a [language server](https://microsoft.github.io/language-server-protocol/) for the rust programming language, which provides good features for code completion, code navigation, and code analysis.

## Implementing simple plugin

### Create a project

SWC CLI supports creating a new plugin project.

Run

```sh
swc plugin new --target-type wasm32-wasi my-first-plugin
# You should to run this
rustup target add wasm32-wasi
```

to create a new plugin, and open `my-first-plugin` with your preferred rust IDE.

### Implementing a visitor

The generated code has

```rust
impl VisitMut for TransformVisitor {
    // Implement necessary visit_mut_* methods for actual custom transform.
    // A comprehensive list of possible visitor methods can be found here:
    // https://rustdoc.swc.rs/swc_ecma_visit/trait.VisitMut.html
}
```

which is used to transform code.
[The trait `VisitMut`](https://rustdoc.swc.rs/swc_ecma_visit/trait.VisitMut.html) supports mutating AST nodes, and as it supports all AST types, it has lots of methods.

---

We will use

```js
foo === bar;
```

as the input. From [the SWC Playground](https://play.swc.rs), you can get actual representation of this code.

```json
{
  "type": "Module",
  "span": {
    "start": 0,
    "end": 12,
    "ctxt": 0
  },
  "body": [
    {
      "type": "ExpressionStatement",
      "span": {
        "start": 0,
        "end": 12,
        "ctxt": 0
      },
      "expression": {
        "type": "BinaryExpression",
        "span": {
          "start": 0,
          "end": 11,
          "ctxt": 0
        },
        "operator": "===",
        "left": {
          "type": "Identifier",
          "span": {
            "start": 0,
            "end": 3,
            "ctxt": 0
          },
          "value": "foo",
          "optional": false
        },
        "right": {
          "type": "Identifier",
          "span": {
            "start": 8,
            "end": 11,
            "ctxt": 0
          },
          "value": "bar",
          "optional": false
        }
      }
    }
  ],
  "interpreter": null
}
```

Let's implement a method for `BinExpr`.
You can do it like

```rust
use swc_core::{
    ast::*,
    visit::VisitMut,
};

impl VisitMut for TransformVisitor {
    fn visit_mut_bin_expr(&mut self, e: &mut BinExpr) {
        e.visit_mut_children_with(self);
    }
}
```

Note that `visit_mut_children_with` is required if you want to call the method handler for children.
e.g. `visit_mut_ident` for `foo` and `bar` will be called by `e.visit_mut_children_with(self);` above.

Let's narrow down it using the binary operator.

```rust
use swc_core::ast::*;
use swc_core::common::Spanned;

impl VisitMut for TransformVisitor {
    fn visit_mut_bin_expr(&mut self, e: &mut BinExpr) {
        e.visit_mut_children_with(self);

        if e.op == op!("===") {
            e.left = Ident::new("kdy1".into(), e.left.span()).into();
        }
    }
}
```

`op!("===")` is a macro call, and it returns various types of operators.
It returns [BinaryOp](https://rustdoc.swc.rs/swc_ecma_ast/enum.BinaryOp.html) in this case, because we provided `"==="`, which is a binary operator.
See [the rustdoc for op! macro](https://rustdoc.swc.rs/swc_ecma_ast/macro.op.html) for more details.

If we run this plugin, we will get

```js
kdy1 === bar;
```

## Testing your transform

You can simply run `cargo test` to test your plugins.
SWC also provides a utility to ease fixture testing.

You can take a look at [the real fixture test for typescript type stripper](https://github.com/swc-project/swc/blob/c0abdb394a94bcbc7ea9602163e6ce032c89b996/crates/swc_ecma_transforms_typescript/tests/strip.rs#L4514-L4527).

```rust
#[testing::fixture("tests/fixture/**/input.ts")]
#[testing::fixture("tests/fixture/**/input.tsx")]
fn fixture(input: PathBuf) {
    let output = input.with_file_name("output.js");
    test_fixture(
        Syntax::Typescript(TsConfig {
            tsx: input.to_string_lossy().ends_with(".tsx"),
            ..Default::default()
        }),
        &|t| chain!(tr(), properties(t, true)),
        &input,
        &output,
    );
}

```

Things to note:

- The glob provided to `testing::fixture` is relative to the cargo project directory.
- The output file is `output.js`, and it's stored in a same directory as the input file.
- `test_fixture` drives the test.
- You can determine the syntax of the input file by passing the syntax to `test_fixture`.
- You then provide your visitor implementation as the second argument to `test_fixture`.
- Then you provide the input file path and the output file path.

### Logging

SWC uses `tracing` for logging.
By default, SWC testing library configures the log level to `debug` by default, and this can be controlled by using an environment variable named `RUST_LOG`.
e.g. `RUST_LOG=trace cargo test` will print all logs, including `trace` logs.

If you want, you can remove logging for your plugin by using cargo features of `tracing`.
See [the documentation for it](https://docs.rs/crate/tracing/latest/features).

## Publishing your plugin

Please see [plugin publishing guide](../publishing)

---

## File: pages/docs/plugin/publishing.mdx

# Publishing plugins

If you prefer reading codes, you can refer to [the repository for official plugins](https://github.com/swc-project/plugins).

## Creating a npm package

### Building a plugin as a wasm

You can run your plugin as a wasm file by running

```sh
cargo prepublish --release
```

It will create `target/wasm32-wasi/release/your_plugin_name.wasm` or `target/wasm32-unknown-unknown/release/your_plugin_name.wasm`, depending on your config.

### Creating a npm package for plugin

Add the following to your `package.json`:

```json
{
    "main": "your_plugin_name.wasm",
    "scripts": {
        "prepack": "cargo prepublish --release && cp target/wasm32-wasi/release/your_plugin_name.wasm ."
    },
}
```

## Advanced: Improving your plugin

### Adjusting configuration for smaller binary

You can reduce the size of the plugin by configuring cargo.

In your `Cargo.toml` file, you can add the following lines.

```toml
[profile.release]
# This removes more dead code
codegen-units = 1
lto = true
# Optimize for size
opt-level = "s"
# Optimize for performance, this is default so you don't need to specify it
# opt-level = "z"
```

### Removing log for release mode

If logging of your crate is too much, you can remove it by enabling `release_max_level_*` of `tracing`, like

```toml
tracing = { version="0.1", features = ["release_max_level_info"] }
```