lunx.docs
DocsTutorialsUsing Plugins

Using Plugins

Extend Lunx with official and community plugins. Learn the plugin lifecycle, write custom build actions, and compose multiple plugins safely.

Installing a plugin

Install the plugin package, then add it to the plugins array in lunx.config.ts. Plugin order matters — plugins run in array order during the build.

typescriptlunx.config.ts
import { defineConfig } from 'lunx-dev'

export default defineConfig({
  plugins: [
    // A plugin is an object with a name and Rollup-style hooks
    {
      name: 'strip-debug',
      transform(code, id) {
        if (id.includes('/src/')) return code.replace(/console\.debug\([^)]*\);?/g, '')
      },
    },
  ],
})

resolveId, load and transform run in dev and in the build; renderChunk and generateBundle in the build. Vite's own hooks run as in Vite: config, configResolved, transformIndexHtml, configureServer, writeBundle and closeBundle, so existing Vite plugins work unchanged.

Plugin lifecycle hooks

Lunx plugins are plain objects with a name string and optional hook functions. Lunx calls the hooks at the same points Vite and Rollup do, in the dev server and in the build.

resolveId()

Intercepts module path resolution. Return a custom ID to redirect imports to a virtual module or an alternative path.

load()

Loads module content from a custom source. Return source code as a string to bypass the file system entirely.

transform()

Transform module source code. Receives the source and module ID. Return modified code and optional source map.

generateBundle()

Called after all chunks are generated, before files are written. Modify or add output files programmatically.

closeBundle()

Called after the bundle has been written. Use for post-build tasks like notifications or upload scripts.

Writing a custom plugin

Custom plugins are declared inline in lunx.config.ts or in a separate file. The TypeScript type LunxPlugin provides full autocomplete.

typescriptlunx.config.ts
import { defineConfig, type LunxPlugin } from 'lunx-dev'

// Inline plugin — injects a build banner into every JS chunk
function bannerPlugin(banner: string): LunxPlugin {
  return {
    name: 'banner-plugin',
    generateBundle(options, bundle) {
      for (const [fileName, chunk] of Object.entries(bundle)) {
        if (chunk.type === 'chunk') {
          chunk.code = `/* ${banner} */\n${chunk.code}`
        }
      }
    }
  }
}

// Virtual module plugin — exposes build metadata to the app
function buildInfoPlugin(): LunxPlugin {
  const virtualId = 'virtual:build-info'
  const resolvedId = '\0' + virtualId

  return {
    name: 'build-info',
    resolveId(id) {
      if (id === virtualId) return resolvedId
    },
    load(id) {
      if (id === resolvedId) {
        return `export const buildTime = '${new Date().toISOString()}';
export const version = '${process.env.npm_package_version}';`
      }
    }
  }
}

export default defineConfig({
  framework: 'react',
  plugins: [
    bannerPlugin('Built with Lunx v1.0.0'),
    buildInfoPlugin(),
  ],
})

Using the virtual module in your app

typescript
// src/components/Footer.tsx
import { buildTime, version } from 'virtual:build-info'

export function Footer() {
  return (
    <footer className="text-xs text-gray-500 p-4 text-center">
      v{version} — built {new Date(buildTime).toLocaleDateString()}
    </footer>
  )
}

Transform plugin example

Use the transform hook to modify source code at compile time. The example below strips all console.log calls from production builds.

typescript
function stripConsolePlugin(): LunxPlugin {
  return {
    name: 'strip-console',
    transform(code, id) {
      // Only run in production, skip node_modules
      if (process.env.NODE_ENV !== 'production') return
      if (id.includes('node_modules')) return

      const cleaned = code.replace(
        /console\.log\([^)]*\);?/g,
        '/* console.log removed */'
      )
      return { code: cleaned, map: null }
    }
  }
}
Plugin sandbox
Third-party plugins run inside the Lunx sandbox. They must declare required permissions (network access, file system write) in their package.json manifest. Undeclared permissions are blocked and logged as a fatal error. Run lunx security plugins to audit installed plugins.