Co-authored-by: wawa0584 <60140118+WestonSeyler@users.noreply.github.com> Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
11 KiB
| outline | lastUpdated |
|---|---|
| deep | false |
Getting Started
Overview
Unplugin is a library that offers an unified plugin system for various build tools. It extends the excellent Rollup plugin API to serve as the standard plugin interface, and provides a compatibility layer based on the build tools employed.
Unplugin current supports:
Trying It Online
You can try Unplugin in your browser directly.
Creating an Unplugin package
npx degit unplugin/unplugin-starter unplugin-starter
Check the unplugin-starter repository for more details.
Plugin Installation
Pre-requisites
- Node.js 14.0.0 or later
::: warning We will discontinue support for Node.js v14 & v16 in the next major release. Please consider upgrading to Node.js v18 or higher. :::
Install package
::: code-group
npm install unplugin-starter --save-dev
yarn add unplugin-starter -D
pnpm add unplugin-starter -D
bun add unplugin-starter -D
:::
Bundler & Framework Integration
::: code-group
// vite.config.ts
import Starter from 'unplugin-starter/vite'
export default defineConfig({
plugins: [
Starter({ /* options */ }),
],
})
// rollup.config.js
import Starter from 'unplugin-starter/rollup'
export default {
plugins: [
Starter({ /* options */ }),
],
}
// webpack.config.js
module.exports = {
/* ... */
plugins: [
require('unplugin-starter/webpack')({ /* options */ })
]
}
// rspack.config.js
module.exports = {
/* ... */
plugins: [
require('unplugin-starter/rspack')({ /* options */ })
]
}
// esbuild.config.js
import { build } from 'esbuild'
import Starter from 'unplugin-starter/esbuild'
build({
plugins: [Starter()],
})
// vue.config.js
module.exports = {
configureWebpack: {
plugins: [
require('unplugin-starter/webpack')({ /* options */ }),
],
},
}
// nuxt.config.ts
export default defineNuxtConfig({
modules: [
['unplugin-starter/nuxt', { /* options */ }],
],
})
// astro.config.mjs
import { defineConfig } from 'astro/config'
import Starter from 'unplugin-turbo-console/astro'
// https://astro.build/config
export default defineConfig({
integrations: [
Starter()
]
})
Supported Hooks
| Hook | Rollup | Vite | webpack 4 | webpack 5 | esbuild | Rspack |
|---|---|---|---|---|---|---|
enforce |
❌ 1 | ✅ | ✅ | ✅ | ❌ 1 | ✅ |
buildStart |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
resolveId |
✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
loadInclude2 |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
load |
✅ | ✅ | ✅ | ✅ | ✅ 3 | ✅ |
transformInclude2 |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
transform |
✅ | ✅ | ✅ | ✅ | ✅ 3 | ✅ |
watchChange |
✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
buildEnd |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
writeBundle4 |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
::: details Notice
- Rollup and esbuild do not support using
enforceto control the order of plugins. Users need to maintain the order manually. - webpack's id filter is outside of loader logic; an additional hook is needed for better perf on webpack. In Rollup and Vite, this hook has been polyfilled to match the behaviors. See for the following usage examples.
- Although esbuild can handle both JavaScript and CSS and many other file formats, you can only return JavaScript in
loadandtransformresults. - Currently,
writeBundleis only serves as a hook for the timing. It doesn't pass any arguments. :::
Usage
import type { UnpluginFactory } from 'unplugin'
import { createUnplugin } from 'unplugin'
export interface Options {
// define your plugin options here
}
export const unpluginFactory: UnpluginFactory<Options | undefined> = options => ({
name: 'unplugin-starter',
// webpack's id filter is outside of loader logic,
// an additional hook is needed for better perf on webpack
transformInclude(id) {
return id.endsWith('main.ts')
},
// just like rollup transform
transform(code) {
return code.replace(/<template>/, '<template><div>Injected</div>')
},
// more hooks coming
})
export const unplugin = /* #__PURE__ */ createUnplugin(unpluginFactory)
export default unplugin
export const vitePlugin = unplugin.vite
export const rollupPlugin = unplugin.rollup
export const webpackPlugin = unplugin.webpack
export const rspackPlugin = unplugin.rspack
export const esbuildPlugin = unplugin.esbuild
Supported Context
| Context | Rollup | Vite | webpack 4 | webpack 5 | esbuild | Rspack |
|---|---|---|---|---|---|---|
this.parse |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
this.addWatchFile |
✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
this.emitFile1 |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
this.getWatchFiles |
✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
this.warn |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
this.error |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
::: info Notice
- Currently,
this.emitFileonly supports theEmittedAssetvariant. :::
Nested Plugins
Since v0.10.0, Unplugin supports constructing multiple nested plugins to behave like a single one.
Bundler Supported
| Rollup | Vite | webpack 4 | webpack 5 | Rspack | esbuild |
|---|---|---|---|---|---|
✅ >=3.11 |
✅ | ✅ | ✅ | ✅ | ✅ (v1.8.0+) |
::: details Notice
- Rollup supports nested plugins since v3.1.0. Plugin author should ask users to have a Rollup version of
>=3.1.0when using nested plugins. For single plugin format, Unplugin works for any version of Rollup. :::
Usage
import type { UnpluginFactory } from 'unplugin'
import { createUnplugin } from 'unplugin'
export interface Options {
// define your plugin options here
}
export const unpluginFactory: UnpluginFactory<Options | undefined> = options => (
[
{
name: 'plugin-a',
transform(code) {
return code.replace(/<template>/, '<template><div>Injected</div>')
},
},
{
name: 'plugin-b',
resolveId(id) {
return id
},
},
]
)
export const unplugin = /* #__PURE__ */ createUnplugin(unpluginFactory)
export default unplugin
Bundler-Specific Logic
While Unplugin provides compatible layers for some hooks, the functionality of it is limited to the common subset of the build's plugins capability. For more advanced bundler-specific usages, Unplugin provides an escape hatch for that.
Hooks
import type { UnpluginFactory } from 'unplugin'
import { createUnplugin } from 'unplugin'
export interface Options {
// define your plugin options here
}
export const unpluginFactory: UnpluginFactory<Options | undefined> = (options, meta) => {
console.log(meta.framework) // vite rollup webpack esbuild rspack
return {
name: 'unplugin-starter',
transform(code) {
return code.replace(/<template>/, '<template><div>Injected</div>')
},
transformInclude(id) {
return id.endsWith('main.ts')
},
vite: {
// Vite plugin
configureServer(server) {
// configure Vite server
},
},
rollup: {
// Rollup plugin
},
webpack(complier) {
// Configure webpack compiler
},
rspack(complier) {
// Configure webpack compiler
},
esbuild: {
// Change the filter of onResolve and onLoad
// onResolveFilter?: RegExp,
// onLoadFilter?: RegExp,
// Tell esbuild how to interpret the contents. By default Unplugin tries to guess the loader
// from file extension (eg: .js -> "js", .jsx -> 'jsx')
// loader?: (Loader | (code: string, id: string) => Loader)
// Or you can completely replace the setup logic
// setup?: EsbuildPlugin.setup,
},
}
}
export const unplugin = /* #__PURE__ */ createUnplugin(unpluginFactory)
export default unplugin
Plugins
The package exports a set of functions in place of createUnplugin that allow for the creation of plugins for specific bundlers.
Each of the function takes the same generic factory argument as createUnplugin.
import {
createEsbuildPlugin,
createRollupPlugin,
createRspackPlugin,
createVitePlugin,
createWebpackPlugin
} from 'unplugin'
const vitePlugin = createVitePlugin({ /* options */ })
const rollupPlugin = createRollupPlugin({ /* options */ })
const esbuildPlugin = createEsbuildPlugin({ /* options */ })
const webpackPlugin = createWebpackPlugin({ /* options */ })
const rspackPlugin = createRspackPlugin({ /* options */ })