Skip to content

搭配 Babel 和 Webpack 使用

Webpack 是一个强大的静态模块打包器(static module bundler),用于现代 JavaScript 应用。它处理带有依赖关系的模块(JavaScript、CSS、图片等),并生成优化后的静态资源(static assets)。当与 Babel 结合时,Webpack 可以在其打包过程中将你的现代 JavaScript 代码(ES2015+),包括 JSX 或 TypeScript,转译成与旧浏览器兼容的版本。

本章将指导你如何使用 Webpack (版本 5+) 和 Babel (版本 7+) 设置项目,来打包和转译 JavaScript 模块。

创建一个新的项目目录并使用 npm 进行初始化:

mkdir webpack-babel-project
cd webpack-babel-project
npm init -y

你需要安装 Webpack、Webpack CLI、Babel 核心 (@babel/core)、babel-loader(用于让 Webpack 使用 Babel)以及 @babel/preset-env。

npm install --save-dev webpack webpack-cli @babel/core babel-loader @babel/preset-env

可选地,用于开发服务器:

npm install --save-dev webpack-dev-server html-webpack-plugin

html-webpack-plugin 简化了创建 HTML 文件来服务你的打包文件的过程。

你的 package.json 文件中的 devDependencies 将相应更新。

在你的项目根目录中创建一个 babel.config.json 文件:

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

这告诉 Babel 使用 @babel/preset-env 来转译现代 JavaScript。

在你的项目根目录中创建一个 webpack.config.js 文件。这个文件告诉 Webpack 如何打包你的项目。

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'development', // 或 'production' 用于优化构建
entry: './src/index.js', // 你的应用的入口点
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'), // 输出目录
clean: true, // 在每次构建前清理输出目录
},
module: {
rules: [
{
test: /\.js$/i, // 将此规则应用于 .js 文件
exclude: /node_modules/, // 不转译 node_modules
use: {
loader: 'babel-loader', // 对这些文件使用 babel-loader
options: {
// Babel 选项可以放在这里或 babel.config.json 中
// presets: ['@babel/preset-env'] // 如果 babel.config.json 存在则冗余
}
}
}
// 你可以在这里添加更多关于 CSS、图片等的规则
]
},
plugins: [
new HtmlWebpackPlugin({
title: 'Webpack Babel App',
template: './src/index.html' // 可选:你的 HTML 模板路径
})
],
devServer: {
static: './dist', // 从 dist 目录提供内容
port: 8080,
open: true, // 自动打开浏览器
hot: true, // 启用热模块替换
},
devtool: 'inline-source-map', // 用于更好的调试(仅限开发环境)
};

webpack.config.js 的关键部分:

  • mode:设置 'development' 或 'production'。production 模式会启用多种优化。
  • entry:你应用的主 JavaScript 文件(入口点)。
  • output:指定打包文件的输出位置(dist 目录中的 bundle.js)。
  • module.rules:定义了不同类型的模块(文件)应该如何处理。处理 .js 文件的规则使用了 babel-loader。
  • plugins:HtmlWebpackPlugin 会生成一个包含你的 bundle.js 的 HTML 文件。
  • devServer:为带有热重载的开发环境配置 webpack-dev-server。

创建以下目录结构:

webpack-babel-project/
├── dist/ # 输出文件夹 (Webpack 会创建)
├── node_modules/
├── src/
│ ├── index.html # HTML 模板 (可选,如果使用 HtmlWebpackPlugin 模板)
│ ├── index.js # 主应用 JavaScript (入口点)
│ └── math.js # 一个示例模块
├── babel.config.json
├── package.json
└── webpack.config.js

src/index.html(简单模板):

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<h1>Hello from Webpack and Babel!</h1>
<div id="app"></div>
</body>
</html>

src/math.js:

export const add = (a, b) => a + b;
export const subtract = (a, b) => {
// 使用类进行演示
class Calculator {
constructor() {
this.operation = 'subtract';
}
compute(x, y) {
return x - y;
}
}
const calc = new Calculator();
return calc.compute(a, b);
};

src/index.js:

import { add, subtract } from './math.js';
const main = () => {
const num1 = 10;
const num2 = 5;
const appDiv = document.getElementById('app');
if (appDiv) {
appDiv.innerHTML = `
<p>${num1} + ${num2} = ${add(num1, num2)}</p>
<p>${num1} - ${num2} = ${subtract(num1, num2)}</p>
`;
}
console.log(`Addition: ${add(num1, num2)}`);
console.log(`Subtraction: ${subtract(num1, num2)}`);
// 如果目标是旧浏览器,可能需要 polyfill 的特性示例
const arr = [1, 2, 3];
if (arr.includes(2)) {
console.log('Array includes 2!');
}
};
main();

更新 package.json 文件中的 scripts 部分:

"scripts": {
"start": "webpack serve --open",
"build": "webpack --mode production",
"build:dev": "webpack --mode development"
}

要启动开发服务器:

npm start

这将在浏览器中打开你的应用(通常是 http://localhost:8080)。Webpack 将监视文件变化并自动重新打包和刷新浏览器。

要创建优化后的生产环境构建:

npm run build

这将在 dist 文件夹中生成 bundle.js(和 index.html)。JavaScript 代码将被压缩并针对生产环境进行优化。

如果你在构建后检查 dist/bundle.js,你会发现 Webpack 已经将 index.js 和 math.js 打包在一起了。Babel 通过 babel-loader 将现代 JavaScript 语法(如箭头函数、类、模板字面量)转译成了与 ES5 兼容的代码(或根据 @babel/preset-env 目标配置)。

bundle.js 中转译逻辑的简化表示可能如下所示(Webpack 添加了许多样板代码):

// ... Webpack 运行时 ...
// 转译后的 math.js 模块内容
var add = function add(a, b) { return a + b; };
var subtract = function subtract(a, b) {
var Calculator = /*#__PURE__*/function () { /* ... 转译后的类 ... */ }();
var calc = new Calculator();
return calc.compute(a, b);
};
// 转译后的 index.js 模块内容
var main = function main() {
var num1 = 10;
var num2 = 5;
// ... DOM 操作和带有转译语法的控制台日志 ...
console.log("Addition: ".concat(add(num1, num2)));
};
main();
// ... 更多 Webpack 样板代码 ...

这种设置有效地结合了 Webpack 的模块打包能力和 Babel 的转译能力,为现代 JavaScript 应用创建了一个强大的构建过程。对于像 Array.prototype.includes 这样的特性,如果目标是旧环境,请确保你的 Babel preset-env 配置了使用 core-js 的 Polyfill(参见其他章节)。