1.1.4 • Published 2 years ago

complugin v1.1.4

Weekly downloads
-
License
MIT
Repository
-
Last release
2 years ago

complugin

npm size

Unified plugin system for bundle-tools.(e.g. rollback, vite, webpack, esbuild).

Currently supports:

Note

  1. In Webpack, please don't use thread-loader.
  2. In Rollup, Complugin cannot be used as an output plugin.
  3. In esbuild, please use complugin.proxyEsbuild(esbuild).build({/* options */}) instead of esbuild.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 unified hooks-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

HookRollupViteWebpack4Webpack5esbuild
buildStart
resolveId
load
transformInclude1
transform2
buildEnd
generateBundle3
  1. 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.
  2. Although esbuild can handle both JavaScript and CSS and many other file formats, you can only return JavaScript in load and transform results.
  3. 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