SWC —— 一篇就够

话说最近本来在倒腾 Prisma 和 Graphql ,可是用 vite 做一个前端示例的时候,偏偏被一个蛋疼的问题卡住了,不得已只好重新用 webpack ,正好试试 SWC。

严格论,SWC 是 babel 的取代者,等量对比的应该是 SWC vs esbuild。

SWC

Rust-based platform for the Web

SWC 是一个可扩展的基于 Rust 的平台,适用于下一代快速开发工具。 它被 Next.js、Parcel 和 Deno 等工具以及 Vercel、ByteDance、腾讯、Shopify 等公司使用。

SWC 可用于编译和捆绑。 对于编译,它使用现代 JavaScript 功能获取 JavaScript / TypeScript 文件,并输出所有主流浏览器都支持的有效代码。

.swcrc 编译配置

SWC 开箱即用,无需定制。 或者,您可以覆盖配置。 以下是默认值:

{
  "jsc": {
    "parser": {
      "syntax": "ecmascript",
      "jsx": false,
      "dynamicImport": false,
      "privateMethod": false,
      "functionBind": false,
      "exportDefaultFrom": false,
      "exportNamespaceFrom": false,
      "decorators": false,
      "decoratorsBeforeExport": false,
      "topLevelAwait": false,
      "importMeta": false
    },
    "transform": null,
    "target": "es5",
    "loose": false,
    "externalHelpers": false,
    // Requires v1.2.50 or upper and requires target to be es2016 or upper.
    "keepClassNames": false
  }
}

jsc.externalHelpers

{
  "jsc": {
    "externalHelpers": true
  }
}

输出代码可能依赖于辅助函数来支持目标环境。 默认情况下,辅助函数会内联到需要的输出文件中。

您可以通过启用 externalHelpers 来使用来自外部模块的帮助程序,帮助程序代码将由来自 node_modules/@swc/helpers 的输出文件导入。

捆绑时,此选项将大大减少您的文件大小。

除了 @swc/core 之外,您还必须添加 @swc/helpers 作为依赖项。

jsc.parser

typescript

{
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "tsx": false,
      "decorators": false,
      "dynamicImport": false
    }
  }
}

ecmascript

{
  "jsc": {
    "parser": {
      "syntax": "ecmascript",
      "jsx": false,
      "dynamicImport": false,
      "privateMethod": false,
      "functionBind": false,
      "classPrivateProperty": false,
      "exportDefaultFrom": false,
      "exportNamespaceFrom": false,
      "decorators": false,
      "decoratorsBeforeExport": false,
      "importMeta": false
    }
  }
}

jsc.target

Starting from @swc/core v1.0.27, you can specify the target environment by using the field.

{
  "jsc": {
    // Disable es3 / es5 / es2015 transforms
    "target": "es2016"
  }
}

jsc.loose

Starting from @swc/core v1.1.4, you can enable "loose" transformations by enabling jsc.loose which works like babel-preset-env loose mode.

{
  "jsc": {
    "loose": true
  }
}

参考:Babel 6: loose mode (2ality.com)

ES Class 代码

class Point {
 constructor(x, y) {
     this.x = x;
     this.y = y;
 }
 toString() {
     return `(${this.x}, ${this.y})`;
 }
}

正常模式

"use strict";

var _createClass = (function () {
 function defineProperties(target, props) {
     for (var i = 0; i < props.length; i++) {
         var descriptor = props[i];
         descriptor.enumerable = descriptor.enumerable || false;
         descriptor.configurable = true;
         if ("value" in descriptor) descriptor.writable = true;
         Object.defineProperty(target, descriptor.key, descriptor); // (A)
     }
 }
 return function (Constructor, protoProps, staticProps) {
     if (protoProps) defineProperties(Constructor.prototype, protoProps);
     if (staticProps) defineProperties(Constructor, staticProps);
     return Constructor;
 };
})();

function _classCallCheck(instance, Constructor) {
 if (!(instance instanceof Constructor)) {
     throw new TypeError("Cannot call a class as a function");
 }
}

var Point = (function () {
 function Point(x, y) {
     _classCallCheck(this, Point);

     this.x = x;
     this.y = y;
 }

 _createClass(Point, [{
     key: "toString",
     value: function toString() {
         return "(" + this.x + ", " + this.y + ")";
     }
 }]);

 return Point;
})();

Loose 模式

"use strict";

function _classCallCheck(instance, Constructor) { ··· }

var Point = (function () {
 function Point(x, y) {
     _classCallCheck(this, Point);

     this.x = x;
     this.y = y;
 }

 Point.prototype.toString = function toString() { // (A)
     return "(" + this.x + ", " + this.y + ")";
 };

 return Point;
})();

jsc.transform

