76. Babel 教程

1. Babel 简介

Babel 是一个 JavaScript 编译器,它可以将使用最新 JavaScript 特性编写的代码转换为向后兼容的 JavaScript 代码,以便在旧版本的浏览器或环境中运行。

1.1 Babel 的核心特性

  • 语法转换:将 ES6+ 语法转换为 ES5 语法
  • Polyfill:通过 Polyfill 方式在目标环境中添加缺失的特性
  • 代码转换:支持 JSX、TypeScript 等语法的转换
  • 插件系统:通过插件扩展功能
  • 预设:通过预设简化配置
  • 源码映射:生成源码映射,便于调试

1.2 Babel 的使用场景

  • 使用最新 JavaScript 特性:在不支持这些特性的环境中使用 ES6+ 语法
  • 前端开发:确保代码在各种浏览器中兼容
  • Node.js 开发:在旧版本 Node.js 中使用新特性
  • React 开发:转换 JSX 语法
  • TypeScript 开发:作为 TypeScript 编译流程的一部分

2. 安装与初始化

2.1 全局安装 Babel

# 使用 npm
npm install -g @babel/core @babel/cli

# 使用 yarn
yarn global add @babel/core @babel/cli

# 使用 pnpm
pnpm add -g @babel/core @babel/cli

2.2 本地安装 Babel

推荐在项目中本地安装 Babel,以确保版本一致性:

# 安装核心包
npm install --save-dev @babel/core @babel/cli

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

# 安装 React 相关预设(如果需要)
npm install --save-dev @babel/preset-react

# 安装 TypeScript 相关预设(如果需要)
npm install --save-dev @babel/preset-typescript

2.3 创建配置文件

在项目根目录创建 Babel 配置文件:

2.3.1 创建 babel.config.js 文件

module.exports = {
  presets: [
    '@babel/preset-env'
  ]
};

2.3.2 创建 .babelrc 文件

{
  "presets": [
    "@babel/preset-env"
  ]
}

2.3.3 在 package.json 中配置

{
  "babel": {
    "presets": [
      "@babel/preset-env"
    ]
  }
}

2.4 配置 package.json 脚本

package.json 文件中添加 Babel 脚本:

{
  "scripts": {
    "build": "babel src --out-dir dist",
    "watch": "babel src --out-dir dist --watch"
  }
}

然后可以使用以下命令运行:

# 编译代码
npm run build

# 监视文件变化并自动编译
npm run watch

3. 基本使用

3.1 编译单个文件

# 全局安装的 Babel
babel input.js --out-file output.js

# 本地安装的 Babel
npx babel input.js --out-file output.js

# 使用 yarn
yarn babel input.js --out-file output.js

# 使用 pnpm
pnpm babel input.js --out-file output.js

3.2 编译目录

# 编译 src 目录到 dist 目录
babel src --out-dir dist

# 监视目录变化
babel src --out-dir dist --watch

3.3 使用不同的配置文件

# 使用指定的配置文件
babel src --out-dir dist --config-file babel.config.custom.js

3.4 生成源码映射

# 生成源码映射
babel src --out-dir dist --source-maps

# 内联源码映射
babel src --out-dir dist --source-maps inline

3.5 从 stdin 读取

# 从 stdin 读取
cat input.js | babel --stdin > output.js

4. 配置详解

4.1 配置文件格式

Babel 支持多种格式的配置文件:

  • babel.config.js:JavaScript 模块,支持注释,适用于 monorepo
  • .babelrc:JSON 格式,适用于单个项目
  • .babelrc.js:JavaScript 模块,支持注释
  • .babelrc.json:JSON 格式
  • package.json:在 babel 字段中配置

4.2 核心配置选项

4.2.1 presets

预设是一组插件的集合,用于简化配置:

module.exports = {
  presets: [
    '@babel/preset-env',
    '@babel/preset-react',
    '@babel/preset-typescript'
  ]
};

4.2.2 plugins

插件用于转换特定的语法或功能:

module.exports = {
  plugins: [
    '@babel/plugin-proposal-class-properties',
    '@babel/plugin-proposal-optional-chaining',
    '@babel/plugin-transform-runtime'
  ]
};

4.2.3 env

根据环境配置不同的选项:

module.exports = {
  presets: ['@babel/preset-env'],
  env: {
    development: {
      sourceMaps: true
    },
    production: {
      minified: true
    }
  }
};

4.3 @babel/preset-env 配置

@babel/preset-env 是最常用的预设,用于转换 ES6+ 语法:

module.exports = {
  presets: [
    [
      '@babel/preset-env',
      {
        targets: {
          browsers: ['> 1%', 'last 2 versions', 'not dead'],
          node: 'current'
        },
        useBuiltIns: 'usage',
        corejs: 3,
        modules: 'commonjs'
      }
    ]
  ]
};

4.3.1 targets

指定目标环境:

