Oasis's Cloud

一个人的首要责任,就是要有雄心。雄心是一种高尚的激情,它可以采取多种合理的形式。
—— 《一个数学家的辩白》

Taro 构建流程源码分析

作者:oasis


概述

本文基于源码分析 taro build --type weapp 命令的执行过程,深入理解 Taro 的构建机制和插件化架构。

1.png

核心模块

构建过程主要涉及以下几个关键类和模块:

  1. Config 类 (packages/taro-service/src/Config.ts) - 配置管理
  2. Weapp 平台类 (packages/taro-platform-weapp/src/program.ts) - 微信小程序平台适配
  3. MiniCombination 类 (packages/taro-webpack5-runner/src/webpack/MiniCombination.ts) - 小程序构建配置组合
  4. React/Vue3 框架插件 - 框架层面的处理

构建流程

1. 配置初始化

首先,Config 类会初始化项目配置。配置初始化逻辑位于 packages/taro-service/src/Config.ts

async init (configEnv: {
    mode: string
    command: string
  }) {
    this.initialConfig = {}
    this.initialGlobalConfig = {}
    this.isInitSuccess = false
    this.configPath = resolveScriptPath(path.join(this.appPath, CONFIG_DIR_NAME, DEFAULT_CONFIG_FILE))
    if (!fs.existsSync(this.configPath)) {
      if (this.disableGlobalConfig) return
      this.initGlobalConfig()
    } else {
      createSwcRegister({
        only: [
          filePath => filePath.indexOf(path.join(this.appPath, CONFIG_DIR_NAME)) >= 0
        ]
      })
      try {
        const userExport = getModuleDefaultExport(require(this.configPath))
        this.initialConfig = typeof userExport === 'function' ? await userExport(merge, configEnv) : userExport
        this.isInitSuccess = true
      } catch (err) {
        console.log(err)
      }
    }
  }

关键点: - 查找并加载 config/index.ts 配置文件 - 使用 SWC 注册器处理配置文件 - 支持函数式和对象式两种配置导出方式

2. 平台初始化

平台类负责特定平台的适配工作。以微信小程序为例,packages/taro-platform-weapp/src/program.ts

constructor (ctx, config, pluginOptions?: IOptions) {
    super(ctx, config)
    this.template = new Template(pluginOptions)
    this.setupTransaction.addWrapper({
      close () {
        this.modifyTemplate(pluginOptions)
        this.modifyWebpackConfig()
      }
    })
  }

关键点: - 初始化模板处理器 - 通过事务机制在构建完成后修改模板和 webpack 配置

3. 框架插件处理

框架插件根据使用的框架(React/Vue3)进行相应的处理。以 React 框架为例,packages/taro-framework-react/src/index.ts

export default (ctx: IPluginContext) => {
  const { framework = 'react' } = ctx.initialConfig

  if (!isReactLike(framework)) return

  ctx.modifyWebpackChain(({ chain }) => {
    // 通用
    setAlias(framework, chain)

    if (process.env.TARO_PLATFORM === 'web') {
      // H5
      modifyH5WebpackChain(ctx, framework, chain)
    } else if (process.env.TARO_PLATFORM === 'harmony' || process.env.TARO_ENV === 'harmony') {
      // 鸿蒙
      modifyHarmonyWebpackChain(ctx, framework, chain)
    } else {
      // 小程序
      modifyMiniWebpackChain(ctx, framework, chain)
    }
  })
}

关键点: - 根据平台类型(H5/鸿蒙/小程序)选择不同的 webpack 配置修改函数 - 设置框架相关的别名和配置

4. 构建配置处理

MiniCombination 类负责组合最终的 webpack 配置,packages/taro-webpack5-runner/src/webpack/MiniCombination.ts

process (config: Partial<IMiniBuildConfig>) {
    const baseConfig = new MiniBaseConfig(this.appPath, config)
    const chain = this.chain = baseConfig.chain
    const {
      entry = {},
      output = {},
      mode = 'production',
      globalObject = 'wx',
      sourceMapType = 'cheap-module-source-map',
      fileType = {
        style: '.wxss',
        config: '.json',
        script: '.js',
        templ: '.wxml'
      },
      /** special mode */
      isBuildPlugin = false,
      /** hooks */
      modifyComponentConfig,
      optimizeMainPackage
    } = config

    this.fileType = fileType

    modifyComponentConfig?.(componentConfig, config)

    if (isBuildPlugin) {
      // 编译目标 - 小程序原生插件
      this.isBuildPlugin = true
      this.buildNativePlugin = BuildNativePlugin.getPlugin(this)
      chain.merge({
        context: path.join(process.cwd(), this.sourceRoot, 'plugin')
      })
    }

    if (optimizeMainPackage) {
      this.optimizeMainPackage = optimizeMainPackage
    }

    const webpackEntry = this.getEntry(entry)
    const webpackOutput = this.getOutput({
      publicPath: '/',
      globalObject,
      isBuildPlugin,
      output
    })
}

关键点: - 设置小程序文件类型(.wxss.json.js.wxml) - 处理小程序原生插件构建场景 - 配置 webpack 入口和输出

配置合并机制

配置的合并遵循以下层次结构:

  1. 基础配置:来自 config/index.ts 的用户配置
  2. 平台配置:由 Weapp 平台类提供平台特定配置
  3. 框架配置:由框架插件注入框架相关配置
  4. 构建配置:由 webpack5-runner 处理最终的构建配置

环境变量设置

在构建过程中,会设置以下环境变量(packages/taro-vite-runner/src/mini/config.ts):

env.FRAMEWORK = JSON.stringify(framework)
env.TARO_ENV = JSON.stringify(buildAdapter)
env.TARO_PLATFORM = JSON.stringify(process.env.TARO_PLATFORM || PLATFORM_TYPE.MINI)
env.NODE_ENV = JSON.stringify(process.env.NODE_ENV)
env.SUPPORT_TARO_POLYFILL = env.SUPPORT_TARO_POLYFILL || '"disabled"'

这些环境变量在编译时会被注入到代码中,用于区分不同的构建目标和运行环境。

总结

Taro 的构建过程体现了其插件化架构的核心设计理念:

这种架构设计使得 Taro 能够支持多平台、多框架的跨平台开发,同时保持了代码的可维护性和可扩展性。