{
  "jsc": {
    "transform": {
      "react": {
        "pragma": "React.createElement",
        "pragmaFrag": "React.Fragment",
        "throwIfNamespace": true,
        "development": false,
        "useBuiltins": false
      },
      "optimizer": {
        "globals": {
          "vars": {
            "__DEBUG__": "true"
          }
        }
      }
    }
  }
}

jsc.transform.legacyDecorator

You can use the legacy (stage 1) class decorators syntax and behavior.

{
  "jsc": {
    "parser": {
      "syntax": "ecmascript",
      "decorators": true
    },
    "transform": {
      "legacyDecorator": true
    }
  }
}

jsc.transform.decoratorMetadata

This feature requires v1.2.13+.

If you are using typescript and decorators with emitDecoratorMetadata enabled, you can use swc for faster iteration:

{
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "decorators": true
    },
    "transform": {
      "legacyDecorator": true,
      "decoratorMetadata": true
    }
  }
}

jsc.transform.react

jsc.transform.react.runtime

可能的值: automatic, classic. 这会影响 JSX 源代码的编译方式。

  • Use runtime: automatic to use a JSX runtime module (e.g. react/jsx-runtime introduced in React 17).
  • Use runtime: classic to use React.createElement instead - with this option, you must ensure that React is in scope when using JSX.

Learn more here.

jsc.transform.react.importSource

  • Defaults to react.
  • When using runtime: automatic, determines the runtime library to import.
  • This option can be overrided with @jsxImportSource foo.

jsc.transform.react.pragma

  • Defaults to React.createElement.
  • When using runtime: classic, replaces the function used when compiling JSX expressions.
  • This option can be overrided with @jsx foo.

jsc.transform.react.pragmaFrag

  • Defaults to React.Fragment
  • Replace the component used when compiling JSX fragments.
  • This option can be overrided with @jsxFrag foo.

jsc.transform.react.throwIfNamespace

Toggles whether or not to throw an error if an XML namespaced tag name is used. For example: <f:image />

Though the JSX spec allows this, it is disabled by default since React's JSX does not currently have support for it.

jsc.transform.react.development

Toggles debug props __self and __source on elements generated from JSX, which are used by development tooling such as React Developer Tools.

This option is set automatically based on the Webpack mode setting when used with swc-loader. See Using swc with webpack.

jsc.transform.react.useBuiltins

Use Object.assign() instead of _extends. Defaults to false.

jsc.transform.react.refresh

Enable react-refresh related transform. Defaults to false as it's considered experimental.

Pass refresh: true to enable this feature, or an object with the following:

interface ReactRefreshConfig {
  refreshReg: String;
  refreshSig: String;
  emitFullSignatures: boolean;
}

jsc.transform.constModules

{
  "jsc": {
    "transform": {
      "constModules": {
        "globals": {
          "@ember/env-flags": {
            "DEBUG": "true"
          },
          "@ember/features": {
            "FEATURE_A": "false",
            "FEATURE_B": "true"
          }
        }
      }
    }
  }
}

Then, source code like:

import { DEBUG } from "@ember/env-flags";
import { FEATURE_A, FEATURE_B } from "@ember/features";

console.log(DEBUG, FEATURE_A, FEATURE_B);

is transformed to:

console.log(true, false, true);

jsc.transform.optimizer

SWC 优化器假设:

  • 它是一个模块或包装在一个 iife 中。
  • 访问(获取)全局变量没有副作用。 它与 google 闭包编译器的假设相同。
  • You don't add fields to literals like a numeric literal, regular expression or a string literal.
  • 文件以 gzip 格式提供。

SWC 不会专注于减少非 gzip 压缩文件的大小。

将此设置为 undefined 会跳过优化器通道。

jsc.transform.optimizer.simplify

Requires v1.2.101+

您可以将其设置为 false 以在跳过优化时使用 inline_globals

{
  "jsc": {
    "transform": {
      "optimizer": {
        "simplify": false,
        "globals": {
          "vars": {
            "__DEBUG__": "true"
          }
        }
      }
    }
  }
}

jsc.transform.optimizer.globals

Requires v1.2.101+

  • vars - Variables to inline.
  • typeofs - If you set { "window": "object" }, typeof window will be replaced with "object".
{
  "jsc": {
    "transform": {
      "optimizer": {
        "globals": {
          "vars": {
            "__DEBUG__": "true"
          }
        }
      }
    }
  }
}

Then, you can use it like npx swc '__DEBUG__' --filename input.js.

jsc.transform.optimizer.jsonify

Requires v1.1.1+

  • minCost - 如果解析纯对象文字的成本大于此值,则将对象文字转换为 JSON.parse('{"foo": "bar"}')。 默认为 1024。
{
  "jsc": {
    "transform": {
      "optimizer": {
        "jsonify": {
          "minCost": 0
        }
      }
    }
  }
}

