After reading about SWC, and how it is supposed to be both a transpiler á la babel and a typescript compiler, while doing both blazingly fast, we wanted to check if it could improve our build times.
And it really did! The details of our setup will follow, but first things first: here are the results.
Results
The builds were measured with the time command on macOS and WSL, and with Measure-Command on powershell.
OS | Babel/TSC | SWC | Improvement (%) |
---|---|---|---|
macOS | 1m 41s | 1m 21s | 19.8% |
Ubuntu 18.04 working on windows files (WSL 1) | 6m 10s | 1m 36s | 74.05% |
Ubuntu 20.04 working on ubuntu files (WSL 2) | 3m 21s | 1m 45d | 47.76% |
Windows (Powershell) | 2m 31s | 1m 40s | 33.77% |
The biggest improvement was reached with WSL operating on files in the Windows file system. A whopping 74% reduction in build time is reason enough to switch! This is a WSL 1 distro, so if that is your setup, it could be worth checking out whether you could receive the same benefit. A WSL 2 distro operating on a Linux file system got quite a speed boost as well with a 47% reduction in build time.
On macOS, the improvement was more modest. 20% is still a lot! But in absolute numbers, we only save about 20 seconds, compared with the minutes saved on the WSL builds. This is, however, still a point in SWCs favour.
Windows/powershell placed in the middle, with 33% build time decrease, saving almost a minute. What is interesting is that while babel/tsc had wildly varying build times on the different platforms, SWC has reduced the build times to be almost identical on all the platforms - they are obviously doing something right!
Configuration
So, in case you want to test it out yourself, here is how we have configured SWC. Our frontend application uses a micro frontend architecture, which you can read more about in our blog post about it, and our motivation for choosing it.
As a summary: We have several standalone frontend apps that load components from each other. Each app is (currently) typescript/react based. They all have their own webpack config, which is the bundler we use. That means that we can, as of now, use the same SWC and webpack config for making all the apps use SWC.
I am assuming that you are already somewhat familiar with how babel, typescript and webpack work.
The dependencies we have installed for this are @swc/core, @swc/jest and swc-loader.
SWC config
.swcrc
[
{
"test": ".tsx?$",
"jsc": {
"parser": {
"syntax": "typescript",
"tsx": true,
"decorators": false,
"dynamicImport": true
}
}
},
{
"test": ".jsx?$",
"jsc": {
"parser": {
"syntax": "ecmascript",
"jsx": true,
"decorators": false,
"dynamicImport": true
}
}
}
]
You can read the full docs here to get an explanation of what the different options mean, but I will point out why we have two config objects. The test property on each object is used to determine if that config should be used on a given file that is sent to the swc-loader by, in our instance, webpack. The only two differences here is that if a ts/tsx file is supplied, we want to use typescript syntax and allow tsx, and if a js/jsx file is supplied, we want to use ecmascript syntax, and allow jsx.
Webpack config
webpack.config.js
module.exports = {
...
module: {
rules: [
...
{
test: /\.([jt]sx?)?$/,
use: "swc-loader",
exclude: /node_modules/,
},
...
],
},
...
};
I have included only the loader config for SWC, and in webpack, the only real benefit is that you don't need to specify two separate loaders for typescript and javascript files.
Jest config
jest.config.js
module.exports = {
transform: {
"^.+\\.(t|j)sx?$": ["@swc/jest"],
},
...
};
Once again, only the SWC-relevant config is included. We use jest as a test framework in our apps, so we need to transpile code for jest as well.
Conclusion
For those of us using a windows/wsl combination, the change has been magical! If you are on other platforms, you could still get a nice speed boost, at least if your setup looks like ours. And as mentioned, SWC seems to give a more similar performance across platforms thant Babel/TSC did. Did you try out swc, and get different results? Have we configured it all wrong? Yell at us on Twitter!