complugin
v1.1.4
Published
Unified plugin system for bundle tools.(e.g. rollback, vite, webpack, esbuild)
Downloads
125
Maintainers
Readme
complugin
Unified plugin system for bundle-tools.(e.g. rollback, vite, webpack, esbuild).
Currently supports:
Note
- In
Webpack
, please don't usethread-loader
. - In
Rollup
,Complugin
cannot be used as an output plugin. - In
esbuild
, please usecomplugin.proxyEsbuild(esbuild).build({/* options */})
instead ofesbuild.build({/* options */})
.
Usage
import { createComplugin } from 'complugin'
interface Options {}
export default createComplugin<Options>({
name: 'my-first-complugin',
// A complugin can additionally specify an enforce property to adjust its application order. The value of enforce can be either "pre" or "post".
enforce: 'pre',
factory(options, meta) {
// Do specific things according to different bundlers.
switch (meta.framework) {
case 'rollup':
// ...
break
case 'vite':
// ...
break
case 'esbuild':
// ...
break
case 'webpack':
// ...
break
default:
// Other bundlers
}
return {
buildStart() {
// ...
},
resolveId(importee, importer) {
// ...
},
load(id) {
// ...
},
transformInclude(id) {
// ...
return false
},
transform(code, id) {
// ...
},
buildEnd() {
// ...
},
generateBundle(bundle, rawBundle) {
// ...
}
}
}
})
Plugin Installation
Vite
// vite.config.ts
import MyComplugin from './my-complugin'
export default {
plugins: [
MyComplugin.vite({
/* options */
}),
// Or
MyComplugin({
/* options */
}).vite
]
}
Rollup
// rollup.config.js
import MyComplugin from './my-complugin'
export default {
plugins: [
MyComplugin.rollup({
/* options */
}),
// Or
MyComplugin({
/* options */
}).rollup
]
}
Webpack
// webpack.config.js
const MyComplugin = require('./my-complugin').default
module.exports = {
plugins: [
MyComplugin.webpack({
/* options */
}),
// Or
MyComplugin({
/* options */
}).webpack
]
}
esbuild
// esbuild.config.js
import _esbuild from 'esbuild'
import { proxyEsbuild } from 'complugin'
import MyComplugin from './my-complugin'
// Cannot be omitted
const esbuild = proxyEsbuild(_esbuild)
esbuild.build({
plugins: [
MyComplugin.esbuild({
/* options */
}),
// Or
MyComplugin({
/* options */
}).esbuild
]
})
Hooks
complugin
takes the excellent Rollup plugin API as a reference, and provides a unifiedhooks-API
for various bundle-tools.
buildStart
Type: (this: CompluginMinifyContext) => void
Kind: async
Next Hook: resolveId
Called when the bundle-tool starts building.
resolveId
Type: (importee: string, importer?: string) => string | { id: string, external?: boolean } | { name?: string, source: string | Buffer } | null
Kind: async
Next Hook: load
if the resolved id that has not yet been loaded
Defines a custom resolver. A resolver can be useful for e.g. locating third-party dependencies.
Returning null defers to other resolveId
functions and eventually the default resolution behavior.
If an object is returned and the string attribute "id"
is set, the import can be resolved to a different ID and excluded from the bundle. This allows you to replace dependencies with external dependencies without requiring users to manually mark them as "external"
through external options.
If an object is returned and the attribute "source"
is set, the value of "source"
is taken as the asset content and an asset file is emitted.
load
Type: (this: CompluginContext, id: string) => string | { code: string, map?: object, ast?: AcornNode } | { code: string, copy: true } | null
Kind: async
Next Hook: transformInclude
if no cache was used, or there was no cached copy with the same code
Defines a custom loader. Returning null
defers to other load
functions (and eventually the default behavior of loading from the file system). this hook can optionally return a { code, map, ast }
object.
transformInclude
Type: (id: string) => boolean
Next Hook: transform
if true
is returned
Whether transform is enabled. If this hook is not set, all transformations are enabled.
transform
Type: (this: CompluginContext, code: string, id: string, ast?: AcornNode) => string | { code: string, map?: object, ast?: AcornNode } | null
Can be used to transform individual modules. this hook can optionally return a { code, map, ast }
object. If the transformation does not move code, you can preserve existing sourcemaps
by setting map to null
. Otherwise you might need to generate the source map.
buildEnd
Type: (this: CompluginMinifyContext) => void
Kind: async
Next Hook: generateBundle
Called when bundler-tool has finished bundling.
generateBundle
Type: (bundle: { [fileName: string]: OutputFile }, rawBundle: unknown) => void
Called when bundler-tool has generated bundle object. You can prevent files from being emitted by deleting them from the bundle object in this hook.
Hooks Supported
| Hook | Rollup | Vite | Webpack4 | Webpack5 | esbuild |
| ----------------------------------------------------------------------------- | :----: | :--: | :------: | :------: | :-----: |
| buildStart
| ✅ | ✅ | ✅ | ✅ | ✅ |
| resolveId
| ✅ | ✅ | ✅ | ✅ | ✅ |
| load
| ✅ | ✅ | ✅ | ✅ | ✅ |
| transformInclude
1 | ✅ | ✅ | ✅ | ✅ | ✅ |
| transform
2 | ✅ | ✅ | ✅ | ✅ | ✅ |
| buildEnd
| ✅ | ✅ | ✅ | ✅ | ✅ |
| generateBundle
3 | ✅ | ✅ | ✅ | ✅ | ✅ |
Webpack
's id filter is outside of loader logic; an additional hook is needed for better perf onWebpack
. InRollup
andVite
, this hook has been polyfilled to match the behaviors.- Although
esbuild
can handle both JavaScript and CSS and many other file formats, you can only return JavaScript inload
andtransform
results. - In order to be compatible with various construction tools, this hook is not compatible with rollup's
generateBundle-hook
at design.
CompluginMinifyContext
emitFile
Type: (asset: { name?: string, fileName?: string, source: string | Buffer }) => void
Emits a new asset file that is included in the build output.
error
Type: (message: string) => never | void
Structurally equivalent to this.warn
, except that it will also abort the bundling process when the bundler is rollup
or vite
.
warn
Type: (message: string) => void
Using this method will queue warnings for a build.
resolve
Type: (importee: string, importer?: string) => Promise<{ id: string; external?: boolean } | undefined>
Resolve imports to module ids (i.e. file names) using the same plugins that bundler uses, and determine if an import should be external. If null is returned, the import could not be resolved by bundler or any plugin but was not explicitly marked as external by the user.
In webpack
, some module-id cannot be correctly identified as external.
parse
Type: (input: string, options?: AcornOptions) => AcornNode
Use acorn
library to parse code to an AST.
CompluginContext
emitAsset
Type: (asset: { name?: string, fileName?: string, source: string | Buffer }): string
Emits a new asset file that is included in the build output and returns a placeholder-expression that can be used in various places to reference the emitted file.
e.g:
const hooks = {
// ...others hook,
load(id) {
const placeholder = this.emitAsset({ name: 'hello world.txt', source: 'hello world!' })
return `
import { readFile } from 'fs/promises'
const fileName = ${placeholder}
readFile(fileName).then((content) => {
console.log(content.toString()) // hello world!
})
`
}
}
addWatchFile
Type: (fileName: string) => void
Adds additional files to be monitored in watch mode so that changes to these files will trigger rebuilds.
rebuild
(New)
Type: () => void
force rebuild.
API
createComplugin
Type: <UserOptions = {}>(args: CreateCompluginArgs<UserOptions>) => CompluginInstance<UserOptions>
create a complugin.
utils
plugin utils.
proxyEsbuild
Type: (esbuild: typeof import('esbuild')) => typeof import('esbuild')
At present, the generated esbuild-plugin needs to run in the esbuild environment proxied by proxyEsbuild()
.
registerCompluginGenerator
Type: (framework: string, generator: <UserOptions = {}>(args: CreateCompluginArgs<UserOptions>, userOptions?: UserOptions) => any) => void
Register custom plugin generator.
e.g:
import { registerCompluginGenerator, commonInputFS } from 'complugin'
import MyComplugin from './my-complugin'
// Register
registerCompluginGenerator('custom', function ({ name, enforce, factory }, options) {
const meta = {
// required
framework: 'custom',
version: '1.0.0',
inputFS: { ...commonInputFS }
// ...others
}
const {
buildStart,
resolveId,
load,
transformInclude = () => true,
transform,
buildEnd,
generateBundle
} = factory(options, meta)
return // ...
})
// Usage
const createdCustomPlugin = MyComplugin.custom({
/* options */
})
const createdCustomPluginOr = MyComplugin({
/* options */
}).custom
Give a ⭐️ if this project helped you!
License
MIT License © 2022 xxXyh1908