This will change all pure object literals to JSON.parse("").

jsc.keepClassNames

Requires v1.2.50+ and target to be es2016 or higher

启用此选项将使 swc 保留原始类名。

jsc.paths

Requires v1.2.62+

语法与 tsconfig.json 相同:了解更多

Requires jsc.baseUrl. See below.

jsc.baseUrl

Learn more.

原文:TypeScript: Documentation - Module Resolution (typescriptlang.org)

Base URL

Using a baseUrl is a common practice in applications using AMD module loaders where modules are “deployed” to a single folder at run-time. The sources of these modules can live in different directories, but a build script will put them all together.

Setting baseUrl informs the compiler where to find modules. All module imports with non-relative names are assumed to be relative to the baseUrl.

Value of baseUrl is determined as either:

  • value of baseUrl command line argument (if given path is relative, it is computed based on current directory)
  • value of baseUrl property in ‘tsconfig.json’ (if given path is relative, it is computed based on the location of ‘tsconfig.json’)

Note that relative module imports are not impacted by setting the baseUrl, as they are always resolved relative to their importing files.

You can find more documentation on baseUrl in RequireJS and SystemJS documentation.

Path mapping

Sometimes modules are not directly located under baseUrl. For instance, an import to a module "jquery" would be translated at runtime to "node_modules/jquery/dist/jquery.slim.min.js". Loaders use a mapping configuration to map module names to files at run-time, see RequireJs documentation and SystemJS documentation.

The TypeScript compiler supports the declaration of such mappings using paths property in tsconfig.json files. Here is an example for how to specify the paths property for jquery.

{
  "compilerOptions": {
    "baseUrl": ".", // This must be specified if "paths" is.
    "paths": {
      "jquery": ["node_modules/jquery/dist/jquery"] // This mapping is relative to "baseUrl"
    }
  }
}

Please notice that paths are resolved relative to baseUrl. When setting baseUrl to another value than ".", i.e. the directory of tsconfig.json, the mappings must be changed accordingly. Say, you set "baseUrl": "./src" in the above example, then jquery should be mapped to "../node_modules/jquery/dist/jquery".

Using paths also allows for more sophisticated mappings including multiple fall back locations. Consider a project configuration where only some modules are available in one location, and the rest are in another. A build step would put them all together in one place. The project layout may look like:

projectRoot
├── folder1
│   ├── file1.ts (imports 'folder1/file2' and 'folder2/file3')
│   └── file2.ts
├── generated
│   ├── folder1
│   └── folder2
│       └── file3.ts
└── tsconfig.json

The corresponding tsconfig.json would look like:

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "*": ["*", "generated/*"]
    }
  }
}

This tells the compiler for any module import that matches the pattern "*" (i.e. all values), to look in two locations:

  1. "*": meaning the same name unchanged, so map <moduleName> => <baseUrl>/<moduleName>
  2. "generated/*" meaning the module name with an appended prefix “generated”, so map <moduleName> => <baseUrl>/generated/<moduleName>

Following this logic, the compiler will attempt to resolve the two imports as such:

import ‘folder1/file2’:

  1. pattern ’*’ is matched and wildcard captures the whole module name
  2. try first substitution in the list: ’*’ -> folder1/file2
  3. result of substitution is non-relative name - combine it with baseUrl -> projectRoot/folder1/file2.ts.
  4. File exists. Done.

