阿里云主机折上折
  • 微信号
Current Site:Index > Plugin execution order control

Plugin execution order control

Author:Chuan Chen 阅读数:54214人阅读 分类: 构建工具

Plugin Execution Order Control

Vite.js's plugin system is based on Rollup's plugin mechanism, where the execution order of plugins directly affects the build results. Understanding and controlling plugin execution order is key to optimizing the build process. Issues with plugin order typically arise when multiple plugins need to work together, such as when one plugin transforms code and another needs to process the result.

Basics of Plugin Execution Order

Vite plugins execute in two phases: hooks like resolveId, load, and transform belong to the build phase, while hooks like buildStart and buildEnd belong to the output phase. By default, plugins execute in the order they are listed in the array:

// vite.config.js
export default {
  plugins: [
    pluginA(), // executes first
    pluginB()  // executes later
  ]
}

However, certain hooks support modes like sequential (execute in order), parallel (execute in parallel), or first (terminate early). For example, the transform hook defaults to sequential, while resolveId defaults to first.

Methods to Control Execution Order

1. Explicit Sorting

Adjust the position using the enforce property:

// vite.config.js
export default {
  plugins: [
    {
      ...pluginA(),
      enforce: 'pre' // executes early
    },
    pluginB(), // normal order
    {
      ...pluginC(),
      enforce: 'post' // executes late
    }
  ]
}

Possible values for enforce:

  • pre: Executes before core plugins
  • default: Normal order
  • post: Executes after core plugins

2. Hook Priority

Some hooks can explicitly pass control by returning null:

function myPlugin() {
  return {
    name: 'my-plugin',
    resolveId(source) {
      if (source.startsWith('@/')) return null // let subsequent plugins handle it
      return source
    }
  }
}

3. Conditional Execution

Use the apply property to control when a plugin is active:

// vite.config.js
export default {
  plugins: [
    {
      ...pluginA(),
      apply: 'build' // only executes during build
    }
  ]
}

Practical Examples

CSS Preprocessing Scenario

Compile Sass first, then add browser prefixes:

import sass from 'sass'
import autoprefixer from 'autoprefixer'

export default {
  plugins: [
    {
      name: 'vite-sass-preprocessor',
      transform(code, id) {
        if (id.endsWith('.scss')) {
          return sass.compileString(code).css
        }
      },
      enforce: 'pre'
    },
    {
      name: 'vite-autoprefixer',
      transform(code, id) {
        if (id.endsWith('.css')) {
          return autoprefixer.process(code).css
        }
      }
    }
  ]
}

Multi-Plugin Collaboration Example

Typical order when processing Vue SFCs:

export default {
  plugins: [
    vue(), // first parse Vue single-file components
    {
      ...imageOptimizer(),
      enforce: 'post' // optimize images last
    }
  ]
}

Debugging Plugin Order

Use the --debug flag to inspect plugin execution:

vite build --debug

The output will show the execution order and time consumption of each plugin hook, which is very helpful for optimizing plugin order.

Advanced Control Techniques

1. Manually Triggering Hooks

function myPlugin() {
  return {
    name: 'manual-hook',
    buildStart() {
      this.emitFile({
        type: 'chunk',
        id: 'virtual-module',
        name: 'virtual-module'
      })
    }
  }
}

2. Dynamically Adjusting Order

export default {
  plugins: [
    {
      name: 'dynamic-order',
      config(config) {
        if (config.mode === 'development') {
          return {
            plugins: [devPlugin()]
          }
        }
      }
    }
  ]
}

3. Hook Interception

function interceptorPlugin() {
  return {
    name: 'hook-interceptor',
    transform(code, id) {
      if (id.includes('intercept')) {
        return code.replace('foo', 'bar')
      }
    }
  }
}

Common Problem Solutions

Handling Plugin Conflicts

When two plugins process the same type of file:

export default {
  plugins: [
    {
      ...markdownPlugin(),
      enforce: 'pre',
      apply: 'serve' // only process markdown during development
    },
    {
      ...anotherMarkdownPlugin(),
      enforce: 'post'
    }
  ]
}

Performance Optimization Order

Place time-consuming plugins last:

export default {
  plugins: [
    basicTransforms(),
    {
      ...expensivePlugin(),
      enforce: 'post'
    }
  ]
}

Plugin Order and Build Modes

Different orders may be needed for development and production modes:

export default {
  plugins: [
    mode === 'production' ? productionPlugin() : null,
    devOnlyPlugin()
  ].filter(Boolean)
}

Plugin Metadata Exchange

Pass information via the meta property:

function firstPlugin() {
  return {
    name: 'first',
    transform(code) {
      this.meta.myData = 'processed'
    }
  }
}

function secondPlugin() {
  return {
    name: 'second',
    transform(code) {
      console.log(this.meta.myData) // retrieve data from upstream plugins
    }
  }
}

Virtual Module Processing Order

Special attention is needed for virtual modules:

function virtualModulePlugin() {
  const virtualId = 'virtual:module'
  return {
    name: 'virtual-module',
    resolveId(id) {
      if (id === virtualId) return virtualId
    },
    load(id) {
      if (id === virtualId) return 'export default "content"'
    }
  }
}

Such plugins typically require enforce: 'pre' to ensure they execute first.

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.