npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

complugin

v1.1.4

Published

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

Downloads

159

Readme

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

| Hook | Rollup | Vite | Webpack4 | Webpack5 | esbuild | | ----------------------------------------------------------------------------- | :----: | :--: | :------: | :------: | :-----: | | 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