import ‘folder2/file3’:

  1. pattern ’*’ is matched and wildcard captures the whole module name
  2. try first substitution in the list: ’*’ -> folder2/file3
  3. result of substitution is non-relative name - combine it with baseUrl -> projectRoot/folder2/file3.ts.
  4. File does not exist, move to the second substitution
  5. second substitution ‘generated/*’ -> generated/folder2/file3
  6. result of substitution is non-relative name - combine it with baseUrl -> projectRoot/generated/folder2/file3.ts.
  7. File exists. Done.

jsc.minify

Requires v1.2.67+

See the documentation for minification for more details.

原文:TypeScript: Documentation - Module Resolution (typescriptlang.org)

Minification

🚧

This feature is still under construction. We are working on making the smallest bundle size possible, without breaking changes.

Starting with v1.2.67, you can configure SWC to minify your code by enabling minify in your .swcrc file:

{
// Enable minification
"minify": true,
// Optional, configure minifcation options
"jsc": {
 "minify": {
   "compress": {
     "unused": true
   },
   "mangle": true
 }
}
}

Configuration

jsc.minify.compress

Type: boolean | object.

Similar to the compress option of terser.

{
"jsc": {
 "minify": {
   "compress": true // equivalent to {}
 }
}
}
  • arguments, defaults to false.
  • arrows, defaults to true.
  • booleans, defaults to true.
  • booleans_as_integers, defaults to false.
  • collapse_vars, defaults to true.
  • comparisons, defaults to true.
  • computed_props, defaults to false.
  • conditionals, defaults to false.
  • dead_code, defaults to false.
  • defaults, defaults to true.
  • directives, defaults to false.
  • drop_console, defaults to false.
  • drop_debugger, defaults to true.
  • ecma, defaults to 5.
  • evaluate, defaults to true.
  • global_defs, defaults to {}.
  • hoist_funs, defaults to false.
  • hoist_props, defaults to true.
  • hoist_vars, defaults to false.
  • ie8, Ignored.
  • if_return, defaults to true.
  • inline, defaults to ``.
  • join_vars, defaults to true.
  • keep_classnames, defaults to false.
  • keep_fargs, defaults to false.
  • keep_infinity, defaults to false.
  • loops, defaults to true.
  • negate_iife, defaults to true.
  • passes, defaults to 0, which means no limit.
  • properties, defaults to true.
  • pure_getters, defaults to ``.
  • pure_funcs, defaults to []. Type is an array of string.
  • reduce_funcs, defaults to false.
  • reduce_vars, defaults to false.
  • sequences, defaults to true.
  • side_effects, defaults to true.
  • switches, defaults to false.
  • top_retain, defaults to ``.
  • toplevel, defaults to ``.
  • typeofs, defaults to true.
  • unsafe, defaults to false.
  • unsafe_arrows, defaults to false.
  • unsafe_comps, defaults to false.
  • unsafe_Function, defaults to false.
  • unsafe_math, defaults to false.
  • unsafe_symbols, defaults to false.
  • unsafe_methods, defaults to false.
  • unsafe_proto, defaults to false.
  • unsafe_regexp, defaults to false.
  • unsafe_undefined, defaults to false.
  • unused, defaults to true.
  • module, Ignored. Currently, all files are treated as module.

jsc.minify.mangle

Type: boolean | object.

Similar to the mangle option of terser.

{
  "jsc": {
    "minify": {
      "mangle": true // equivalent to {}
    }
  }
}
  • properties, Defaults to false, and true is identical to {}.
  • topLevel, Defaults to false. Aliased as toplevel for compatibility with terser.
  • keepClassnames, Defaults to false. Aliased as keep_classnames for compatibility with terser.
  • keepFnames, Defaults to false.
  • keepPrivateProps, Defaults to false. Aliased as keep_private_props for compatibility with terser.
  • reserved, Defaults to []
  • ie8, Ignored.
  • safari10, Not implemented yet.

@swc/core Usage

swc.minify(code, options)

This API is asynchronous and all of parsing, minification, and code generation will be done in background thread. The options argument is same as jsc.minify object. For example:

import swc from "@swc/core";

const { code, map } = await swc.minify(
  "import foo from '@src/app'; console.log(foo)",
  {
    compress: false,
    mangle: true,
  }
);

expect(code).toMatchInlineSnapshot(`"import a from'@src/app';console.log(a);"`);

Returns Promise<{ code: string, map: string }>.

swc.minifySync(code, options)

This API exists on @swc/core, @swc/wasm, @swc/wasm-web.

import swc from "@swc/core";

const { code, map } = swc.minifySync(
  "import foo from '@src/app'; console.log(foo)",
  {
    compress: false,
    mangle: true,
  }
);

expect(code).toMatchInlineSnapshot(`"import a from'@src/app';console.log(a);"`);

Returns { code: string, map: string }.

APIs for WebAssembly

Replacing Terser

您可以通过 yarn resolutions 减少构建时间并覆盖 Terser,而无需库来更新它们的依赖项。 示例 package.json 将包括:

{
  "resolutions": { "terser": "npm:@swc/core" }
}

这将对所有嵌套依赖项使用 SWC 缩小器而不是 Terser。 确保删除锁定文件并重新安装依赖项。

$ rm -rf node_modules yarn.lock
$ yarn

jsc.experimental

Currently, there are no experimental options.

多个入口

Requires v1.0.47+

[
  {
    "test": ".*.js$",
    "module": {
      "type": "commonjs"
    }
  },
  {
    "test": ".*.ts$",
    "module": {
      "type": "amd"
    }
  }
]

这使得 SWC 将 JavaScript 文件编译为 CommonJS 模块,并将 TypeScript 文件编译为 AMD 模块。

请注意,test 选项只能用于转编译 typescript 文件,例如

{
  "test": ".*.ts$",
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "tsx": false,
      "decorators": true,
      "dynamicImport": true
    }
  }
}

test

Type: Regex / Regex[]

{
  "test": ".*.ts$",
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "tsx": false,
      "decorators": true,
      "dynamicImport": true
    }
  }
}

exclude

Type: Regex / Regex[]

{
  "exclude": [".*.js$", ".*.map$"],
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "tsx": false,
      "decorators": true,
      "dynamicImport": true
    }
  }
}

sourceMaps

Requires v1.2.50+

Enable source map by adding sourceMaps: true or sourceMaps: 'inline' to the .swcrc.

{
  "sourceMaps": true
}

inlineSourcesContent

Requires v1.2.101+

默认为 true。 如果要让 swc 将文件内容存储到 sourcemap 中,可以将 inlineSourcesContent 设置为 true

{
  "sourceMaps": true,
  "inlineSourcesContent": true
}

浏览器支持

v1.1.10 开始,您现在可以使用 browserslist 自动配置支持的浏览器。

Usage

First, install browserslist. Then, update your .swcrc:

{
  "env": {
    "targets": {
      "chrome": "79"
    },
    "mode": "entry",
    "coreJs": 3
  }
}

Options

browserslist

If you want to use browserlists with SWC, omit targets in your .swcrc:

{
  "env": {
    "coreJs": 3
  }
}

browserlists can be configured in multiple ways:

  • .browserslistrc
  • browserslist field in package.json

You can use path to specify a custom path to load these configuration files.

targets

string | Array<string> | { [string]: string }, defaults to {}.

Describes the environments you support/target for your project. This can either be a browserslist-compatible query:

{
  "env": {
    "targets": "> 0.25%, not dead"
  }
}

Or an object of minimum environment versions to support:

{
  "env": {
    "targets": {
      "chrome": "58",
      "ie": "11"
    }
  }
}

Example environments:

  • chrome
  • opera
  • edge
  • firefox
  • safari
  • ie
  • ios
  • android
  • node
  • electron

If targets is not specified, SWC uses browserslist to get target information.

path

  • string, defaults to current directory.
  • path specifies the directory to load the browserslist module and any browserslist configuration files. For example, .browserslistrc or browserslist field in package.json. This can be useful if your build system isn't in the root of your project.

mode

  • string, defaults to undefined.
  • Possible values: usage, entry, undefined (this matches useBuiltIns from Babel)

⚠️ The usage mode is currently not as efficient as Babel, yet.

skip

Define ES features to skip to reduce bundle size. For example, your .swcrc could be:

{
  "env": {
    "skip": ["core-js/modules/foo"]
  }
}

Additional Options

  • debug: (boolean) defaults to false.
  • dynamicImport: (boolean) defaults to false.
  • loose: (boolean) defaults to false. Enable loose transformations for any plugins that allow them.
  • include: (string[]) can be a core-js module (es.math.sign) or an SWC pass (transform-spread).
  • exclude: (string[]) can be a core-js module (es.math.sign) or an SWC pass (transform-spread).
  • coreJs: (string) defaults to undefined. The version of core-js to use.
  • shippedProposals: (boolean) defaults to false.
  • forceAllTransforms: (boolean) defaults to false. Enable all possible transforms.

Modules

SWC can transpile your code using ES Modules to CommonJS or UMD/AMD. By default, module statements will remain untouched.

CommonJS

To emit a CommonJS module, change the type in .swcrc:

{
  "module": {
    "type": "commonjs",

    // These are defaults.
    "strict": false,
    "strictMode": true,
    "lazy": false,
    "noInterop": false
  }
}

ES6

To emit a ES6 module, change the type in .swcrc:

{
  "module": {
    "type": "es6",

    // These are defaults.
    "strict": false,
    "strictMode": true,
    "lazy": false,
    "noInterop": false
  }
}

AMD

To emit an AMD module, change the type in .swcrc:

{
  "module": {
    "type": "amd",
    // Optional. If specified, swc emits named AMD module.
    "moduleId": "foo",

    // These are defaults.
    "strict": false,
    "strictMode": true,
    "lazy": false,
    "noInterop": false
  }
}

UMD

To emit an UMD module, change the type in .swcrc:

{
  "module": {
    "type": "umd",
    "globals": {},

    // These are defaults.
    "strict": false,
    "strictMode": true,
    "lazy": false,
    "noInterop": false
  }
}

Shared Options

These options are shared by commonjs / es6 / umd / amd inside .swcrc:

{
  "module": {
    // You can specify "commonjs", "es6", "amd", "umd"
    "type": "commonjs",
    "strict": false,
    "strictMode": true,
    "lazy": false,
    "noInterop": false,
    "ignoreDynamic": false
  }
}

strict

默认为false。 默认情况下,当使用 SWC 导出时,会导出不可枚举的 __esModule 属性。 在某些情况下,此属性用于确定导入是默认导出还是包含默认导出。默认为“假”。 默认情况下,当使用 SWC 导出时,会导出不可枚举的 __esModule 属性。 在某些情况下,此属性用于确定导入是默认导出还是包含默认导出。

要防止 __esModule 属性被导出,您可以将 strict 选项设置为 true

strictMode

Defaults to true. If true, swc emits 'use strict' directive.

lazy

默认为“假”。 此选项将 Babel 编译的 import 语句更改为在首次使用导入的绑定时进行延迟评估。 这可以改善模块的初始加载时间,因为有时完全不需要预先评估依赖项。 在实现库模块时尤其如此。

lazy 的值有几个可能的影响:

  • false - 没有任何导入模块的延迟初始化。
  • true - 不要惰性初始化本地 ./foo 导入,而是惰性初始化 foo 依赖项。 本地路径更可能具有循环依赖,如果延迟加载可能会中断,因此默认情况下它们不是惰性的,而独立模块之间的依赖很少是循环的。
  • Array<string> - 使用与给定字符串之一匹配的源来延迟初始化所有导入。

导入永远不会惰性的两种情况是:

  • import "foo"; Side-effect imports are automatically non-lazy since their very existence means that there is no binding to later kick-off initialization.
  • export from "foo" Re-exporting all names requires up-front execution because otherwise there is no way to know what names need to be exported.

noInterop

默认为false。 默认情况下,当使用带有 swc 的导出时,会导出一个不可枚举的 __esModule 属性。 然后,此属性用于确定导入是默认导出还是包含默认导出。

在不需要自动展开默认值的情况下,您可以将 noInterop 选项设置为 true 以避免使用 interopRequireDefault 帮助器(如上面的内联形式所示)。

ignoreDynamic

如果设置为 true,将保留动态导入。

打包配置

🚧 此功能仍在建设中。

SWC 能够将多个 JavaScript 或 TypeScript 文件捆绑为一个。

此功能当前命名为 spack,但在 v2 中将重命名为 swcpackspack.config.js 将被 swcpack.config.js 弃用。

查看 打包的基本示例

Configuration

You can configure bundling using spack.config.js with similar options to webpack. In the future, we are exploring a webpack compatible plugin system.

// spack.config.js

module.exports = {
  entry: {
    web: __dirname + "/src/index.ts",
  },
  output: {
    path: __dirname + "/lib",
  },
};

Note: CommonJS is currently required. In the future, ES Modules will be supported.

如果您想要自动完成或类型检查配置,您可以使用来自 @swc/core/spackconfig 函数包装导出。 这是一个带有类型注释的标识函数。

const { config } = require("@swc/core/spack");

module.exports = config({
  entry: {
    web: __dirname + "/src/index.ts",
  },
  output: {
    path: __dirname + "/lib",
  },
});

mode

Possible values: production, debug, none.

Currently this value is not used, but it will behave similarly to webpack.

entry

确定打包的入口。 您可以指定一个文件或包名称到文件路径的映射。

注意:目前这应该是绝对路径。 您可以使用 __dirname 创建一个。

未来,SWC 将支持使用相对路径,并将解析相对于 spack.config.js 的文件。

output

You can change destination directory of the bundler using output.

const { config } = require("@swc/core/spack");

module.exports = config({
  output: {
    path: __dirname + "/lib",
    // Name is optional.
    name: "index.js",
  },
});

options

Used to control the behavior of SWC. This field is optional.

Migrating from Babel

SWC 的 编译 旨在支持所有 ECMAScript 功能。 SWC CLI 旨在替代 Babel:

$ npx babel # old
$ npx swc # new

Babel 也快有 10 年的历史了,终于也快到他寿终正寝的时候了 —— 他可能没有死,但是在用户的心中已经死了。人们早就翘首期盼着类似 SWC 这样的产物出现。

只是从今天的情况看,SWC 恐怕很难能撑过下一个 10 年(但愿回来打脸)。且不说眼下还有 deno wasmer 这些奇行种的存在。

Comparison

This table outlines the differences between SWC and Babel.

babel package name swc
babel-plugin-external-helpers ✔️
babel-plugin-proposal-async-generator-functions ✔️
babel-plugin-proposal-class-properties ✔️
babel-plugin-proposal-decorators ✔️
babel-plugin-proposal-do-expressions ❌ (stage 1)
babel-plugin-proposal-dynamic-import ✔️
babel-plugin-proposal-export-default-from ✔️
babel-plugin-proposal-export-namespace-from ✔️
babel-plugin-proposal-function-bind ❌ (stage 0)
babel-plugin-proposal-function-sent ❌ (stage 2)
babel-plugin-proposal-json-strings ✔️
babel-plugin-proposal-logical-assignment-operators ❌ (stage 1)
babel-plugin-proposal-nullish-coalescing-operator ✔️
babel-plugin-proposal-numeric-separator ✔️
babel-plugin-proposal-object-rest-spread ✔️
babel-plugin-proposal-optional-catch-binding ✔️
babel-plugin-proposal-optional-chaining ✔️
babel-plugin-proposal-partial-application ❌ (stage 1)
babel-plugin-proposal-pipeline-operator ❌ (stage 0)
babel-plugin-proposal-private-methods ✔️
babel-plugin-proposal-throw-expressions ❌ (stage 2)
babel-plugin-proposal-unicode-property-regex
babel-plugin-syntax-async-generators ✔️
babel-plugin-syntax-bigint ✔️
babel-plugin-syntax-class-properties ✔️
babel-plugin-syntax-decorators ✔️
babel-plugin-syntax-do-expressions ❌ (stage 1)
babel-plugin-syntax-dynamic-import ✔️
babel-plugin-syntax-export-default-from ✔️
babel-plugin-syntax-export-namespace-from ✔️
babel-plugin-syntax-flow
babel-plugin-syntax-function-bind ❌ (stage 0)
babel-plugin-syntax-function-sent ❌ (stage 2)
babel-plugin-syntax-import-meta ❌ (stage 3, wip)
babel-plugin-syntax-json-strings ✔️
babel-plugin-syntax-jsx ✔️
babel-plugin-syntax-logical-assignment-operators ❌ (stage 1)
babel-plugin-syntax-nullish-coalescing-operator ✔️
babel-plugin-syntax-numeric-separator ✔️
babel-plugin-syntax-object-rest-spread ✔️
babel-plugin-syntax-optional-catch-binding ✔️
babel-plugin-syntax-optional-chaining ✔️
babel-plugin-syntax-partial-application ❌ (stage 1)
babel-plugin-syntax-pipeline-operator ❌ (stage 0)
babel-plugin-syntax-throw-expressions ❌ (stage 2)
babel-plugin-syntax-top-level-await ✔️
babel-plugin-syntax-typescript ✔️
babel-plugin-transform-arrow-functions ✔️
babel-plugin-transform-async-to-generator ✔️
babel-plugin-transform-block-scoped-functions ✔️
babel-plugin-transform-block-scoping ✔️
babel-plugin-transform-classes ✔️
babel-plugin-transform-computed-properties ✔️
babel-plugin-transform-destructuring ✔️
babel-plugin-transform-dotall-regex
babel-plugin-transform-duplicate-keys ✔️
babel-plugin-transform-exponentiation-operator ✔️
babel-plugin-transform-flow-comments
babel-plugin-transform-flow-strip-types
babel-plugin-transform-for-of ✔️
babel-plugin-transform-function-name ✔️
babel-plugin-transform-instanceof ✔️
babel-plugin-transform-jscript
babel-plugin-transform-literals ✔️
babel-plugin-transform-member-expression-literals ✔️
babel-plugin-transform-modules-amd ✔️
babel-plugin-transform-modules-commonjs ✔️
babel-plugin-transform-modules-systemjs
babel-plugin-transform-modules-umd ✔️
babel-plugin-transform-named-capturing-groups-regex
babel-plugin-transform-new-target
babel-plugin-transform-object-assign
babel-plugin-transform-object-set-prototype-of-to-assign
babel-plugin-transform-object-super
babel-plugin-transform-object-rest-spread ✔️
babel-plugin-transform-parameters ✔️
babel-plugin-transform-property-literals ✔️
babel-plugin-transform-property-mutators
babel-plugin-transform-proto-to-assign
babel-plugin-transform-react-constant-elements
babel-plugin-transform-react-display-name ✔️
babel-plugin-transform-react-inline-elements
babel-plugin-transform-react-jsx ✔️
babel-plugin-transform-react-jsx-compat
babel-plugin-transform-react-jsx-self ✔️
babel-plugin-transform-react-jsx-source ✔️
babel-plugin-transform-regenerator ✔️
babel-plugin-transform-reserved-words ✔️
babel-plugin-transform-runtime ✔️
babel-plugin-transform-shorthand-properties ✔️
babel-plugin-transform-spread ✔️
babel-plugin-transform-sticky-regex ✔️
babel-plugin-transform-strict-mode ✔️
babel-plugin-transform-template-literals ✔️
babel-plugin-transform-typeof-symbol ✔️
babel-plugin-transform-typescript ✔️
babel-plugin-transform-unicode-regex
babel-preset-env ✔️
babel-preset-env-standalone
babel-preset-flow
babel-preset-react ✔️
babel-preset-stage-0
babel-preset-stage-1
babel-preset-stage-2
babel-preset-stage-3
babel-preset-typescript ✔️
babel-register ✔️ (swc-register)

@swc 官方插件库

@swc/cli

swc 命令行

Usage

Run the following to download pre-built binaries:

npm i -D @swc/cli @swc/core

Then, you can transpile your files:

# Transpile one file and emit to stdout
npx swc ./file.js

# Transpile one file and emit to `output.js`
npx swc ./file.js -o output.js

# Transpile and write to /output dir
npx swc ./my-dir -d output

Options

--filename (-f)

Filename to use when reading from stdin. This will be used in source maps and errors.

npx swc -f input.js

--config-file

Path to a .swcrc file to use.

npx swc input.js --config-file .swcrc

--env-name

The name of the 'env' to use when loading configs and plugins. Defaults to the value of SWC_ENV, or else NODE_ENV, or else development.

npx swc input.js --env-name='test'

--no-swcrc

Whether or not to look up .swcrc files.

npx swc input.js --no-swcrc

--ignore

List of glob paths to not compile.

npx swc src --ignore **/*.test.js

