babel-loader:让你的 JS 代码兼容所有浏览器

一、为什么需要 Babel

现代 JavaScript 有很多新特性(ES6+),但旧浏览器不支持。

javascript 复制代码
// ES6+ 代码
const greet = (name) => `Hello, ${name}!`;
class Person {
  constructor(name) {
    this.name = name;
  }
}

// 旧浏览器需要转换为 ES5
var greet = function(name) {
  return 'Hello, ' + name + '!';
};
function Person(name) {
  this.name = name;
}

Babel 就是用来做这个转换的,babel-loader 让 webpack 能够使用 Babel。


二、基础配置

安装

bash 复制代码
npm install --save-dev babel-loader @babel/core @babel/preset-env

webpack 配置

javascript 复制代码
module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env']
          }
        }
      }
    ]
  }
};

三、Babel 配置文件

推荐使用独立的配置文件,而不是写在 webpack 配置中。

babel.config.js(推荐)

javascript 复制代码
module.exports = {
  presets: [
    ['@babel/preset-env', {
      targets: {
        browsers: ['> 1%', 'last 2 versions', 'not dead']
      },
      useBuiltIns: 'usage',
      corejs: 3
    }]
  ],
  plugins: []
};

.babelrc

json 复制代码
{
  "presets": [
    ["@babel/preset-env", {
      "targets": "> 0.25%, not dead"
    }]
  ]
}

四、Preset 详解

@babel/preset-env

最常用的 preset,根据目标环境自动确定需要的转换。

javascript 复制代码
{
  presets: [
    ['@babel/preset-env', {
      // 目标环境
      targets: {
        chrome: '58',
        ie: '11',
        node: '12'
      },
      
      // 或使用 browserslist 查询
      targets: '> 0.25%, not dead',
      
      // 模块转换:'auto' | 'amd' | 'umd' | 'systemjs' | 'commonjs' | false
      modules: false,  // webpack 已处理模块,设为 false
      
      // polyfill 策略
      useBuiltIns: 'usage',  // 'usage' | 'entry' | false
      corejs: 3
    }]
  ]
}

@babel/preset-react

转换 JSX 语法。

bash 复制代码
npm install --save-dev @babel/preset-react
javascript 复制代码
{
  presets: [
    '@babel/preset-env',
    ['@babel/preset-react', {
      runtime: 'automatic'  // React 17+ 不需要 import React
    }]
  ]
}

@babel/preset-typescript

转换 TypeScript。

bash 复制代码
npm install --save-dev @babel/preset-typescript
javascript 复制代码
{
  presets: [
    '@babel/preset-env',
    '@babel/preset-typescript'
  ]
}

五、Polyfill 策略

useBuiltIns: 'usage'(推荐)

根据代码中实际使用的特性自动引入 polyfill。

bash 复制代码
npm install --save core-js@3
javascript 复制代码
// 源代码
const promise = Promise.resolve();
const arr = [1, 2, 3].includes(2);

// Babel 自动添加需要的 polyfill
import "core-js/modules/es.promise";
import "core-js/modules/es.array.includes";

useBuiltIns: 'entry'

手动在入口引入,Babel 根据目标环境替换为需要的 polyfill。

javascript 复制代码
// 入口文件
import 'core-js/stable';
import 'regenerator-runtime/runtime';

// Babel 会替换为具体需要的 polyfill

useBuiltIns: false

不自动引入 polyfill,需要手动管理。


六、常用插件

1. 类属性

bash 复制代码
npm install --save-dev @babel/plugin-proposal-class-properties
javascript 复制代码
// 支持类属性语法
class MyClass {
  count = 0;  // 实例属性
  static version = '1.0';  // 静态属性
  
  handleClick = () => {  // 箭头函数自动绑定 this
    this.count++;
  }
}

2. 装饰器

bash 复制代码
npm install --save-dev @babel/plugin-proposal-decorators
javascript 复制代码
{
  plugins: [
    ['@babel/plugin-proposal-decorators', { legacy: true }],
    ['@babel/plugin-proposal-class-properties', { loose: true }]
  ]
}
javascript 复制代码
@connect(mapStateToProps)
class MyComponent extends React.Component {
  // ...
}

3. 可选链和空值合并

bash 复制代码
npm install --save-dev @babel/plugin-proposal-optional-chaining
npm install --save-dev @babel/plugin-proposal-nullish-coalescing-operator
javascript 复制代码
// 可选链
const name = user?.profile?.name;

