配置 Babel 进行 ES6+ 代码转译

Babel 是现代 JavaScript 开发的核心工具,它能将 ES6+ 代码转译为向后兼容的 JavaScript 版本,让我们能够在各种环境中使用最新的语言特性。

Babel 是一个 JavaScript 编译器,主要用于:

  • 将 ES6+ 语法转换为 ES5 语法
  • 支持实验性的 JavaScript 特性
  • 添加缺失的 polyfill 来支持新的 API
  • 进行代码转换和优化
  • 预设 (Presets): 预配置的插件集合
  • 插件 (Plugins): 执行具体转换的代码
  • Polyfill: 为不支持的环境提供新 API 的实现
  • 目标环境 (Targets): 指定需要支持的浏览器或 Node.js 版本
# 安装 Babel 核心包和 CLI 工具
npm install --save-dev @babel/core @babel/cli

# 安装最常用的预设
npm install --save-dev @babel/preset-env

# 安装运行时支持(可选)
npm install --save-dev @babel/polyfill core-js@3
  • @babel/core: Babel 的核心编译器
  • @babel/cli: 命令行工具
  • @babel/preset-env: 智能预设,根据目标环境自动确定需要的转换
  • core-js: 现代 JavaScript 特性的 polyfill 库

创建 babel.config.js 文件:

module.exports = {
  presets: [
    [
      '@babel/preset-env',
      {
        // 目标环境配置
        targets: {
          node: 'current', // 针对当前 Node.js 版本
          browsers: ['> 1%', 'last 2 versions', 'not dead'], // 浏览器兼容性
        },
        // Polyfill 配置
        useBuiltIns: 'usage', // 按需引入 polyfill
        corejs: 3, // 指定 core-js 版本
        // 模块转换配置
        modules: false, // 保留 ES6 模块语法(用于 webpack 等工具的 tree-shaking)
      },
    ],
  ],
  plugins: [
    // 可选的插件
    '@babel/plugin-proposal-class-properties', // 支持类属性语法
    '@babel/plugin-proposal-optional-chaining', // 可选链操作符
    '@babel/plugin-proposal-nullish-coalescing-operator', // 空值合并操作符
  ],
  // 环境特定配置
  env: {
    development: {
      plugins: ['@babel/plugin-transform-runtime'], // 开发时优化
    },
    production: {
      plugins: [
        '@babel/plugin-transform-runtime',
        ['babel-plugin-transform-remove-console', { exclude: ['error', 'warn'] }], // 移除 console.log
      ],
    },
    test: {
      presets: [
        [
          '@babel/preset-env',
          {
            targets: { node: 'current' },
            modules: 'commonjs', // 测试环境使用 CommonJS
          },
        ],
      ],
    },
  },
};
module.exports = {
  presets: [
    [
      '@babel/preset-env',
      {
        targets: {
          browsers: ['> 1%', 'last 2 versions'],
        },
        useBuiltIns: 'usage',
        corejs: 3,
      },
    ],
  ],
};
module.exports = {
  presets: [
    [
      '@babel/preset-env',
      {
        targets: {
          node: '16', // 指定 Node.js 版本
        },
        useBuiltIns: 'usage',
        corejs: 3,
      },
    ],
  ],
};
module.exports = {
  presets: [
    [
      '@babel/preset-env',
      {
        targets: {
          browsers: [
            'Chrome >= 60',
            'Safari >= 10.1',
            'iOS >= 10.3',
            'Firefox >= 54',
            'Edge >= 15',
          ],
        },
        useBuiltIns: 'entry',
        corejs: 3,
      },
    ],
  ],
};

也可以在 package.json 中配置:

{
  "babel": {
    "presets": [
      [
        "@babel/preset-env",
        {
          "targets": {
            "node": "current"
          },
          "useBuiltIns": "usage",
          "corejs": 3
        }
      ]
    ]
  }
}

控制如何处理 polyfill:

// 'entry' - 在入口文件导入整个 polyfill
{
  useBuiltIns: 'entry',
  corejs: 3
}

// 'usage' - 按需自动导入(推荐)
{
  useBuiltIns: 'usage',
  corejs: 3
}

// false - 不自动添加 polyfill
{
  useBuiltIns: false
}

指定目标环境:

