SWC 编译与转译 #

编译基础 #

什么是编译? #

编译是将源代码从一种形式转换为另一种形式的过程。SWC 主要处理:

text
┌─────────────────────────────────────────────────────────────┐
│                     SWC 编译流程                             │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  现代语法 ───► 目标语法                                       │
│  TypeScript ───► JavaScript                                  │
│  JSX ───► JavaScript                                         │
│  ES2022 ───► ES5/ES2015                                      │
│                                                              │
└─────────────────────────────────────────────────────────────┘

基本编译示例 #

javascript
// 输入(ES2022)
class Example {
  #privateField = 42;
  
  #privateMethod() {
    return this.#privateField;
  }
  
  get value() {
    return this.#privateMethod();
  }
}

// 输出(ES2015)
var Example = function() {
  "use strict";
  function Example() {
    this._privateField = 42;
  }
  var _proto = Example.prototype;
  _proto._privateMethod = function() {
    return this._privateField;
  };
  _proto = Object.create(null, {
    value: {
      get: function() {
        return this._privateMethod();
      }
    }
  });
  return Example;
}();

ECMAScript 特性编译 #

箭头函数 #

javascript
// 输入
const add = (a, b) => a + b;
const greet = name => `Hello, ${name}!`;

// 输出(ES5)
var add = function(a, b) {
  return a + b;
};
var greet = function(name) {
  return "Hello, " + name + "!";
};

#

javascript
// 输入
class Person {
  constructor(name) {
    this.name = name;
  }
  
  greet() {
    return `Hello, I'm ${this.name}`;
  }
  
  static create(name) {
    return new Person(name);
  }
}

// 输出(ES5)
var Person = function() {
  "use strict";
  function Person(name) {
    this.name = name;
  }
  var _proto = Person.prototype;
  _proto.greet = function() {
    return "Hello, I'm " + this.name;
  };
  Person.create = function(name) {
    return new Person(name);
  };
  return Person;
}();

类字段 #

javascript
// 输入
class Counter {
  count = 0;
  increment = () => {
    this.count++;
  };
}

// 输出(ES2015)
class Counter {
  constructor() {
    this.count = 0;
    this.increment = ()=>{
      this.count++;
    };
  }
}

私有字段和方法 #

javascript
// 输入
class Example {
  #privateField = 42;
  #privateMethod() {
    return this.#privateField;
  }
}

// 输出(ES2015)
var _privateField = new WeakMap();
var _privateMethod = new WeakSet();
class Example {
  constructor() {
    _privateMethod.add(this);
    _privateField.set(this, {
      writable: true,
      value: 42
    });
  }
}

模板字符串 #

javascript
// 输入
const name = "World";
const greeting = `Hello, ${name}!`;
const multiLine = `
  Line 1
  Line 2
`;

// 输出(ES5)
var name = "World";
var greeting = "Hello, " + name + "!";
var multiLine = "\n  Line 1\n  Line 2\n";

解构赋值 #

javascript
// 输入
const { a, b: renamed, ...rest } = obj;
const [first, second, ...others] = array;

// 输出(ES5)
var _obj = obj, a = _obj.a, renamed = _obj.b, rest = _objectWithoutProperties(_obj, [
  "a",
  "b"
]);
var _array = array, first = _array[0], second = _array[1], others = _array.slice(2);

展开运算符 #

javascript
// 输入
const merged = { ...obj1, ...obj2 };
const combined = [...arr1, ...arr2];

// 输出(ES5)
var merged = Object.assign({}, obj1, obj2);
var combined = arr1.concat(arr2);

默认参数 #

javascript
// 输入
function greet(name = "World", greeting = "Hello") {
  return `${greeting}, ${name}!`;
}

// 输出(ES5)
function greet() {
  var name = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : "World";
  var greeting = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "Hello";
  return greeting + ", " + name + "!";
}

可选链 #

javascript
// 输入
const value = obj?.nested?.property;
const result = func?.();

// 输出(ES5)
var _obj_nested;
var value = obj === null || obj === void 0 ? void 0 : (_obj_nested = obj.nested) === null || _obj_nested === void 0 ? void 0 : _obj_nested.property;
var result = func === null || func === void 0 ? void 0 : func();

空值合并 #

javascript
// 输入
const value = input ?? "default";

// 输出(ES5)
var _input;
var value = (_input = input) !== null && _input !== void 0 ? _input : "default";

async/await #

javascript
// 输入
async function fetchData() {
  const response = await fetch(url);
  const data = await response.json();
  return data;
}

