Skip to content

插件系统

robuild 提供了灵活的插件系统,允许你扩展和自定义构建功能。

什么是插件?

插件是扩展 robuild 功能的模块,可以:

  • 转换代码: 修改源码内容
  • 处理资源: 处理非 JavaScript 文件
  • 添加功能: 集成外部工具和服务
  • 自定义输出: 修改构建结果

插件类型

1. Rolldown 插件

用于 Bundle 模式的插件,基于 rolldown 的插件系统:

typescript
import { defineConfig } from 'robuild'

export default defineConfig({
  entries: [
    {
      type: 'bundle',
      input: './src/index.ts',
      rolldown: {
        plugins: [
          // 使用 rolldown 插件
          {
            name: 'my-plugin',
            setup(build) {
              // 插件逻辑
            }
          }
        ]
      }
    }
  ]
})

2. Oxc 插件

用于 Transform 模式的插件,基于 oxc 的转换系统:

typescript
export default defineConfig({
  entries: [
    {
      type: 'transform',
      input: './src/runtime',
      oxc: {
        plugins: [
          // oxc 插件配置
          {
            name: 'transform-plugin',
            transform(code, id) {
              // 转换逻辑
              return code
            }
          }
        ]
      }
    }
  ]
})

内置插件

1. Shebang 插件

自动处理 shebang 行:

typescript
import { shebangPlugin } from 'robuild/plugins'

export default defineConfig({
  entries: [
    {
      type: 'bundle',
      input: './src/cli.ts',
      rolldown: {
        plugins: [shebangPlugin()]
      }
    }
  ]
})

功能:

  • 自动添加 shebang 行到 CLI 文件
  • 支持自定义 shebang 内容
  • 保持可执行权限

配置选项:

typescript
shebangPlugin({
  shebang: '#!/usr/bin/env node',
  preserve: true
})

2. JSON 插件

处理 JSON 文件:

typescript
import { jsonPlugin } from 'robuild/plugins'

export default defineConfig({
  entries: [
    {
      type: 'bundle',
      input: './src/index.ts',
      rolldown: {
        plugins: [jsonPlugin()]
      }
    }
  ]
})

功能:

  • 导入 JSON 文件作为模块
  • 支持 JSON 路径映射
  • 自动类型推断

创建自定义插件

1. 基本插件结构

typescript
// my-plugin.ts
interface MyPluginOptions {
  prefix?: string
  suffix?: string
}

export function myPlugin(options: MyPluginOptions = {}) {
  const { prefix = '', suffix = '' } = options

  return {
    name: 'my-plugin',
    setup(build) {
      // 插件初始化逻辑
      console.log('My plugin initialized')
    },
    transform(code, id) {
      // 代码转换逻辑
      if (id.endsWith('.ts') || id.endsWith('.js')) {
        return `${prefix}${code}${suffix}`
      }
      return code
    }
  }
}

2. 使用自定义插件

typescript
import { defineConfig } from 'robuild'
import { myPlugin } from './my-plugin'

export default defineConfig({
  entries: [
    {
      type: 'bundle',
      input: './src/index.ts',
      rolldown: {
        plugins: [
          myPlugin({
            prefix: '// Generated by my-plugin\n',
            suffix: '\n// End of generated code'
          })
        ]
      }
    }
  ]
})

插件生命周期

1. 插件初始化

typescript
{
  name: 'my-plugin',
  setup(build) {
    // 在构建开始时调用一次
    console.log('插件初始化')

    // 可以访问构建上下文
    console.log('构建配置:', build.config)
  }
}

2. 代码转换

typescript
{
  name: 'my-plugin',
  transform(code, id) {
    // 对每个文件调用
    if (id.endsWith('.ts')) {
      // 转换 TypeScript 文件
      return code.replace(/console\.log/g, '// console.log')
    }
    return code
  }
}

3. 构建钩子

typescript
{
  name: 'my-plugin',
  setup(build) {
    build.onStart(() => {
      console.log('构建开始')
    })

    build.onEnd((result) => {
      console.log('构建结束', result)
    })
  }
}

实际插件示例

1. 环境变量替换插件

typescript
// env-replace-plugin.ts
interface EnvReplaceOptions {
  env?: Record<string, string>
  prefix?: string
}

