skip to Main Content

I am trying to upgrade node from version 16 => 20
I also decided to try and upgrade some other libraries altogether
I tried starting my backend after the upgrades

% yarn run dev
[nodemon] 3.0.1
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): src/**/*
[nodemon] watching extensions: ts
[nodemon] starting `ts-node --transpileOnly --files src/index.ts`

soon followed by

/Users/.../backend/node_modules/ts-node/dist/index.js:851
            return old(m, filename);
                   ^
Error [ERR_REQUIRE_ESM]: require() of ES Module /Users/.../backend/node_modules/file-type/index.js from /Users/.../backend/src/feature-core/upload-file.ts not supported.
Instead change the require of index.js in /Users/.../backend/src/feature-core/upload-file.ts to a dynamic import() which is available in all CommonJS modules.
    at require.extensions.<computed> [as .js] (/Users/.../backend/node_modules/ts-node/dist/index.js:851:20)

I am not sure what needs to be updated or how, I tried making some changes following some github issues but could’t find a solution.

Update

This is where the error takes place:

import { protectedProcedure } from '../trpc/initialize'
import { randomString } from '../utils/rand'
import { uploadFile as uploadFileToS3 } from '../lib/s3'
import { TRPCError } from '@trpc/server'
import { fileTypeFromBuffer } from 'file-type'

export const uploadFileBase64 = protectedProcedure.input(z.object({ body: z.string() })).mutation(async ({ input }) => {
  const buffer = Buffer.from(input.body, 'base64')
  const fileType = await fileTypeFromBuffer(buffer)

  if (fileType === undefined) {
    throw new TRPCError({ code: 'BAD_REQUEST', message: 'ファイルの種類を判定できませんでした' })
  }

  const key = `${randomString()}.${fileType.ext}`
  await uploadFileToS3({
    key,
    body: buffer,
    contentType: fileType.mime,
  })

  return { key: '' }
})

I am not using require, neither here nor in any other file, so according to the answers I am guessing I need to add "type": "module" to my package.json.
However after adding that I got this error instead:

TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /Users/.../backend/src/index.ts
    at new NodeError (node:internal/errors:405:5)
    at Object.getFileProtocolModuleFormat [as file:] (node:internal/modules/esm/get_format:99:9)
    at defaultGetFormat (node:internal/modules/esm/get_format:142:36)
    at defaultLoad (node:internal/modules/esm/load:91:20)
    at DefaultModuleLoader.load (node:internal/modules/esm/loader:263:26)
    at DefaultModuleLoader.moduleProvider (node:internal/modules/esm/loader:179:22)
    at new ModuleJob (node:internal/modules/esm/module_job:63:26)
    at DefaultModuleLoader.#createModuleJob (node:internal/modules/esm/loader:203:17)
    at DefaultModuleLoader.getJobFromResolveResult (node:internal/modules/esm/loader:156:34)
    at DefaultModuleLoader.getModuleJob (node:internal/modules/esm/loader:141:17) {
  code: 'ERR_UNKNOWN_FILE_EXTENSION'
}
[nodemon] app crashed - waiting for file changes before starting...

So I am guessing there is still something I am missing.

2

Answers


  1. Chosen as BEST ANSWER

    Quick Answer

    const fileTypes = await eval("import('file-type')")
    

    putting this inside an async function should do the trick

    Explanation

    As explained by @monim the library file-type became ESM-only package after an upgrade, which required me to add "type": "module" and change all my imports to ESM format.

    Did I want to change to ESM?
    No, only one library had become ESM-only, and inside a pretty large directory I would rather keep the changes I make minimal. So as suggested by @Evert I tried using await import inside an async function.
    This worked perfectly, and everything ran smoothly except tslint which gave me this error:

    error TS1323: Dynamic imports are only supported when the '--module' flag is set to 'es2020', 'es2022', 'esnext', 'commonjs', 'amd', 'system', 'umd', 'node16', or 'nodenext'.
    

    And after a quick search I found out that changing the code to eval('await import()) could fix the tslint error message.
    If you are not using tslint this should work fine as well:

    const fileTypes = await import ('file-type')
    

  2. this error occurs because a package you are importing has been converted to an ESM-only package (ECMAScript modules ), which means that the package cannot be imported with require() anymore. so as you said you upgraded some libraries first you have to check if they no longer support ESM .

    to solve this error use imports/exports instead of require() .

    don’t forget to add "type": "module" to your package.json file: .

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search