// 输出(ES2015)
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
  try {
    var info = gen[key](arg);
    var value = info.value;
  } catch (error) {
    reject(error);
    return;
  }
  if (info.done) {
    resolve(value);
  } else {
    Promise.resolve(value).then(_next, _throw);
  }
}
function _asyncToGenerator(fn) {
  return function() {
    var self = this, args = arguments;
    return new Promise(function(resolve, reject) {
      var gen = fn.apply(self, args);
      function _next(value) {
        asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
      }
      function _throw(err) {
        asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
      }
      _next(undefined);
    });
  };
}
function fetchData() {
  return _fetchData.apply(this, arguments);
}
function _fetchData() {
  _fetchData = _asyncToGenerator(function*() {
    var response = yield fetch(url);
    var data = yield response.json();
    return data;
  });
  return _fetchData.apply(this, arguments);
}

TypeScript 编译 #

类型擦除 #

SWC 默认只擦除类型,不进行类型检查:

typescript
// 输入
interface User {
  name: string;
  age: number;
}

function greet(user: User): string {
  return `Hello, ${user.name}!`;
}

const user: User = { name: "Alice", age: 30 };
javascript
// 输出
function greet(user) {
  return "Hello, " + user.name + "!";
}
var user = {
  name: "Alice",
  age: 30
};

枚举 #

typescript
// 输入
enum Direction {
  Up = "UP",
  Down = "DOWN",
  Left = "LEFT",
  Right = "RIGHT"
}

const enum Status {
  Active,
  Inactive
}
javascript
// 输出
var Direction;
(function(Direction) {
  Direction["Up"] = "UP";
  Direction["Down"] = "DOWN";
  Direction["Left"] = "LEFT";
  Direction["Right"] = "RIGHT";
})(Direction || (Direction = {}));

// const enum 内联
var Status = {
  Active: 0,
  Inactive: 1
};

命名空间 #

typescript
// 输入
namespace Utils {
  export function log(message: string) {
    console.log(message);
  }
  
  export const version = "1.0.0";
}
javascript
// 输出
var Utils;
(function(Utils) {
  function log(message) {
    console.log(message);
  }
  Utils.log = log;
  Utils.version = "1.0.0";
})(Utils || (Utils = {}));

装饰器 #

typescript
// 输入
function logged(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const original = descriptor.value;
  descriptor.value = function(...args: any[]) {
    console.log(`Calling ${propertyKey}`);
    return original.apply(this, args);
  };
}

class Example {
  @logged
  method() {
    return "result";
  }
}
javascript
// 输出
function logged(target, propertyKey, descriptor) {
  var original = descriptor.value;
  descriptor.value = function() {
    for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
      args[_key] = arguments[_key];
    }
    console.log("Calling " + propertyKey);
    return original.apply(this, args);
  };
}
class Example {
  method() {
    return "result";
  }
}
_decorate([
  logged
], Example.prototype, "method", null);

泛型 #

typescript
// 输入
function identity<T>(arg: T): T {
  return arg;
}

const result = identity<string>("hello");
javascript
// 输出(类型被擦除)
function identity(arg) {
  return arg;
}
var result = identity("hello");

类型导入 #

typescript
// 输入
import type { User } from './types';
import { type Role, type Permission } from './auth';

function checkUser(user: User) {
  return user;
}
javascript
// 输出(类型导入被移除)
function checkUser(user) {
  return user;
}

JSX 编译 #

Classic 运行时 #

javascript
// 输入
const element = <div className="container">Hello, World!</div>;

// 输出
var element = React.createElement("div", {
  className: "container"
}, "Hello, World!");

Automatic 运行时 #

javascript
// 输入
const element = <div className="container">Hello, World!</div>;

// 输出
import { jsx as _jsx } from "react/jsx-runtime";
var element = _jsx("div", {
  className: "container",
  children: "Hello, World!"
});

JSX 配置 #

json
{
  "jsc": {
    "parser": {
      "syntax": "ecmascript",
      "jsx": true
    },
    "transform": {
      "react": {
        "runtime": "automatic",
        "importSource": "react",
        "pragma": "React.createElement",
        "pragmaFrag": "React.Fragment"
      }
    }
  }
}

自定义 JSX #

json
{
  "jsc": {
    "transform": {
      "react": {
        "runtime": "classic",
        "pragma": "h",
        "pragmaFrag": "Fragment"
      }
    }
  }
}
javascript
// 输入
const element = <div>Hello</div>;

// 输出
var element = h("div", null, "Hello");

Vue JSX #