{
  targets: {
    // 浏览器
    browsers: ['> 1%', 'last 2 versions', 'not dead'],
    // Node.js
    node: '14',
    // iOS
    ios: '12',
    // Android
    android: '8'
  }
}

4.3.2 useBuiltIns

指定如何处理 polyfill:

  • false:不自动添加 polyfill
  • 'entry':在入口文件添加所有 polyfill
  • 'usage':根据代码使用情况添加必要的 polyfill
{
  useBuiltIns: 'usage',
  corejs: 3
}

4.3.3 modules

指定模块转换方式:

  • 'amd':转换为 AMD 模块
  • 'commonjs':转换为 CommonJS 模块
  • 'umd':转换为 UMD 模块
  • 'systemjs':转换为 SystemJS 模块
  • 'esmodules':保持 ES 模块
  • false:不转换模块
{
  modules: 'commonjs'
}

5. 插件与预设

5.1 常用插件

插件 描述 安装命令
@babel/plugin-proposal-class-properties 支持类属性语法 npm install --save-dev @babel/plugin-proposal-class-properties
@babel/plugin-proposal-optional-chaining 支持可选链语法 npm install --save-dev @babel/plugin-proposal-optional-chaining
@babel/plugin-proposal-nullish-coalescing-operator 支持空值合并运算符 npm install --save-dev @babel/plugin-proposal-nullish-coalescing-operator
@babel/plugin-transform-runtime 避免重复注入 helper 函数 npm install --save-dev @babel/plugin-transform-runtime
@babel/plugin-syntax-dynamic-import 支持动态导入语法 npm install --save-dev @babel/plugin-syntax-dynamic-import
@babel/plugin-transform-arrow-functions 转换箭头函数 npm install --save-dev @babel/plugin-transform-arrow-functions
@babel/plugin-transform-async-to-generator 转换 async/await npm install --save-dev @babel/plugin-transform-async-to-generator

5.2 常用预设

预设 描述 安装命令
@babel/preset-env 转换 ES6+ 语法 npm install --save-dev @babel/preset-env
@babel/preset-react 转换 JSX 语法 npm install --save-dev @babel/preset-react
@babel/preset-typescript 转换 TypeScript 语法 npm install --save-dev @babel/preset-typescript
@babel/preset-flow 转换 Flow 语法 npm install --save-dev @babel/preset-flow

5.3 使用插件和预设

在配置文件中添加插件和预设:

module.exports = {
  presets: [
    '@babel/preset-env',
    '@babel/preset-react'
  ],
  plugins: [
    '@babel/plugin-proposal-class-properties',
    '@babel/plugin-proposal-optional-chaining',
    '@babel/plugin-transform-runtime'
  ]
};

6. Polyfill

6.1 什么是 Polyfill

Polyfill 是一段代码,用于在目标环境中添加缺失的功能。Babel 可以通过以下方式添加 Polyfill:

6.2 使用 @babel/polyfill

注意:@babel/polyfill 在 Babel 7.4.0 后已被废弃,建议使用 core-js 和 regenerator-runtime。

6.3 使用 core-js 和 regenerator-runtime

  1. 安装依赖:
npm install --save core-js regenerator-runtime
  1. 配置 @babel/preset-env:
module.exports = {
  presets: [
    [
      '@babel/preset-env',
      {
        useBuiltIns: 'usage',
        corejs: 3
      }
    ]
  ]
};

这样,Babel 会根据代码使用情况自动添加必要的 Polyfill。

6.4 使用入口文件导入

在入口文件顶部导入:

// 导入所有 Polyfill
import 'core-js';
import 'regenerator-runtime/runtime';

// 或只导入必要的 Polyfill
import 'core-js/stable';
import 'regenerator-runtime/runtime';

然后配置:

module.exports = {
  presets: [
    [
      '@babel/preset-env',
      {
        useBuiltIns: 'entry',
        corejs: 3
      }
    ]
  ]
};

7. 与构建工具集成

7.1 与 Webpack 集成

  1. 安装依赖:
npm install --save-dev babel-loader @babel/core @babel/preset-env
  1. 配置 webpack.config.js:
module.exports = {
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader'
        }
      }
    ]
  }
};

7.2 与 Rollup 集成

  1. 安装依赖:
npm install --save-dev @rollup/plugin-babel @babel/core @babel/preset-env
  1. 配置 rollup.config.js:
import babel from '@rollup/plugin-babel';

export default {
  input: 'src/index.js',
  output: {
    file: 'dist/bundle.js',
    format: 'esm'
  },
  plugins: [
    babel({
      babelHelpers: 'bundled',
      exclude: 'node_modules/**'
    })
  ]
};

7.3 与 Parcel 集成

Parcel 内置了 Babel 支持,无需额外配置。如果需要自定义 Babel 配置,只需创建 Babel 配置文件即可。

7.4 与 Gulp 集成

  1. 安装依赖:
