Skip to content
Advertisement

Migrating from Babel to SWC with React

TL;DR

How to translate a node script like this:

"test": "NODE_ENV=test riteway -r @babel/register 'src/**/*.test.js' | tap-nirvana",

to use SWC instead of Babel?


Context

We recently upgraded our Next.js version. Next.js now supports SWC instead of Babel.

The unit tests for React in our project are written with RITEway. The test command is:

"test": "NODE_ENV=test riteway -r @babel/register 'src/**/*.test.js' | tap-nirvana",

It transforms the files with Babel first because otherwise import statements and JSX would cause errors.

During our attempts to migrating to SWC, we had no luck with the CLI. However, we found the @swc-node/register package. It allowed us to transform our command like this:

"test": "riteway -r @swc-node/register src/**/*.test.js | tap-nirvana"

which fixes new syntax like the import statement and a test like this would run:

import { describe } from 'riteway';

describe('my test', async assert => {
  assert({
    given: 'true',
    should: 'be true',
    actual: true,
    expected: true,
  });
});

However, tests for React components like this

import { describe } from 'riteway';
import render from 'riteway/render-component';

import Authentication from './user-authentication-component';

describe('user authentication component', async assert => {
  const $ = render(<Authentication />);

  assert({
    given: 'just rendering',
    should: "render 'Authentication'",
    actual: $('*:contains("Authentication")').text(),
    expected: 'Authentication',
  });
});

still throw the following error:

$ yarn test
yarn run v1.22.17
$ riteway -r @swc-node/register src/**/*.test.js | tap-nirvana
/Users/user/dev/learning-flow/node_modules/@swc/core/index.js:135
        return bindings.transformSync(isModule ? JSON.stringify(src) : src, isModule, toBuffer(newOptions));
                        ^

Error: error: Expression expected
 
  |
7 |   const $ = render(<Authentication />);
  |                                    ^

error: Expression expected
 
  |
7 |   const $ = render(<Authentication />);
  |                                     ^

error: Unexpected token `)`. Expected this, import, async, function, [ for array literal, { for object literal, @ for decorator, function, class, null, true, false, number, bigint, string, regexp, ` for template literal, (, or an identifier
 
  |
7 |   const $ = render(<Authentication />);
  |                                      ^



Caused by:
    0: failed to process js file
    1: Syntax Error
    at Compiler.transformSync

How can we create that command so that it runs with SWC?

Answer

After some experimentation I found out that it works if you import React from 'react'; in every file (both the component as well as the test) and change the file extensions to .jsx as described in the docs.

However, this is unsatisfying, as we’d like to use React 17’s JSX transform feature to avoid having to import React in every file. Additionally, we’d like to keep all file endings .js.

We tried setting .swcrc without any luck so far.

I’m posting this answer here in case no way to configure .swcrc can be found.

Advertisement