export function envReplacePlugin(options: EnvReplaceOptions = {}) {
  const { env = process.env, prefix = 'process.env.' } = options

  return {
    name: 'env-replace',
    transform(code, id) {
      // 替换 process.env.VARIABLE 为实际值
      return code.replace(
        new RegExp(`${prefix}(\\w+)`, 'g'),
        (match, key) => {
          const value = env[key]
          return value ? JSON.stringify(value) : 'undefined'
        }
      )
    }
  }
}

2. 文件大小分析插件

typescript
// size-analyzer-plugin.ts
import { readFileSync } from 'fs'
import { join } from 'path'

export function sizeAnalyzerPlugin() {
  return {
    name: 'size-analyzer',
    setup(build) {
      build.onEnd((result) => {
        console.log('\n文件大小分析:')

        result.outputFiles?.forEach(file => {
          const stats = readFileSync(file).length
          const sizeKB = (stats / 1024).toFixed(2)
          console.log(`  ${file}: ${sizeKB} KB`)
        })
      })
    }
  }
}

3. 自动导入插件

typescript
// auto-import-plugin.ts
interface AutoImportOptions {
  imports: Record<string, string[]>
}

export function autoImportPlugin(options: AutoImportOptions) {
  const { imports } = options

  return {
    name: 'auto-import',
    transform(code, id) {
      if (!id.endsWith('.ts') && !id.endsWith('.js')) {
        return code
      }

      let importStatements = ''

      // 检查代码中使用的导入
      Object.entries(imports).forEach(([module, exports]) => {
        const used = exports.filter(exp =>
          new RegExp(`\\b${exp}\\b`).test(code)
        )

        if (used.length > 0) {
          importStatements += `import { ${used.join(', ')} } from '${module}'\n`
        }
      })

      return importStatements + code
    }
  }
}

插件配置最佳实践

1. 类型安全

typescript
// 定义插件选项类型
interface MyPluginOptions {
  enabled?: boolean
  config?: Record<string, any>
}

// 使用类型安全的插件
export function myPlugin(options: MyPluginOptions = {}) {
  const { enabled = true, config = {} } = options

  if (!enabled) {
    return { name: 'my-plugin' } // 空插件
  }

  return {
    name: 'my-plugin',
    setup(build) {
      // 使用配置
      console.log('配置:', config)
    }
  }
}

2. 错误处理

typescript
export function safePlugin() {
  return {
    name: 'safe-plugin',
    transform(code, id) {
      try {
        // 插件逻辑
        return modifiedCode
      } catch (error) {
        console.error(`插件错误 (${id}):`, error)
        return code // 返回原始代码
      }
    }
  }
}

3. 性能优化

typescript
export function optimizedPlugin() {
  const cache = new Map()

  return {
    name: 'optimized-plugin',
    transform(code, id) {
      // 使用缓存避免重复处理
      if (cache.has(id)) {
        return cache.get(id)
      }

      const result = processCode(code)
      cache.set(id, result)
      return result
    }
  }
}

插件生态系统

1. 官方插件

robuild 提供了一些官方插件:

typescript
import {
  shebangPlugin,
  jsonPlugin,
  // 更多官方插件...
} from 'robuild/plugins'

2. 社区插件

社区维护的插件:

typescript
import {
  vuePlugin,
  reactPlugin,
  // 更多社区插件...
} from '@robuild/plugins'

3. 插件开发

开发自己的插件:

bash
# 创建插件项目
mkdir robuild-plugin-example
cd robuild-plugin-example
npm init -y

# 安装开发依赖
npm install --save-dev typescript @types/node

插件调试

1. 调试模式

typescript
export default defineConfig({
  entries: ['./src/index.ts'],
  rolldown: {
    plugins: [
      {
        name: 'debug-plugin',
        setup(build) {
          // 启用调试日志
          if (process.env.DEBUG) {
            console.log('插件调试信息:', build.config)
          }
        }
      }
    ]
  }
})

2. 插件测试

typescript
// 测试插件
import { myPlugin } from './my-plugin'

const plugin = myPlugin({ prefix: '// TEST' })
const result = plugin.transform('console.log("hello")', 'test.js')
console.log(result) // // TEST\nconsole.log("hello")

下一步

Released under the MIT License.