json
{
  "jsc": {
    "parser": {
      "syntax": "ecmascript",
      "jsx": true
    },
    "transform": {
      "react": {
        "runtime": "classic",
        "pragma": "h",
        "pragmaFrag": "Fragment"
      }
    }
  }
}

模块转换 #

ES Modules 到 CommonJS #

javascript
// 输入
import { foo, bar } from './module';
import * as utils from './utils';
export default function() {}
export const value = 42;
javascript
// 输出
"use strict";
Object.defineProperty(exports, "__esModule", {
  value: true
});
Object.defineProperty(exports, "value", {
  enumerable: true,
  get: function() {
    return value;
  }
});
exports.default = function() {};
var _module = require("./module");
var utils = require("./utils");
const value = 42;

CommonJS 到 ES Modules #

javascript
// 输入
const foo = require('./foo');
module.exports = { value: 42 };
javascript
// 输出
import foo from "./foo";
export const value = 42;
export default { value: 42 };

动态导入 #

javascript
// 输入
const module = await import('./module');

// 输出(保持动态导入)
const module = await import('./module');

目标环境编译 #

ES5 目标 #

json
{
  "jsc": {
    "target": "es5"
  }
}

ES2015 目标 #

json
{
  "jsc": {
    "target": "es2015"
  }
}

ES2020 目标 #

json
{
  "jsc": {
    "target": "es2020"
  }
}

目标特性对照 #

特性 ES5 ES2015 ES2020
箭头函数 转换 保留 保留
转换 保留 保留
模板字符串 转换 保留 保留
可选链 转换 转换 保留
空值合并 转换 转换 保留
async/await 转换 转换 保留

Polyfill 注入 #

配置 #

json
{
  "env": {
    "targets": {
      "chrome": "60"
    },
    "coreJs": "3.29",
    "mode": "usage"
  }
}

自动注入 #

javascript
// 输入
const result = [1, 2, 3].includes(2);
const obj = { a: 1, b: 2 };
const copy = { ...obj };

// 输出(自动注入 polyfill)
import "core-js/modules/es.array.includes.js";
import "core-js/modules/es.object.assign.js";
var result = [1, 2, 3].includes(2);
var obj = { a: 1, b: 2 };
var copy = Object.assign({}, obj);

编译 API #

transform 函数 #

javascript
const swc = require('@swc/core');

const result = await swc.transform(sourceCode, {
  jsc: {
    parser: {
      syntax: 'ecmascript'
    },
    target: 'es2015'
  }
});

console.log(result.code);
console.log(result.map);

transformSync 函数 #

javascript
const swc = require('@swc/core');

const result = swc.transformSync(sourceCode, {
  jsc: {
    parser: {
      syntax: 'ecmascript'
    },
    target: 'es2015'
  }
});

parseFile 函数 #

javascript
const swc = require('@swc/core');

const ast = await swc.parseFile('./src/index.js', {
  syntax: 'ecmascript'
});

console.log(ast);
javascript
const swc = require('@swc/core');

const ast = await swc.parse(sourceCode, {
  syntax: 'ecmascript'
});

const { code } = await swc.print(ast, {
  minify: false
});

实战示例 #

编译 TypeScript 项目 #

javascript
// build.js
const swc = require('@swc/core');
const fs = require('fs');
const path = require('path');

async function build() {
  const files = fs.readdirSync('./src');
  
  for (const file of files) {
    if (file.endsWith('.ts')) {
      const input = fs.readFileSync(`./src/${file}`, 'utf-8');
      
      const result = await swc.transform(input, {
        jsc: {
          parser: {
            syntax: 'typescript'
          },
          target: 'es2015'
        },
        module: {
          type: 'commonjs'
        }
      });
      
      const outputFile = file.replace('.ts', '.js');
      fs.writeFileSync(`./dist/${outputFile}`, result.code);
    }
  }
}

build();

编译 React 组件 #

javascript
const swc = require('@swc/core');

const jsxCode = `
import React from 'react';

function Button({ children, onClick }) {
  return (
    <button className="btn" onClick={onClick}>
      {children}
    </button>
  );
}

export default Button;
`;

const result = await swc.transform(jsxCode, {
  jsc: {
    parser: {
      syntax: 'ecmascript',
      jsx: true
    },
    transform: {
      react: {
        runtime: 'automatic'
      }
    },
    target: 'es2015'
  },
  module: {
    type: 'es6'
  }
});

下一步 #

现在你已经掌握了 SWC 的编译和转译功能,接下来学习 代码压缩 了解如何优化代码体积!

最后更新:2026-03-28