Skip to content

Build Setup

Integrate Atscript into your build process using unplugin-atscript. This plugin automatically compiles .as files during the build, using your configuration file.

Installation

bash
npm install -D unplugin-atscript

Vite — Node.js Library

The most common setup: build a Node.js library with external dependencies. The plugin compiles .as files while Vite handles bundling.

javascript
// vite.config.js
import { defineConfig } from 'vite'
import atscript from 'unplugin-atscript/vite'

export default defineConfig({
  plugins: [atscript()],
  build: {
    lib: {
      entry: 'src/index.ts',
      formats: ['es'],
    },
    rollupOptions: {
      external: [/node_modules/],
    },
  },
})

Vite — UI Application

For frontend projects (e.g. Vue, React), add the Atscript plugin alongside your framework plugin:

javascript
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import atscript from 'unplugin-atscript/vite'

export default defineConfig({
  plugins: [atscript(), vue()],
})

This lets you import .as types directly in your components — for example, to drive form rendering from metadata or validate user input against your type definitions.

Other Bundlers

unplugin-atscript supports all major bundlers. Import from the bundler-specific entry point:

javascript
// rollup.config.js
import atscript from 'unplugin-atscript/rollup'

export default {
  plugins: [atscript()],
}
javascript
// build.js
import { build } from 'esbuild'
import atscript from 'unplugin-atscript/esbuild'

build({
  plugins: [atscript()],
  entryPoints: ['src/index.ts'],
  bundle: true,
  outdir: 'dist',
})
javascript
// rolldown.config.js
import atscript from 'unplugin-atscript/rolldown'

export default {
  plugins: [atscript()],
}
javascript
// webpack.config.js
import atscript from 'unplugin-atscript/webpack'

export default {
  plugins: [atscript()],
}
javascript
// rspack.config.js
import atscript from 'unplugin-atscript/rspack'

export default {
  plugins: [atscript()],
}
javascript
// farm.config.js
import atscript from 'unplugin-atscript/farm'

export default {
  plugins: [atscript()],
}

Options

The plugin takes the same options on every bundler entry. There is just one:

OptionTypeDefaultEffect
strictbooleantrueFail the build on parse/diagnostic errors. false = log errors but keep building.
javascript
atscript({ strict: false }) // warn-only — useful mid-refactor or in CI pre-flight

With strict: false, a .as file that fails to compile yields an empty module (module.exports = {}), so anything importing it will likely break at runtime — keep strict: true for normal builds.

Everything else (primitives, annotations, plugins, include/exclude) lives in atscript.config.*, which the plugin auto-discovers. The plugin only intercepts *.as imports; per-file filtering is delegated to the bundler.

How It Works

  1. Config Discovery — the plugin finds your atscript.config.* by searching upward from each .as file
  2. Plugin Execution — runs the plugins defined in your configuration
  3. Runtime JS — for each imported .as it emits the runtime metadata module (the same output as asc -f js)
  4. Import Resolution — lets you import .as files directly in TypeScript/JavaScript

In development the plugin compiles on demand with hot module replacement (native on Vite/Webpack/Rspack/Farm; via watch mode on Rollup/Rolldown). In production it pre-compiles during the build.

Type artifacts are not written by the bundler plugin

unplugin-atscript never writes .as.d.ts or the project-level atscript.d.ts to disk. For type checking and IDE support, generate types with the CLI: asc -f dts (e.g. as a postinstall and pre-build step), or let the VSCode extension regenerate them on save. (Declaration bundling in library builds is a separate concern — see below.)

Library Builds with Declaration Bundling

If you build a library whose TypeScript entries re-export .as symbols and bundle declarations with rolldown-plugin-dts (used by tsdown) or rollup-plugin-dts, the plugin serves type declarations to the declaration pass automatically: when the declaration bundler resolves an .as import from a generated declaration module, unplugin-atscript responds with the same declarations asc -f dts would produce, rendered fresh from the .as source. Re-exported symbols stay fully typed in the bundled .d.ts.

typescript
// src/index.ts — a library entry re-exporting an Atscript model
export { User } from './models/user.as'
typescript
// tsdown.config.ts
import { defineConfig } from 'tsdown'
import atscript from 'unplugin-atscript/rolldown'

export default defineConfig({
  entry: ['src/index.ts'],
  dts: true,
  plugins: [atscript()],
})

The only requirement is that atscript() is present in the plugin list of the build that bundles declarations — the same plugin instance covers both the runtime and declaration passes.

Symptom of a missing plugin: a re-exported .as symbol works as a value but loses all properties in a type position, and the emitted declaration imports it from a JS chunk:

typescript
// dist/index.d.mts — broken: no declaration exists for the .mjs chunk
import { t as User } from './user-ABC123.mjs'

If you see this, the plugin was not wired into the declaration build (or you are on an unplugin-atscript version that predates declaration support).

Bundling for Production

@atscript/typescript ships two entries: the default tsPlugin() factory (build-time only) and @atscript/typescript/utils (runtime helpers like Validator, ValidatorError, isAnnotatedType). If you externalize @atscript/typescript to keep build-time code out of your bundle, you must also externalize @atscript/typescript/utils — otherwise the runtime helpers get inlined into your bundle while downstream consumers (@atscript/moost-validator, plugins, your own code) import them from node_modules. Two copies of ValidatorError means instanceof returns false, error interceptors silently miss validation errors, and they escape as 500s.

The simplest fix is to externalize the whole namespace so every subpath comes along:

typescript
// rollup / rolldown / esbuild / rspack config
export default {
  external: [/^@atscript\//],
}

The same applies to subpath imports from any other @atscript/* package.

Next Steps

Released under the MIT License.