# Swc > 🚧 This feature will be dropped in v2, in favor of SWC-based bundlers like [Parcel 2], [Turbopack], [Rspack], [fe-farm]. --- # Source: https://swc.rs/docs/configuration/bundling # Bundling Configuration 🚧 This feature will be dropped in v2, in favor of SWC-based bundlers like [Parcel 2 ], [Turbopack ], [Rspack ], [fe-farm ]. Please use one of the bundlers instead. SWC is able to bundle multiple JavaScript or TypeScript files into one. This feature is currently named `spack `, but will be renamed to `swcpack `in `v2 `. `spack.config.js `will be deprecated for `swcpack.config.js `. View a [basic example of bundling ]. ## 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. If you want auto-completion or type checking for configuration, you can wrap the export with a `config `function from `@swc/core/spack `. It’s an identity function with type annotation. spack.config.js ```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 [] Determines the entry of bundling. You may specify a file or a map of bundle name to file path. > Note: Currently this should be absolute path. You can use `__dirname `to create one. In the future, SWC will support using relative paths and will resolve files relative to `spack.config.js `. ### output [] You can change destination directory of the bundler using `output `. spack.config.js ```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. --- # Source: https://swc.rs/docs/configuration/minification # Minification āš ļø This section is for people who want to use swc as a last step of the build process. If you want to use the swc minifier with a bundler, see the documentation for - [swcMinify with the Terser Webpack Plugin ] - [SWC Minify Webpack Plugin ]which is a standalone tool if you only want minification. # Assumptions SWC Minifier makes small amount of assumptions to make the minification efficient. This is similar to other minifiers. - `.toString() `and `.valueOf() `don’t have side effects, and for built-in objects they have not been overridden. - `undefined `, `NaN `and `Infinity `have not been externally redefined. - `arguments.callee `, `arguments.caller `and `Function.prototype.caller `are not used. These are not valid in strict mode. - The code doesn’t expect the contents of `Function.prototype.toString() `or `Error.prototype.stack `to be anything in particular. - Getting and setting properties on a plain object does not cause other side effects (using `.watch() `or `Proxy `). - Object properties can be added, removed and modified (not prevented with `Object.defineProperty() `, `Object.defineProperties() `, `Object.freeze() `, `Object.preventExtensions() `or `Object.seal() `). - `document.all `is not `null `. - Assigning properties to a class doesn’t have side effects and does not throw. - Acesssing**declared**top-level identifiers do not have side effects. If you declare a variable on `globalThis `using a getter with side-effects, SWC Minifier will likely break it. - TDZ violation does not exist. TDZ violation will be ignored and not preserved. - Arithmetic expression may**not**have side effects. This assumption means that you can’t rely on the exception thrown by the JS engine when adding a bigint and a number. ```const a = 1 n ; const b = 1 ; const c = a + b; ``` If you execute this code, the JS engine will throw an exception. But SWC Minifier will ignore it. Related: [terser - compiler assumptions ] Starting with `v1.2.67 `, you can configure SWC to minify your code by enabling `minify `in your `.swcrc `file: .swcrc ```{ // Enable minification "minify" : true , // Optional, configure minification options "jsc" : { "minify" : { "compress" : { "unused" : true }, "mangle" : true } } } ``` ## Configuration [] ### Note about comments [] If you set `jsc.minify.compress `to `true `or `{} `, SWC will remove all comments starting from `v1.11.11 `. Previous versions will preserve only license comments. If you don’t want this, modify `jsc.minify.format `. ### `jsc.minify.compress `[] Type: `boolean | object `. Similar to [the compress option ]of `terser `. .swcrc ```{ "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 `true `. - `conditionals `, defaults to `true `. - `dead_code `, defaults to `true `. - `defaults `, defaults to `true `. - `directives `, defaults to `true `. - `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 `true `. - `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 `true `. - `sequences `, defaults to `true `. - `side_effects `, defaults to `true `. - `switches `, defaults to `true `. - `top_retain `, defaults to ā€œ. - `toplevel `, defaults to `true `. - `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 `. .swcrc ```{ "jsc" : { "minify" : { "mangle" : true // equivalent to {} } } } ``` - `props `, Defaults to `false `, and `true `is identical to `{} `. - `topLevel `, Defaults to `true `. Aliased as `toplevel `for compatibility with `terser `. - `keepClassNames `, Defaults to `false `. Aliased as `keep_classnames `for compatibility with `terser `. - `keepFnNames `, Defaults to `false `. - `keepPrivateProps `, Defaults to `false `. Aliased as `keep_private_props `for compatibility with `terser `. - `reserved `, Defaults to `[] ` - `ie8 `, Ignored. - `safari10 `, Defaults to `false `. #### `jsc.minify.mangle.properties `[] Type: `object `. Similar to [the mangle properties option ]of `terser `. .swcrc ```{ "jsc" : { "minify" : { "mangle" :{ "properties" :{ "reserved" : [ "foo" , "bar" ], "undeclared" : false , "regex" : "rust regex" } } } } } ``` - `reserved `: Don’t use these names as properties. - `undeclared `: Mangle properties even if it’s not declared. - `regex `: Mangle properties only if it matches this regex ### `jsc.minify.format `[] These properties are mostly not implemented yet, but it exists to support passing terser config to swc minify without modification. - `asciiOnly `, Defaults to `false `. Implemented as `v1.2.184 `and aliased as `ascii_only `for compatibility with `terser `. - `beautify `, Defaults to `false `. Currently noop. - `braces `, Defaults to `false `. Currently noop. - `comments `, Defaults to `some `. - `false `removes all comments - `'some' `preserves some comments - `'all' `preserves all comments - `ecma `, Defaults to 5. Currently noop. - `indentLevel `, Currently noop and aliases as `indent_level `for compatibility with `terser `. - `indentStart `, Currently noop and aliases as `indent_start `for compatibility with `terser `. - `inlineScript `, Aliases as `inline_script `for compatibility with `terser `and requires `@swc/core@1.9.2 `or later. - `keepNumbers `, Currently noop and aliases as `keep_numbers `for compatibility with `terser `. - `keepQuotedProps `, Currently noop and aliases as `keep_quoted_props `for compatibility with `terser `. - `maxLineLen `, Currently noop, and aliases as `max_line_len `for compatibility with `terser `. - `preamble `, Supported since `v1.3.66 `. - `quoteKeys `, Currently noop and aliases as `quote_keys `for compatibility with `terser `. - `quoteStyle `, Currently noop and aliases as `quote_style `for compatibility with `terser `. - `preserveAnnotations `, Currently noop and aliases as `preserve_annotations `for compatibility with `terser `. - `safari10 `, Currently noop. - `semicolons `, Currently noop. - `shebang `, Currently noop. - `webkit `, Currently noop. - `wrapIife `, Currently noop and aliases as `wrap_iife `for compatibility with `terser `. - `wrapFuncArgs `, Currently noop and aliases as `wrap_func_args `for compatibility with `terser `. ## @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 , module: true } ); expect (code). toMatchInlineSnapshot ( `"import a from'@src/app';console.log(a);"` ); ``` Returns `{ code: string, map: string } `. ## APIs for WebAssembly [] ### Replacing Terser [] You can reduce build time and override Terser without needing a library to update their dependencies through [yarn resolutions ]. Example `package.json `would include: package.json ```{ "resolutions" : { "terser" : "npm:@swc/core" } } ``` This will use the SWC minifier instead of Terser for all nested dependencies. Ensure you remove your lockfile and re-install your dependencies. ```$ rm -rf node_modules yarn.lock $ yarn ``` --- # Source: https://swc.rs/docs/configuration/modules šŸ’” SWC provides an official JSON Schema for the configuration file. .swcrc ```{ "$schema" : "https://swc.rs/schema.json" , } ``` # 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 `: .swcrc ```{ "$schema" : "https://swc.rs/schema.json" , "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 `: .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 `: .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 `: .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 `: .swcrc ```{ "module" : { // You can specify "commonjs", "es6", "amd", "umd" "type" : "commonjs" , "strict" : false , "strictMode" : true , "lazy" : false , "noInterop" : false , "ignoreDynamic" : false , "preserveImportMeta" : false , "outFileExtension" : "js" , } } ``` ### strict [] Defaults to `false `. By default, when using exports with SWC, a non-enumerable `__esModule `property is exported. In some cases, this property is used to determine if the import is the default export or if it contains the default export. To prevent the `__esModule `property from being exported, you can set the strict option to `true `. ### strictMode [] Defaults to `true `. If true, swc emits ā€˜use strict’ directive. ### lazy [] Defaults to `false `. This option changes Babel’s compiled `import `statements to be lazily evaluated when their imported bindings are used for the first time. This can improve the initial load time of your module because evaluating dependencies upfront is sometimes entirely unnecessary. This is especially the case when implementing a library module. The value of `lazy `has a few possible effects: - `false `- No lazy initialization of any imported module. - `true `- Do not lazy-initialize local `./foo `imports, but lazy-init `foo `dependencies. Local paths are much more likely to have circular dependencies, which may break if loaded lazily, so they are not lazy by default, whereas dependencies between independent modules are rarely cyclical. - `Array `- Lazy-initialize all imports with source matching one of the given strings. The two cases where imports can never be lazy are: - `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 [] Defaults to `false `. By default, when using exports with swc a non-enumerable `__esModule `property is exported. This property is then used to determine if the import is the default export or if it contains the default export. In cases where the auto-unwrapping of default is not needed, you can set the noInterop option to true to avoid the usage of the interopRequireDefault helper (shown in inline form above). ### ignoreDynamic [] If set to `true `, dynamic imports will be preserved. ### preserveImportMeta [] If set to `true `, `import.meta `will be preserved. ### importInterop [] Possible values: - `swc `(alias: `babel `) - `node ` - `none ` Defaults to `none `if `noInterop `is true, and `swc `otherwise. ### resolveFully [] When set to `true `, fully resolves module `import `file paths, including any that end with `index.js `. ### outFileExtension [] when supplied with `resolveFully `, this will change the extension of any locally resolved file paths to be the one specified. You should use this extension to match the `--out-file-extension `option for @swc/cli. --- # Source: https://swc.rs/docs/configuration/supported-browsers # Supported Browsers Starting with `v1.1.10 `, you can now use `browserslist `to automatically configure supported browsers. ## Usage [] .swcrc ```{ "env" : { "targets" : { "chrome" : "79" }, "mode" : "entry" , "coreJs" : "3.22" } } ``` ## Options [] ### targets [] `string | Array | { [string]: string } `, defaults to `{} `. Describes the environments you support/target for your project. This can either be a [browserslist-compatible ]query [(with limitations) ]: .swcrc ```{ "env" : { "targets" : "> 0.25%, not dead" } } ``` Or an object of minimum environment versions to support: .swcrc ```{ "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, iff you have a usage like `"foo"["a" + "t"]() `. SWC does not evaluate the expression `ā€œaā€ + ā€œtā€ `and will not include the `String.prototype.at `polyfill. ### skip [] Define ES features to skip to reduce bundle size. For example, your `.swcrc `could be: .swcrc ```{ "env" : { "skip" : [ "core-js/modules/foo" ] } } ``` ### coreJs [] - `string `, defaults to `undefined `. - `coreJs `specifies the version of `core-js `to use, can be any core-js versions supported by swc. E.g., `"3.22" `. The option has an effect when used alongside `mode: "usage" `or `mode: "entry" `. It is recommended to specify the minor version (E.g. `"3.22" `) otherwise `"3" `will be interpreted as `"3.0" `which may not include polyfills for the latest features. ## 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 `). - `shippedProposals `: ( *boolean *) defaults to `false `. - `forceAllTransforms `: ( *boolean *) defaults to `false `. Enable all possible transforms. --- # Source: https://swc.rs/docs/configuration/swcrc šŸ’” SWC provides an official JSON Schema for the configuration file. .swcrc ```{ "$schema" : "https://swc.rs/schema.json" , } ``` # Configuring SWC SWC can be configured with an `.swcrc `file. ## Compilation [] Compilation works out of the box with SWC and does not require customization. Optionally, you can override the configuration. Here are the defaults: .swcrc ```{ "$schema" : "https://swc.rs/schema.json" , "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 }, "minify" : false } ``` Read more about [configuring compilation ]. ## Supported Browsers [] Starting with `v1.1.10 `, you can now use `browserslist `to automatically configure supported browsers. ### Usage [] First, install `browserslist `. Then, update your `.swcrc `: .swcrc ```{ "env" : { "targets" : { "chrome" : "79" }, "mode" : "entry" , "coreJs" : "3.22" } } ``` Read more about [configuring supported browsers ]. ## Modules [] Read more about [configuring modules ]. ## Minification [] Starting with `v1.2.67 `, you can configure SWC to minify your code by enabling `minify `in your `.swcrc `file: .swcrc ```{ "minify" : true } ``` Read more about [configuring the JavaScript minifier ]. --- # Source: https://swc.rs/docs/getting-started # Getting Started ## Installation [] The easiest way to try SWC is using the [Playground ]. Otherwise, run the following to download pre-built binaries: ### pnpm npm yarn pnpm ```pnpm add -D @swc/cli @swc/core ``` ### npm ```npm i -D @swc/cli @swc/core ``` ### yarn ```yarn add -D @swc/cli @swc/core ``` Then, you can transpile your first file and emit to `stdout `: ```npx swc ./file.js ``` ## Supported Binaries [] SWC can be downloaded and used as a pre-built binary, or built from source. Currently, the following binaries are provided: - Mac (Apple Silicon) - Mac (x64) - Linux (x86_64) - Linux (aarch64) - Linux (armv7) - Alpine Linux (also install `@swc/core-linux-musl `) - Android (aarch64) - Windows (win32-x64) - Windows (ia32) --- # Source: https://swc.rs/docs/plugin/ecmascript/cheatsheet # Plugin cheatsheet šŸ’” This page describes the known hard points for implementing plugins for ecmascript. You may find documentation at [https://rustdoc.swc.rs/swc ]useful, especially if you are dealing with a visitor or `Id `issue. ## Understanding types [] ### `JsWord `[] `String `allocates, and ā€˜text’-s of source code has a special trait. Those are lots of duplicates. Obviously, if your variable is named `foo `, you need to use `foo `multiple times. So SWC interns the string to reduce the number of allocations. `JsWord `is a string type that is interned. You can create a `JsWord `from `&str `, or from a `String `. Use `.into() `to convert to `JsWord `. ### `Ident `, `Id `, `Mark `, `SyntaxContext `[] SWC uses a special system for managing variables. See [the rustdoc for `Ident `]for details. ## Common issues [] ### Getting AST representation of input [] [SWC Playground ]supports getting AST from the input code. ### Variable management of SWC [] ### Error reporting [] See [rustdoc for `swc_common::errors::Handler `]. ### Comparing `JsWord `with `&str `[] If you don’t know what `JsWord `is, see [the rustdoc for swc_atoms ]. You can create `&str `by doing `&val `where `val `is a variable of type `JsWord `. ### Matching `Box `[] You will need to use `match `to match on various nodes, including `Box `. For performance reason, all expressions are stored in a boxed form. ( `Box `) SWC stores callee of call expressions as a `Callee `enum, and it has `Box `. ```use swc_core :: ast ::* ; use swc_core :: visit :: { VisitMut , VisitMutWith }; struct MatchExample ; impl VisitMut for MatchExample { fn visit_mut_callee ( &mut self , callee : &mut Callee ) { callee . visit_mut_children_with ( self ); if let Callee :: Expr (expr) = callee { // expr is `Box` if let Expr :: Ident (i) = &mut**expr { i . sym = "foo" . into (); } } } } ``` ### Changing AST type [] If you want to change `ExportDefaultDecl `to `ExportDefaultExpr `, you should do it from `visit_mut_module_decl `. ### Inserting new nodes [] If you want to inject a new `Stmt `, you need to store the value in the struct, and inject it from `visit_mut_stmts `or `visit_mut_module_items `. See [a destructuring core transform ]. ```struct MyPlugin { stmts : Vec < Stmt >, } ``` ## Tips [] ### Decorators and TypeScript types [] Those are handled before your plugin is called. So you can’t access them from the Wasm plugin. This design decision is made to make Wasm plugins easier to write and the Wasm binary smaller. - Tracking issue: [https://github.com/swc-project/swc/issues/9132 ] ### Comments while testing [] You can make your pass generic over `C: Comments `. `test_fixture `provides `&mut Tester `, which has `comments `field. - [Example pass ] - [Testing for the test ] ### Apply `resolver `while testing [] SWC applies plugin after applying [`resolver `], so it’s better to test your transform with it. As written in the rustdoc for the `resolver `, you have to use correct `SyntaxContext `if you need to reference global variable (e.g. `__dirname `, `require `) or top-level bindings written by the user. ```fn tr () -> impl Pass { ( resolver ( Mark :: new (), Mark :: new (), false ), // Most of transform does not care about globals so it does not need `SyntaxContext` your_transform () ) } test! ( Syntax :: default (), | _ | tr (), basic, // input "(function a ([a]) { a });" , // output "(function a([_a]) { _a; });" ); ``` ### Make your handlers stateless [] Let’s say we are going to handle all array expressions in a function expression. You can add a flag to the visitor to check if we are in a function expression. You will be tempted to do ```struct Transform { in_fn_expr : bool } impl VisitMut for Transform { noop_visit_mut_type! (); fn visit_mut_fn_expr ( &mut self , n : &mut FnExpr ) { self . in_fn_expr = true ; n . visit_mut_children_with ( self ); self . in_fn_expr = false ; } fn visit_mut_array_lit ( &mut self , n : &mut ArrayLit ) { if self . in_fn_expr { // Do something } } } ``` but this cannot handle ```const foo = function () { const arr = [ 1 , 2 , 3 ]; const bar = function () {}; const arr2 = [ 2 , 4 , 6 ]; } ``` After visiting `bar `, `in_fn_expr `is `false `. You have to do ```struct Transform { in_fn_expr : bool } impl VisitMut for Transform { noop_visit_mut_type! (); fn visit_mut_fn_expr ( &mut self , n : &mut FnExpr ) { let old_in_fn_expr = self . in_fn_expr; self . in_fn_expr = true ; n . visit_mut_children_with ( self ); self . in_fn_expr = old_in_fn_expr; } fn visit_mut_array_lit ( &mut self , n : &mut ArrayLit ) { if self . in_fn_expr { // Do something } } } ``` instead. ### Test with `@swc/jest `[] You can test your transform with `@swc/jest `by adding your plugin to your `jest.config.js `. jest.config.js ```module . exports = { rootDir: __dirname, moduleNameMapper: { "css-variable$" : "../../dist" , }, transform: { "^.+ \\ .(t|j)sx?$" : [ "@swc/jest" , { jsc: { experimental: { plugins: [ [ require. resolve ( "../../swc/target/wasm32-wasi/release/swc_plugin_css_variable.wasm" ), { basePath: __dirname, displayName: true , }, ], ], }, }, }, ], }, }; ``` See [https://github.com/jantimon/css-variable/blob/main/test/swc/jest.config.js ] ### `Path `is one of unix, while FileName can be one of host OS [] This is because linux version of `Path `code is used while compiling to wasm. So you may need to replace `\\ `with `/ `in your plugin. As `/ `is a valid path separator in windows, it’s valid thing to do. ### Comments [] A comment belongs to a span of the node. (lo for leading comments, hi for trailing comments) If you want to add a leading comment to a node, you can do `PluginCommentsProxy.add_leading(span.lo, comment); `. See [PluginCommentsProxy ]. ## Ownership model (of rust) [] > This section is not about `swc `itself. But this is described at here because it’s the cause of almost all trickyness of APIs. In rust, only one variable can *own *a data, and there’s at most one mutable reference to it. Also, you need to *own *the value or have a mutable reference to it if you want to modify the data. But there’s at most one owner/mutable reference, so it means if you have a mutable reference to a value, other code cannot modify the value. Every update operation should performed by the code which *owns *the value or has a mutable reference to it. So, some of babel APIs like `node.delete `is super tricky to implement. As your code has ownership or mutable refernce to *some *part of AST, SWC cannot modify the AST. ## Tricky operations [] ### Deleting node [] Let’s say, we want to drop the variable named `bar `in the code below. ```var foo = 1 ; var bar = 1 ; ``` There are two ways to do this. #### Mark & Delete [] The first way is to mark it as *invalid *and delete it later. This is typically more convenient. ```use swc_core :: ast ::* ; use swc_core :: visit :: { VisitMut , VisitMutWith }; impl VisitMut for Remover { fn visit_mut_var_declarator ( &mut self , v : &mut VarDeclarator ) { // This is not required in this example, but you typically need this. v . visit_mut_children_with ( self ); // v.name is `Pat`. // See https://rustdoc.swc.rs/swc_ecma_ast/enum.Pat.html match v . name { // If we want to delete the node, we should return false. // // Note the `&*` before i.sym. // The type of symbol is `JsWord`, which is an interned string. Pat :: Ident (i) => { if &* i . sym == "bar" { // Take::take() is a helper function, which stores invalid value in the node. // For Pat, it's `Pat::Invalid`. v . name . take (); } } _ => { // Noop if we don't want to delete the node. } } } fn visit_mut_var_declarators ( &mut self , vars : &mut Vec < VarDeclarator >) { vars . visit_mut_children_with ( self ); vars . retain ( | node | { // We want to remove the node, so we should return false. if node . name . is_invalid () { return false } // Return true if we want to keep the node. true }); } fn visit_mut_stmt ( &mut self , s : &mut Stmt ) { s . visit_mut_children_with ( self ); match s { Stmt :: Decl ( Decl :: Var (var)) => { if var . decls . is_empty () { // Variable declaration without declarator is invalid. // // After this, `s` becomes `Stmt::Empty`. s . take (); } } _ => {} } } fn visit_mut_stmts ( &mut self , stmts : &mut Vec < Stmt >) { stmts . visit_mut_children_with ( self ); // We remove `Stmt::Empty` from the statement list. // This is optional, but it's required if you don't want extra `;` in output. stmts . retain ( | s | { // We use `matches` macro as this match is trivial. ! matches! (s, Stmt :: Empty ( .. )) }); } fn visit_mut_module_items ( &mut self , stmts : &mut Vec < ModuleItem >) { stmts . visit_mut_children_with ( self ); // This is also required, because top-level statements are stored in `Vec`. stmts . retain ( | s | { // We use `matches` macro as this match is trivial. ! matches! (s, ModuleItem :: Stmt ( Stmt :: Empty ( .. ))) }); } } ``` #### Delete from the parent handler [] Another way to delete the node is deleting it from the parent handler. This can be useful if you want to delete the node only if the parent node is specific type. e.g. You don’t want to touch the variables in for loops while deleting free variable statements. ```use swc_core :: ast ::* ; use swc_core :: visit :: { VisitMut , VsiitMutWith }; struct Remover ; impl VisitMut for Remover { fn visit_mut_stmt ( &mut self , s : &mut Stmt ) { // This is not required in this example, but just to show that you typically need this. s . visit_mut_children_with ( self ); match s { Stmt :: Decl ( Decl :: Var (var)) => { if var . decls . len () == 1 { match var . decls[ 0 ] . name { Pat :: Ident (i) => { if &* i . sym == "bar" { s . take (); } } } } } _ => {} } } fn visit_mut_stmts ( &mut self , stmts : &mut Vec < Stmt >) { stmts . visit_mut_children_with ( self ); // We do same thing here. stmts . retain ( | s | { ! matches! (s, Stmt :: Empty ( .. )) }); } fn visit_mut_module_items ( &mut self , stmts : &mut Vec < ModuleItem >) { stmts . visit_mut_children_with ( self ); // We do same thing here. stmts . retain ( | s | { ! matches! (s, ModuleItem :: Stmt ( Stmt :: Empty ( .. ))) }); } } ``` ### Referencing parent node from handler of child node [] This includes usage of `paths `and `scope `. ### Caching some information about an AST node [] You have two way to use informantion from a parent node. For first, you can precompute information from the parent node handler. Alternatively, you can clone the parent node and use it in the child node handler. ## Alternatives for babel APIs [] ### `generateUidIdentifier `[] This returns a unique identifier with a monotonically increasing integer suffix. `swc `does not provide API to do this, because there’s a very easy way to do this. You can store an integer field in transformer type and use it while calling `quote_ident! `or `private_ident! `. ```struct Example { // You don't need to share counter. cnt : usize } impl Example { /// For properties, it's okay to use `quote_ident`. pub fn next_property_id ( &mut self ) -> Ident { self . cnt += 1 ; quote_ident! ( format! ( "$_css_{}" , self . cnt)) } /// If you want to create a safe variable, you should use `private_ident` pub fn next_variable_id ( &mut self ) -> Ident { self . cnt += 1 ; private_ident! ( format! ( "$_css_{}" , self . cnt)) } } ``` ### `path.find `[] Upward traversal is not supported by `swc `. It’s because upward traversal requires storing information about parent at children nodes, which requires using types like `Arc `or `Mutex `in rust. Instead of traversing upward, you should make it top-down. For example, if you want to infer name of a jsx component from variable assignments or assignments, you can store `name `of component while visiting `VarDecl `and/or `AssignExpr `and use it from the component handler. ### `state.file.get `/ `state.file.set `[] You can simply store the value in the transform struct as an instance of transform struct only process one file. --- # Source: https://swc.rs/docs/plugin/ecmascript/compatibility # Compatibility for wasm plugin In the past, SWC Wasm plugins were not compatible between `@swc/core `versions. This meant that developers using Wasm plugins often had to update them with each new release of @swc/core to ensure compatibility, and the Wasm plugins maintainers should also update their `swc_core `Rust dependencies. This created friction, added maintenance overhead, and could disrupt development workflows. However, starting from @swc/core v1.15.0, our Wasm plugins are now compatible between `@swc/core `versions to some extent. This document explains from the implementation perspective why Wasm plugins were not compatible before, and how you can make your plugins compatible in the new version. ## Background [] [WebAssembly (Wasm) ]is designed as a portable compilation target for programming languages, enabling execution within a memory-safe, sandboxed environment. The Wasm artifacts compiled by the SWC Wasm plugin are loaded and executed by runtimes such as Wasmer or Wasmtime within `@swc/core `. Wasm plugins cannot directly manipulate the Rust AST data structures within the `@swc/core `host environment. Instead, when invoking a Wasm plugin, the host environment serializes the entire AST into a byte array with the [rkyv ]serialization and transmits it to the Wasm runtime. Prior to executing the Wasm plugin, the wasm plugin deserializes the byte array back into a Rust AST and performs the transformation. And then, the wasm plugin serializes the transformed AST back into a byte array and sends it back to the host environment. ![Overview](/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Foverview.71486faa.png&w=3840&q=75) **However, a critical issue arises here: the serialization logic and the deserialization are compiled into both the host ( `@swc/core `) and the Wasm plugin.**This implies that whenever**`@swc/core `modifies the AST**and releases a new version, the older logic in old Wasm plugins becomes incompatible and ceases to function correctly. ## What SWC has done [] There are two primary changes that SWC has implemented to address this issue: -**Replacing the serialization scheme [rkyv ]with the self-describing serialization scheme [cbor ].**The rkyv scheme typically requires the ABI layout of serialization and deserialization to match exactly. It is highly sensitive to changes in the memory layout of data structures, and any modification to a field can cause compatibility problems. In contrast, cbor is a self-describing serialization/deserialization scheme that records the memory layout of fields as metadata within the byte array. Although this approach sacrifices some performance and data compactness, it enables the serialization and deserialization process to be aware of changes in the data structure. -**Making enums extensible.**For each AST enum data type, SWC has added an `Unknown `variant to accommodate differences in data between different versions of `@swc/core `and Wasm plugins. This allows data introduced in newer versions of `@swc/core `, which older versions of the plugin cannot recognize—to, be preserved across serialization and deserialization. To clarify, based on the above technical principles, SWC does not resolve all compatibility issues, such as those caused by field deletions or changes in field types. In practice, these cases are relatively rare since changes to the AST data structures primarily arise from support for new ECMAScript standards. Therefore, we continue to minimize the frequency of breaking changes in Wasm plugins through CI checks and version release strategies. ## Make your plugin compatible [] It’s very simple to enable your Wasm plugin to benefit from the aforementioned changes. - Make sure your Wasm plugin depends on `swc_core >= 47 `. - Enable `swc_ast_unknown `cfg in your `.cargo/config.toml `file. ```[ target . 'cfg(target_arch = "wasm32")' ] rustflags = [ "--cfg=swc_ast_unknown" ] ``` - For each pattern-match code with ast enum, add a match arm for the `Unknown `variant, and just `panic!() `it. For example: ```match imported { ModuleExportName :: Ident (v) => v . sym == exported . name, ModuleExportName :: Str (v) => { v . value . as_str () == Some (exported . name . as_str ()) } #[cfg(swc_ast_unknown)] _ => panic! ( "unknown node" ) } ``` Why is it the `panic!() `here? What’s the difference between the old version and the new version with `panic!() `? Consider a scenario where ECMAScript introduces a new type of AST node. With the older version of SWC, the Wasm plugin would fail immediately during the deserialization, regardless of whether the actual code or the parsed AST contains the newly introduced node type. In contrast, with the newer version of SWC, the Wasm plugin is able to work correctly on ASTs that do not contain the new node type. --- # Source: https://swc.rs/docs/plugin/ecmascript/getting-started # Implementing a plugin ## Important API Changes [] āš ļø Recent API changes that may affect your plugin development: - Replace `chain! `macro with tuples: Use `( `instead of `chain!( `. You can replace all `chain!( `with `( `using IDE features. - For `chain! `with 13+ arguments: Use nested tuples for items after the 13th element. - Replace `-> impl Fold `with `-> impl Pass `in general. - `as_folder `is now `visit_mut_pass `and returns `impl VisitMut + Pass `instead of `impl VisitMut + Fold `. - Use `Program.apply `and `Program.mutate `to apply Pass to program: - `fn apply(self, impl Pass) -> Self ` - `fn mutate(&mut self, impl Pass) ` - Replace `noop() `with `noop_pass() `. The new function lives in `swc_ecma_ast `and is a real noop function. ## Setup environment [] ### Install required toolchain [] As plugin is written in the rust programming language and built as a `.wasm `file, you need to install rust toolchain and wasm target. #### Install rust [] You can follow instructions at [ā€˜Install Rust’ page from the official rust website ] #### Add wasm target to rust [] SWC supports two kinds of `.wasm `files. Those are - wasm32-wasip1 - wasm32-unknown-unknown In this guide, we will use `wasm-wasip1 `as a target. #### Install `swc_cli `[] You can install a rust-based CLI for SWC by doing ```cargo install swc_cli ``` #### Configuring IDE [] If you are going to use vscode, it’s recommended to install `rust-analyzer `extension. `rust-analyzer `is a [language server ]for the rust programming language, which provides good features for code completion, code navigation, and code analysis. ## Implementing simple plugin [] ### Create a project [] SWC CLI supports creating a new plugin project. Run ```swc plugin new --target-type wasm32-wasip1 my-first-plugin # You should to run this rustup target add wasm32-wasip1 ``` to create a new plugin, and open `my-first-plugin `with your preferred rust IDE. ### Implementing a visitor [] The generated code has ```impl VisitMut for TransformVisitor { // Implement necessary visit_mut_* methods for actual custom transform. // A comprehensive list of possible visitor methods can be found here: // https://rustdoc.swc.rs/swc_ecma_visit/trait.VisitMut.html } ``` which is used to transform code. [The trait `VisitMut `]supports mutating AST nodes, and as it supports all AST types, it has lots of methods. We will use ```foo === bar; ``` as the input. From [the SWC Playground ], you can get actual representation of this code. ```{ "type" : "Module" , "span" : { "start" : 0 , "end" : 12 , "ctxt" : 0 }, "body" : [ { "type" : "ExpressionStatement" , "span" : { "start" : 0 , "end" : 12 , "ctxt" : 0 }, "expression" : { "type" : "BinaryExpression" , "span" : { "start" : 0 , "end" : 11 , "ctxt" : 0 }, "operator" : "===" , "left" : { "type" : "Identifier" , "span" : { "start" : 0 , "end" : 3 , "ctxt" : 0 }, "value" : "foo" , "optional" : false }, "right" : { "type" : "Identifier" , "span" : { "start" : 8 , "end" : 11 , "ctxt" : 0 }, "value" : "bar" , "optional" : false } } } ], "interpreter" : null } ``` Let’s implement a method for `BinExpr `. You can do it like ```use swc_core :: { ast ::* , visit :: { VisitMut , VisitMutWith }, }; impl VisitMut for TransformVisitor { fn visit_mut_bin_expr ( &mut self , e : &mut BinExpr ) { e . visit_mut_children_with ( self ); } } ``` Note that `visit_mut_children_with `is required if you want to call the method handler for children. e.g. `visit_mut_ident `for `foo `and `bar `will be called by `e.visit_mut_children_with(self); `above. Let’s narrow down it using the binary operator. ```use swc_core :: { ast ::* , visit :: { VisitMut , VisitMutWith }, common :: Spanned , }; impl VisitMut for TransformVisitor { fn visit_mut_bin_expr ( &mut self , e : &mut BinExpr ) { e . visit_mut_children_with ( self ); if e . op == op! ( "===" ) { e . left = Box :: new ( Ident :: new_no_ctxt ( "kdy1" . into (), e . left . span ()) . into ()); } } } ``` `op!("===") `is a macro call, and it returns various types of operators. It returns [BinaryOp ]in this case, because we provided `"===" `, which is a binary operator. See [the rustdoc for op! macro ]for more details. If we run this plugin, we will get ```kdy1 === bar; ``` ## Testing your transform [] You can simply run `cargo test `to test your plugins. SWC also provides a utility to ease fixture testing. You can easily verify the input and output of the transform. ```test! ( Default :: default (), | _ | visit_mut_pass ( TransformVisitor ), // Note: Updated to use visit_mut_pass instead of as_folder boo, r#"foo === bar;"# ); ``` Then, once you run `UPDATE=1 cargo test `, the snapshot will be updated. You can take a look at [the real fixture test for typescript type stripper ]. ```#[testing :: fixture( "tests/fixture/**/input.ts" )] #[testing :: fixture( "tests/fixture/**/input.tsx" )] fn fixture (input : PathBuf ) { let output = input . with_file_name ( "output.js" ); test_fixture ( Syntax :: Typescript ( TsConfig { tsx : input . to_string_lossy () . ends_with ( ".tsx" ), .. Default :: default () }), &| t | ( tr (), properties (t, true )), // Note: Updated to use tuple syntax instead of chain! & input, & output, ); } ``` Things to note: - The glob provided to `testing::fixture `is relative to the cargo project directory. - The output file is `output.js `, and it’s stored in a same directory as the input file. - `test_fixture `drives the test. - You can determine the syntax of the input file by passing the syntax to `test_fixture `. - You then provide your visitor implementation as the second argument to `test_fixture `. - Then you provide the input file path and the output file path. ### Logging [] SWC uses `tracing `for logging. By default, SWC testing library configures the log level to `debug `by default, and this can be controlled by using an environment variable named `RUST_LOG `. e.g. `RUST_LOG=trace cargo test `will print all logs, including `trace `logs. If you want, you can remove logging for your plugin by using cargo features of `tracing `. See [the documentation for it ]. ## Publishing your plugin [] Please see [plugin publishing guide ] --- # Source: https://swc.rs/docs/plugin/publishing # Publishing plugins If you prefer reading codes, you can refer to [the repository for official plugins ]. ## Creating a npm package [] ### Building a plugin as a wasm [] You can run your plugin as a wasm file by running ```cargo build-wasi --release // build wasm32-wasi target binary cargo build-wasm32 --release // build wasm32-unknown-unknown target binary ``` It will create `target/wasm32-wasi/release/your_plugin_name.wasm `or `target/wasm32-unknown-unknown/release/your_plugin_name.wasm `, depending on your config. ### Creating a npm package for plugin [] Add the following to your `package.json `: package.json ```{ "main" : "your_plugin_name.wasm" , "scripts" : { "prepack" : "cargo prepublish --release && cp target/wasm32-wasi/release/your_plugin_name.wasm ." }, } ``` ## Advanced: Improving your plugin [] ### Adjusting configuration for smaller binary [] You can reduce the size of the plugin by configuring cargo. In your `Cargo.toml `file, you can add the following lines. Cargo.toml ```[ profile . release ] # This removes more dead code codegen-units = 1 lto = true # Optimize for size opt-level = "s" # Optimize for performance, this is default so you don't need to specify it # opt-level = "z" # Strip debug symbols strip = "symbols" ``` ### Removing log for release mode [] If logging of your crate is too much, you can remove it by enabling `release_max_level_* `of `tracing `, like ```tracing = { version= "0.1" , features = [ "release_max_level_info" ] } ``` --- # Source: https://swc.rs/docs/plugin/selecting-swc-core # Selecting the version Currently, the Wasm plugins are not backwards compatible. So you need to select an appropriate version of `swc_core `for your plugin. We provide a simple webapp to help you select the version of `swc_core `. See: [https://plugins.swc.rs ] You can select the framework and the version of**framework**you are using, and the Wasm plugins compatible with it will be shown. # OLD Documentation for the version of `swc_core ` Please use the webapp instead. The page documents the version of `swc_core `you can use for each runtime. ## Note for next.js [] - [next `v13.2.4 `~ `v13.3.1 `cannot execute SWC Wasm plugins, due to a bug of `next-swc `]. ## swc_core [] If you use a version in a range of the title, the Wasm plugin will work for the runtimes written in the body. ### `v0.98.x `~ [] #### Changes [] - `Span.ctxt `is removed to reduce the size of `Span `. - `ctxt: SyntaxContext `is added to various AST nodes. - `IdentName `is used instead of `Ident `in some places like `MemberProp `, because those fields does not need `ctxt `or `optional `. #### Upgrade guide [] - The update PR for the official plugins: [plugins#334 ] #### Versions [] - `@swc/core@1.7.x ` - `next@v15.0.0-canary.117 `(reverted in `next@v15.0.0-canary.118 `) - `next@v15.0.0-canary.122 `~ ### `v0.95.x `~ `v0.96.x `[] - [CHANGELOG ] We optimized some AST type definitions. - `@swc/core@1.6.x ` - `next@15.0.0-canary.37 `~ `next@v15.0.0-canary.116 ` ### `v0.94.x `[] Do not use this version if you are building a plugin for SWC. ### `v0.91.x `~ `v0.93.x `[] We added support for abstract auto-accessors. - `@swc/core@1.5.x ` - `next@15.0.0-canary.29 `~ `v15.0.0-canary.36 ` ### `v0.90.x `[] We refactored AST to make it less error-prone. - `@swc/core@1.4.x ` - `next@14.1.1-canary.52 `~ `next@15.0.0-canary.28 ` - `@rspack/core@0.6.0 `~ ### `v0.88.x `~ `v0.89.x `[] Support for import phase proposal (stage 3) was added. - `@swc/core@1.3.106 `~ `@swc/core@1.3.107 ` - `@rspack/core@0.5.8 `~ `@rspack/core@0.5.9 ` ### `v0.82.x `~ `v0.87.x `[] We modified AST definitions because of `with `of [Import Attributes proposal ]. - `@swc/core@1.3.81 `~ `@swc/core@1.3.105 ` - ~ `next@14.1.0 ` Note: You may need to specify the version of `swc_common `, too, like ```[ dependencies ] swc_common = "=0.33.15" ``` ### `v0.79.x `~ `v0.81.x `[] We modified AST definitions because of `await `of [Explicit Resource Management proposal ]. - `@swc/core@1.3.68 `~ `@swc/core@1.3.80 ` - `next@13.4.10-canary.1 `~ ### `v0.78.x `[] We modified AST definitions because some of the previous definitions were misdesigned. - `@swc/core@1.3.63 `~ `@swc/core@1.3.67 ` - `next@13.4.8 `~ `next@13.4.10-canary.0 ` ### `v0.76.x `~ `v0.77.x `[] We modified AST definitions because of [Explicit Resource Management proposal ], which is stage 3. - `@swc/core@1.3.58 `~ `@swc/core@1.3.62 ` - `next@13.4.3-canary.2 `~ `next@13.4.7 ` ### `v0.75.x `[] We enabled strict mode of `rkyv `and updated `wasmer `to `v3 `. - `@swc/core@1.3.49 `~ `@swc/core@1.3.57 ` - `v13.3.1-canary.12 `~ `next@13.4.3-canary.1 ` ### `v0.72.4 `~ `v0.74.6 `[] We updated `rkyv `to `v0.7.40 `and the bug is now fixed. - `@swc/core@1.3.44 `~ `@swc/core@1.3.47 ` ### `v0.69.x `~ `v0.72.3 `[] Due to a bug of `rkyv@0.7.37 `, you are recommended to use `nightly-2022-09-23 `as the compiler if you are building a plugin for these targets. - `@swc/core@1.3.40 `~ `@swc/core@1.3.42 ` - `next@13.2.5-canary.5 ` ### `v0.66.x `~ `v0.68.x `[] - `@swc/core@1.3.39 ` ### `v0.61.x `~ `v0.64.x `[] - `@swc/core@1.3.38 ` ### `v0.54.x `~ `v0.59.x `[] - `@swc/core@1.3.29 `~ `@swc/core@1.3.37 ` - `next@13.2.4-canary.0 `~ --- # Source: https://swc.rs/docs/usage/bundling # Bundling (swcpack) 🚧 This feature will be dropped in v2, in favor of SWC-based bundlers like [Parcel 2 ], [Turbopack ], [Rspack ], [fe-farm ]. Please use one of the bundlers instead. SWC is able to bundle multiple JavaScript or TypeScript files into one. This feature is currently named `spack `, but will be renamed to `swcpack `in `v2 `. `spack.config.js `will be deprecated for `swcpack.config.js `. View a [basic example of bundling ]. ## Usage [] ### pnpm npm yarn pnpm ```pnpm i -D @swc/cli @swc/core ``` ### npm ```npm i -D @swc/cli @swc/core ``` ### yarn ```yarn add -D @swc/cli @swc/core ``` Create a `spack.config.js `file and run: ```npx spack ``` ## Configuration [] To see all options, [view the configuration ]. ## Features [] ### Compact Output [] Just like `rollup `, SWC emits compact output. a.js ```console. log ( "loading A" ); export function a () { console. log ( "use!" ); } ``` lib.js ```import { a } from "./a" ; a (); ``` becomes: output.js ```console. log ( "loading A" ); function a () { console. log ( "use!" ); } a (); ``` SWC was designed with merging in mind, so naming collisions between multiple files are automatically handled. ### Tree Shaking [] Just like other modern bundlers, SWC can remove unused exports. ### Import Deglobbing [] To aid with tree-shaking, SWC deglobs imports if possible. ```import * as lib from "lib" ; lib. foo (); ``` behaves exactly same as: ```import { foo } from "lib" ; foo (); ``` This preserves all side effects. ### CommonJS Support [] SWC supports importing CommonJS modules and emits more compact output than webpack. source.js ```import * as lib from "lib" ; console. log (lib); // Prevent dce ``` If the `lib `above is a CommonJS module, it’s transcompiled to: output.js ```const load = __spack_require. bind ( void 0 , function ( module , exports ) { // Code from lib goes here }); const lib = load (); console. log (lib); // Prevent dce ``` ### Optimizations [] - Global Inlining (e.g. `process.env.NODE_ENV `) - Inlining - Constant propagation - Dead code elimination The tree shaking described above is using the dead code elimination pass. Currently, SWC can deduce: source.js ```let b = 2 ; let a = 1 ; if (b) { a = 2 ; } let c; if (a) { c = 3 ; } console. log (c); ``` into: output.js ```console. log ( 3 ); ``` ### High Performance [] Performance is a priority for SWC. It’s very fast because it uses all CPU cores and is optimized by `llvm `. ### Multiple Entries Support [] spack.config.js ```const { config } = require ( "@swc/core/spack" ); module . exports = config ({ entry: { web: __dirname + "/src/web.ts" , android: __dirname + "/src/android.ts" , }, output: { path: __dirname + "/lib" , }, module: {}, }); ``` ### Built-in Chunking [] Using the same config as above, if `android.ts `and `web.ts `both references the same file, it will be extracted as a separate chunk and `web.ts `and `android.ts `will import it. --- # Source: https://swc.rs/docs/usage/cli # @swc/cli ## Usage [] Run the following to download pre-built binaries: ### pnpm npm yarn pnpm ```pnpm i -D @swc/cli @swc/core ``` ### npm ```npm i -D @swc/cli @swc/core ``` ### yarn ```yarn add -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. ### `--strip-leading-paths `[] Remove the leading directory (including all parent relative paths) when building the final output path. As an example it compiles all modules under `src `folder to `dist `folder, without create the `src `folder inside of `dist `. ```npx swc src -d dist --strip-leading-paths ``` ## use in nodejs script [] ```const { swcDir } = require ( '@swc/cli' ); const swcOptions = { jsc: { target: 'esnext' , externalHelpers: true , }, module: { type: 'commonjs' , }, sourceMaps: true , }; swcDir ({ cliOptions: { outDir: './dist' , watch: true , filenames: [ './src' ], extensions: [ '.ts' ], stripLeadingPaths: true , }, swcOptions, callbacks: { onSuccess : e => { console. log (e); }, onFail : e => { console. log (e); }, onWatchReady : () => {}, }, }); ``` Please note that when using `callbacks `, the `--quiet (-q) `will always be true. ### `--out-file-extension `[] Use a specific extension for the output files. As an example, if you want to render your es6 output to `.mjs `file extensions, you could call: ```npx swc input.js --out-file-extension mjs ``` Please note that if you are compiling multiple files, you will also need to make sure that your imports are resolved with the appropriate extension. You can do so by making use of the `resolveFully `and `outFileExtension `module options: ```{ "module" : { "resolveFully" : true , "outFileExtension" : "mjs" } } ``` --- # Source: https://swc.rs/docs/usage/core # @swc/core These are the core SWC APIs mainly useful for build tool authors. ## transform [] `@swc/core `provides appropriate `.d.ts `file, so you may not need this. Returns `Promise<{ code: string, map?: string }> ` ```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 } ` ## parse [] Returns `Promise