// 空值合并
const count = value ?? 0;

七、性能优化

1. 缓存

javascript 复制代码
{
  test: /\.js$/,
  exclude: /node_modules/,
  use: {
    loader: 'babel-loader',
    options: {
      cacheDirectory: true,  // 开启缓存
      cacheCompression: false  // 不压缩缓存
    }
  }
}

2. 限制转换范围

javascript 复制代码
{
  test: /\.js$/,
  // 只转换 src 目录
  include: path.resolve(__dirname, 'src'),
  // 排除 node_modules
  exclude: /node_modules/,
  use: 'babel-loader'
}

3. 使用 thread-loader

bash 复制代码
npm install --save-dev thread-loader
javascript 复制代码
{
  test: /\.js$/,
  use: [
    'thread-loader',  // 多线程编译
    'babel-loader'
  ]
}

八、环境区分

开发环境

javascript 复制代码
// babel.config.js
module.exports = (api) => {
  const isDev = api.env('development');
  
  return {
    presets: [
      ['@babel/preset-env', {
        targets: isDev ? { node: 'current' } : '> 0.25%, not dead',
        modules: false
      }],
      '@babel/preset-react'
    ],
    plugins: [
      isDev && 'react-refresh/babel'  // 开发环境热更新
    ].filter(Boolean)
  };
};

生产环境

javascript 复制代码
{
  presets: [
    ['@babel/preset-env', {
      targets: '> 0.25%, not dead',
      useBuiltIns: 'usage',
      corejs: 3
    }]
  ],
  plugins: [
    ['transform-remove-console', {  // 移除 console
      exclude: ['error', 'warn']
    }]
  ]
}

九、常见问题

1. async/await 不工作?

需要 regenerator-runtime:

bash 复制代码
npm install --save regenerator-runtime
javascript 复制代码
// 入口文件
import 'regenerator-runtime/runtime';

或使用 @babel/plugin-transform-runtime:

bash 复制代码
npm install --save-dev @babel/plugin-transform-runtime
npm install --save @babel/runtime
javascript 复制代码
{
  plugins: [
    ['@babel/plugin-transform-runtime', {
      regenerator: true
    }]
  ]
}

2. 某些 ES6+ 特性不转换?

检查 targets 配置,可能目标环境已支持该特性。

3. 打包体积太大?

  • 使用 useBuiltIns: 'usage' 按需引入 polyfill
  • 检查是否转换了 node_modules
  • 使用 @babel/plugin-transform-runtime 避免重复代码

十、完整配置示例

javascript 复制代码
// babel.config.js
module.exports = {
  presets: [
    ['@babel/preset-env', {
      targets: {
        browsers: ['> 1%', 'last 2 versions', 'not dead']
      },
      useBuiltIns: 'usage',
      corejs: 3,
      modules: false
    }],
    ['@babel/preset-react', {
      runtime: 'automatic'
    }],
    '@babel/preset-typescript'
  ],
  plugins: [
    ['@babel/plugin-proposal-decorators', { legacy: true }],
    ['@babel/plugin-proposal-class-properties', { loose: true }],
    '@babel/plugin-proposal-optional-chaining',
    '@babel/plugin-proposal-nullish-coalescing-operator',
    ['@babel/plugin-transform-runtime', {
      corejs: false,
      helpers: true,
      regenerator: true
    }]
  ]
};
javascript 复制代码
// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.(js|jsx|ts|tsx)$/,
        include: path.resolve(__dirname, 'src'),
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            cacheDirectory: true,
            cacheCompression: false
          }
        }
      }
    ]
  }
};
相关推荐
百万蹄蹄向前冲2 小时前
支付宝 VS 微信 小程序差异
前端·后端·微信小程序
兆子龙2 小时前
JavaScript 的 Symbol.iterator:手写一个可迭代对象
前端
NGC_66112 小时前
ArrayList扩容机制
java·前端·算法
独泪了无痕7 小时前
使用Fetch API 探索前后端数据交互
前端·http·交互设计
css趣多多7 小时前
别名路径的知识点
前端
靓仔建9 小时前
Vue3导入组件出错does not provide an export named ‘user_setting‘ (at index.vue:180:10)
开发语言·前端·typescript
EnoYao9 小时前
我写了一个团队体检报告 Skill,把摸鱼的同事扒出来了😅
前端·javascript
梁正雄9 小时前
Python前端-2-css练习
前端·css·python