Web technologies continue to evolve every year. Modern programming languages need modern environments in which to run, and although modern web browsers generally support cool new features, older versions of browsers do not.
But if web developers need to build websites that are compatible with both new and old technologies, how can they write modern code that still runs in old browsers?
That’s where JavaScript compilers come into play. Similar to compilers for other languages, JavaScript compiles modern JS code into code that can run in old browsers without loss of functionality.
Webpack and Babel are the standard tools when it comes to bundling modern JavaScript code. Babel is mostly used for converting modern JavaScript to older versions that can be supported by older browsers.
The biggest disadvantage of using these tools is that the creation time can become tediously long, especially for large projects. So, shortening the build time can streamline your projects — ultimately saving time, money, and the nerves of developers.
One project that improves the performance of JavaScript compiling tools is SWC. It’s a compiler written in Rust that claims to be significantly faster than Babel. Its efficiency, for example, is why Next.js switched from Babel to SWC.
In early tests, previous code transformations using Babel dropped from ~500ms to ~10ms and code minification from Terser dropped from ~250ms to ~30ms using SWC. Overall, this resulted in twice as fast builds. – Next.js changelog, version 11.1
So, SWC is drastically faster than webpack and Babel, but what if you have already bootstrapped your project with those tools? Is it possible to switch from this setup to SWC tooling?
Yes, it is! Let’s see how.
Let’s say you have a simple web application with an HTML file and some JavaScript files. These files are bundled with webpack and the JavaScript files are compiled with Babel.
How the bundling should be done, which compiler should be used for which file type, and the many configuration options are defined in a webpack configuration file that might look something like this:
const path = require('path'); module.exports = { entry: './src/index.js', output: { filename: 'main.js', path: path.resolve(__dirname, 'dist'), }, module: { rules: [ { test: /\.?js$/, exclude: /node_modules/, use: { loader: "babel-loader", } }, ], }, };
Now, if you want to use SWC to bundle your files instead of using Babel, you have two options.
You can replace the compiler and continue using webpack, or you can use SWC’s own bundler called spack, which can completely replace webpack, along with Babel.
Let’s start with the second option first.
To completely replace Babel and webpack, you can use the built-in bundler called spack. It will be installed automatically when you run it:
npm i --save-dev @swc/core swc-loader
Now, similar to the webpack.config.js
file, you need to create a file called spack.config.js
in the root directory of your project, which has the following form:
module.exports = { entry: { web: __dirname + "/src/index.js", }, output: { path: __dirname + "/lib", }, };
You can refer to the official documentation to see what other configurations you can set up with it.
If you want to see real-life examples, you can visit the SWC project’s GitHub page, where some simple examples have been created to best demonstrate how spack and SWC work.
To build your project, run npx spock
in the root of your project. The script will automatically take the configuration and use SWC to compile your JavaScript code, then place it in the output path you defined.
Note: At the time of writing this article, I would not recommend using spack for a production project because it is still in development. The documentation is missing information and many features like custom loaders, and creating multiple bundles do not currently work or are not documented.
This option, which is probably safer and easier due to spack’s unfinished documentation and development, uses SWC as the compiler instead of Babel. To achieve this, you need to install the loader, as follows:
npm i --save-dev @swc/core swc-loader
Next, you have to replace babel-loader
with the installed swc-loader
.
If you do not have a compiler defined, you can simply add the following to your webpack configuration instead of replacing it.
module.exports = { entry: './src/index.js', output: { filename: 'main.js', path: path.resolve(__dirname, 'dist'), }, module: { rules: [ { test: /\.m?js$/, exclude: /(node_modules|bower_components)/, use: { // `.swcrc` can be used to configure swc loader: "swc-loader" } } ], }, };
And that’s it! webpack will now use the lightning-fast SWC compiler instead of Babel to compile your code.
To use a custom configuration, you can create a .swcrc
file where you can customize any configuration you need.
If you use Terser to shrink your output files, SWC also provides you with the option to do the same shrinking from scratch.
You can define this option in the .swcrc
file. Most of the options are similar to those of the Terser plugin, which means it’s enough to copy the options from the Terser plugin into the minify field in .swcrc
.
When it comes to using spack as a complete replacement to webpack and Babel, there are a few caveats to consider. First, your project is not necessarily production-ready because, to date, there are many features of spack that are not quite ready and/or missing.
However, if you’re using just the compiler, your project could likely be used in production. Next.js 11.1 now uses it and has shown that it is quite stable.
Still, I would be cautious, as it is still new, and, although Next is already using it, they are working closely with the developer who created the library.
It’s important to note that there are still several open issues and the documentation is not really detailed enough to configure more advanced use cases.
Building, bundling, and compiling modern web applications can be tedious and costly if it is done in pipelines. SWC takes this challenge head-on by streamlining the bundling and compiling process.
Moreover, migrating Babel is quite easy and the results are incredibly promising so far. Given the fact that the project is young and already has a lot of potential, I’m very excited to see it develop.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
Bypass anti-bot measures in Node.js with curl-impersonate. Learn how it mimics browsers to overcome bot detection for web scraping.
Handle frontend data discrepancies with eventual consistency using WebSockets, Docker Compose, and practical code examples.
Efficient initializing is crucial to smooth-running websites. One way to optimize that process is through lazy initialization in Rust 1.80.