#swc-nodeでESModulesを使う方法
@swc/coreと@swc-node/registerをインストールします。
#設定
下記の設定をします。
package.jsonに"type": "module"を加えます。tsconfig.jsonのcompilerOptions.moduleを"NodeNext"にします。importする際にpathに
.jsを付けます。 (例:import { createTitle } from './utils.js')package.jsonに下記のような処理を実行する設定を追加します。
{
  ...
  "scripts": {
    "execute": "node --loader @swc-node/register/esm scripts/index.ts"
  },
  ...
}
#tsconfig.jsonの例
{
    "compilerOptions": {
      "target": "ESNext",
      "module": "NodeNext",
      "allowJs": true,
      "strict": true,
      "moduleResolution": "NodeNext",
      "esModuleInterop": true,
      "baseUrl": "./",
      "skipLibCheck": true,
      "typeRoots": ["node_modules/@types"],
      "sourceMap": false
    },
    "include": [
      "./scripts/**/*"
    ]
}
#ESLint
typescript-eslintを使います。設定ファイルの拡張子を.cjsにします。(例: .eslintrc.cjs)
これをしない場合、Error [ERR_REQUIRE_ESM]が発生します。
#Jest
@swc/jestを使います。
package.jsonのscriptsを以下のようにします。
{
    ...
    "scripts": {
        "test": "NODE_OPTIONS=--experimental-vm-modules jest",
    },
    ...
}
モックでのimport処理を以下のように変更します。
変更前
import { readFile } from 'node:fs/promises'
jest.mock('node:fs/promises')
import { createTitle }  from './utils.js'
変更後
import { jest } from '@jest/globals'
jest.unstable_mockModule('node:fs/promises', () => ({ readFile: jest.fn() }))
const { readFile } = await import ('node:fs/promises')
const { createTitle } = await import('./utils.js')
#@swc/jest
jest、@types/jest、@swc/core、@swc/jestをインストールします。
設定ファイルの拡張子を.cjsにします。(例: jest.config.cjs)
#jest.config.cjsの例
module.exports = {
  roots: ['<rootDir>/scripts'],
  testMatch: ['**/*.test.ts'],
  extensionsToTreatAsEsm: ['.ts', '.tsx'],
  moduleNameMapper: {
    '^(\\.{1,2}/.*)\\.js$': '$1',
  },
  transform: {
    '^.+\\.ts$': [
      '@swc/jest',
    ],
  },
}