--only

List of glob paths to only compile

Example:

npx swc src --only **/*.js

--watch (-w)

To automatically recompile files on changes, install chokidar:

npm i -D chokidar

Then, add the -w flag:

npx swc input.js -w

--quiet (-q)

Suppress compilation output.

npx swc input.js -q

--source-maps (-s)

Values: true|false|inline|both

npx swc input.js -s

--source-map-target

Define the file for the source map.

npx swc input.js -s --source-map-target input.map.js

--source-file-name

Set sources[0] on returned source map

--source-root

The root from which all sources are relative.

--out-file (-o)

Compile all input files into a single file.

npx swc input.js -o output.js

--out-dir (-d)

Compile an input directory of modules into an output directory.

npx swc src -d dist

--copy-files (-D)

When compiling a directory, copy over non-compilable files.

npx swc src --copy-files

--include-dotfiles

Include dotfiles when compiling and copying non-compilable files.

npx swc src --include-dotfiles

--config (-C)

Override a config from .swcrc file.

npx swc src -C module.type=amd -C module.moduleId=hello

--sync

Invoke swc synchronously. Useful for debugging.

npx swc src --sync

--log-watch-compilation

Log a message when a watched file is successfully compiled.

npx swc input.js --log-watch-compilation

--extensions

Use specific extensions.

@swc/core

这些是核心 SWC API,主要对构建工具者有用。

transform

const swc = require("@swc/core");

swc
  .transform("source code", {
    // Some options cannot be specified in .swcrc
    filename: "input.js",
    sourceMaps: true,
    // Input files are treated as module by default.
    isModule: false,

    // All options below can be configured via .swcrc
    jsc: {
      parser: {
        syntax: "ecmascript",
      },
      transform: {},
    },
  })
  .then((output) => {
    output.code; // transformed code
    output.map; // source map (in string)
  });

transformSync

Returns { code: string, map?: string }

transformFile

Returns Promise<{ code: string, map?: string }>

transformFileSync

Returns { code: string, map?: string }

Options

This still needs to be documented. Contributions welcome!

@swc/wasm-web

该模块允许您使用 WebAssembly 在浏览器内同步转换代码。(机翻,谅解,大意就是能直接在浏览器内使用 wasm 咯)

Usage

You must first initialize the module before you can use it.

import { useEffect, useState } from "react";
import initSwc, { transformSync } from "@swc/wasm-web";

export default function App() {
  const [initialized, setInitialized] = useState(false);

  useEffect(() => {
    async function importAndRunSwcOnMount() {
      await initSwc();
      setInitialized(true);
    }
    importAndRunSwcOnMount();
  }, []);

  function compile() {
    if (!initialized) {
      return;
    }
    const result = transformSync(`console.log('hello')`, {});
    console.log(result);
  }

  return (
    <div className="App">
      <button onClick={compile}>Compile</button>
    </div>
  );
}

@swc/jest

为了让您的 Jest 测试运行得更快,您可以使用 drop-in Rust 替换 替换默认的基于 JavaScript 的运行程序 (ts-jest) SWC。

Installation

npm i -D jest @swc/jest

Usage

Inside jest.config.js, configure Jest to use SWC:

module.exports = {
  transform: {
    "^.+\\.(t|j)sx?$": ["@swc/jest"],
  },
};

swc-loader

Webpack loader

Installation

npm i --save-dev @swc/core swc-loader

Usage

module: {
  rules: [
    {
      test: /\.m?js$/,
      exclude: /(node_modules)/,
      use: {
        // `.swcrc` can be used to configure swc
        loader: "swc-loader"
      }
    }
  ];
}

React Development

The jsc.transform.react.development option is automatically set based on the webpack mode.

其他推荐阅读

示例项目

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章