npm install --save-dev gulp @babel/core @babel/preset-env gulp-babel
  1. 配置 gulpfile.js:
const gulp = require('gulp');
const babel = require('gulp-babel');

gulp.task('babel', () => {
  return gulp.src('src/**/*.js')
    .pipe(babel({
      presets: ['@babel/preset-env']
    }))
    .pipe(gulp.dest('dist'));
});

gulp.task('watch', () => {
  gulp.watch('src/**/*.js', gulp.series('babel'));
});

8. 与框架集成

8.1 与 React 集成

  1. 安装依赖:
npm install --save-dev @babel/preset-react
  1. 配置 Babel:
module.exports = {
  presets: [
    '@babel/preset-env',
    '@babel/preset-react'
  ]
};
  1. 编译 JSX:
// 输入
const element = <h1>Hello, world!</h1>;

// 输出
const element = React.createElement('h1', null, 'Hello, world!');

8.2 与 TypeScript 集成

  1. 安装依赖:
npm install --save-dev @babel/preset-typescript
  1. 配置 Babel:
module.exports = {
  presets: [
    '@babel/preset-env',
    '@babel/preset-typescript'
  ]
};
  1. 编译 TypeScript:
// 输入
const add = (a: number, b: number): number => a + b;

// 输出
const add = (a, b) => a + b;

注意:@babel/preset-typescript 只转换 TypeScript 语法,不进行类型检查。需要使用 tsc 进行类型检查。

9. 最佳实践

9.1 项目配置最佳实践

  1. 使用本地安装:在项目中本地安装 Babel,确保版本一致性
  2. 使用 babel.config.js:对于 monorepo 项目,使用 babel.config.js
  3. 合理配置 targets:根据目标环境配置 targets,减少不必要的转换
  4. **使用 useBuiltIns: 'usage'**:根据代码使用情况添加必要的 Polyfill
  5. 使用 @babel/plugin-transform-runtime:避免重复注入 helper 函数
  6. 添加 .babelrc.js 到 .gitignore:如果配置包含敏感信息

9.2 性能优化

  1. 合理配置 targets:减少不必要的转换
  2. 使用缓存:对于构建工具,启用 Babel 缓存
  3. 使用增量编译:只编译修改的文件
  4. 避免过度转换:只转换必要的语法
  5. 使用 modern 模式:为现代浏览器提供现代代码

9.3 调试技巧

  1. 生成源码映射:使用 --source-maps 选项生成源码映射
  2. 使用 NODE_ENV:根据环境配置不同的 Babel 选项
  3. 检查输出:查看编译后的代码,确保转换正确
  4. 使用 babel-upgrade:升级 Babel 配置

10. 常见问题与解决方案

10.1 Babel 不转换某些语法

问题:Babel 没有转换预期的语法

解决方案

  • 检查是否安装了正确的预设或插件
  • 检查配置文件是否正确
  • 检查目标环境配置是否合理
  • 查看 Babel 文档,确认语法是否需要特定插件

10.2 Polyfill 不生效

问题:Polyfill 没有添加到代码中

解决方案

  • 检查 useBuiltIns 配置是否正确
  • 检查 corejs 版本是否正确
  • 对于 entry 模式,确保在入口文件中导入了 core-js
  • 检查代码是否使用了需要 Polyfill 的功能

10.3 编译速度慢

问题:Babel 编译速度慢

解决方案

  • 启用缓存
  • 合理配置 targets
  • 使用增量编译
  • 避免过度转换
  • 对于大型项目,考虑使用 swc 等更快的编译器

10.4 与其他工具冲突

问题:Babel 与其他工具(如 ESLint、Prettier)冲突

解决方案

  • 确保工具版本兼容
  • 合理配置工具链
  • 对于 ESLint,使用 eslint-plugin-babel
  • 对于 Prettier,确保配置一致

10.5 源码映射问题

问题:源码映射不工作或指向错误的位置

解决方案

  • 确保启用了源码映射
  • 检查构建工具的源码映射配置
  • 对于 webpack,确保 devtool 配置正确
  • 检查输出目录结构

11. 总结

Babel 是一个强大的 JavaScript 编译器,可以帮助开发者使用最新的 JavaScript 特性,同时确保代码在各种环境中兼容。通过本教程的学习,你应该已经掌握了:

  • Babel 的核心概念和基本使用方法
  • 如何安装和配置 Babel
  • 如何使用 Babel 编译代码
  • Babel 的插件和预设系统
  • 如何使用 Polyfill
  • 如何与构建工具和框架集成
  • Babel 的最佳实践和常见问题解决方案

Babel 是前端开发工具链中的重要组成部分,合理使用 Babel 可以显著提高开发效率,同时确保代码的兼容性。建议在所有需要使用最新 JavaScript 特性的项目中都使用 Babel,并根据项目需求进行适当的配置。

12. 扩展阅读

« 上一篇 75. Prettier 教程 下一篇 » TypeScript 教程