{
  targets: {
    // Node.js 版本
    node: '16',
    node: 'current',
    
    // 浏览器查询
    browsers: ['> 1%', 'last 2 versions'],
    browsers: ['Chrome >= 60', 'Safari >= 10'],
    
    // 特定浏览器版本
    chrome: '60',
    firefox: '54',
    safari: '10',
    ie: '11'
  }
}

控制模块转换:

{
  modules: false,      // 保留 ES6 模块(用于 webpack tree-shaking)
  modules: 'commonjs', // 转换为 CommonJS(Node.js)
  modules: 'amd',      // 转换为 AMD
  modules: 'umd',      // 转换为 UMD
  modules: 'auto'      // 自动检测
}

package.json 中添加构建脚本:

{
  "scripts": {
    "build": "babel src --out-dir dist",
    "build:watch": "babel src --out-dir dist --watch",
    "build:sourcemaps": "babel src --out-dir dist --source-maps",
    "clean": "rm -rf dist"
  }
}
# 基础编译
babel src --out-dir dist

# 监听文件变化
babel src --out-dir dist --watch

# 生成 source maps
babel src --out-dir dist --source-maps

# 忽略特定文件
babel src --out-dir dist --ignore "**/*.test.js"

# 复制非 JS 文件
babel src --out-dir dist --copy-files

# 详细输出
babel src --out-dir dist --verbose

安装和配置常用插件:

# 安装插件
npm install --save-dev @babel/plugin-proposal-class-properties
npm install --save-dev @babel/plugin-proposal-optional-chaining
npm install --save-dev @babel/plugin-transform-runtime
module.exports = {
  plugins: [
    // 类属性语法
    '@babel/plugin-proposal-class-properties',
    
    // 可选链操作符 (?.)
    '@babel/plugin-proposal-optional-chaining',
    
    // 空值合并操作符 (??)
    '@babel/plugin-proposal-nullish-coalescing-operator',
    
    // 运行时转换(减少重复代码)
    [
      '@babel/plugin-transform-runtime',
      {
        corejs: 3,
        helpers: true,
        regenerator: true,
      },
    ],
  ],
};
module.exports = {
  presets: ['@babel/preset-env'],
  env: {
    // 开发环境
    development: {
      plugins: ['@babel/plugin-transform-runtime'],
      sourceMaps: 'inline',
    },
    
    // 生产环境
    production: {
      plugins: [
        '@babel/plugin-transform-runtime',
        'babel-plugin-transform-remove-console',
      ],
      minified: true,
    },
    
    // 测试环境
    test: {
      presets: [
        ['@babel/preset-env', { targets: { node: 'current' } }]
      ],
    },
  },
};

问题: regeneratorRuntime is not defined
解决: 添加 regenerator-runtime polyfill

npm install --save regenerator-runtime
// 在入口文件顶部添加
import 'regenerator-runtime/runtime';

问题: 在浏览器中使用时模块导入失败
解决: 检查 modules 配置

// 浏览器环境
{
  modules: false // 保留 ES6 模块供打包工具处理
}

// Node.js 环境
{
  modules: 'commonjs' // 转换为 CommonJS
}

问题: 编译速度慢
解决: 使用缓存和优化配置

module.exports = {
  // 启用缓存
  cacheDirectory: true,
  
  presets: [
    [
      '@babel/preset-env',
      {
        // 只转换需要的特性
        targets: '> 1%',
        
        // 使用松散模式(更快但不严格兼容)
        loose: true,
      },
    ],
  ],
};

创建测试文件 src/test.js

// ES6+ 语法示例
const greet = (name = 'World') => {
  console.log(`Hello, ${name}!`);
};

class Person {
  name = 'Default';
  
  constructor(name) {
    this.name = name;
  }
  
  sayHello() {
    greet(this.name);
  }
}

export { Person, greet };

运行转译:

npm run build

检查输出文件 dist/test.js 是否正确转译。

查看转译后的代码是否正确添加了所需的 polyfill。

在 Jest 配置中使用 Babel:

// jest.config.js
module.exports = {
  transform: {
    '^.+\\.js$': 'babel-jest',
  },
};
// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
        },
      },
    ],
  },
};

Babel 配置完成后,继续配置其他开发工具:

  1. ESLint 和 Prettier 代码质量工具配置
  2. Jest 单元测试框架配置

正确的 Babel 配置确保我们能够使用现代 JavaScript 语法的同时保持良好的兼容性。