knex: knex 0.16 doesn't support knexfiles written in TypeScript

Environment

Knex version: 0.16.3 Database + version: docker postgres:10.4 OS: Windows 10 Pro & Docker node:8.14.0

Bug

  1. knex migrate:make --knexfile knexfile.ts
  2. Error message: Unexpected token import

Works normally on 0.15.x

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 7
  • Comments: 89 (16 by maintainers)

Commits related to this issue

Most upvoted comments

@brunolm why are you so ignorant?

diff --git a/api/package.json b/api/package.json
index c0f8bff..0906f51 100644
--- a/api/package.json
+++ b/api/package.json
@@ -8,7 +8,7 @@
     "dev": "ts-node-dev --respawn --poll --no-notify src/index.ts",
     "\n# Database": "",
     "migrate": "knex migrate:latest --knexfile ./src/db/knexfile.ts",
-    "migrate-make": "knex migrate:make --knexfile ./src/db/knexfile.ts",
+    "migrate-make": "knex migrate:make --cwd src/db",
     "seed": "knex seed:run --knexfile ./src/db/knexfile.ts",
     "seed-make": "knex seed:make --knexfile ./src/db/knexfile.ts",
     "\n# Testing": "",
api_1    | > knex16@1.0.0 migrate-make /usr/src/app
api_1    | > knex migrate:make --cwd src/db "test"
api_1    | 
api_1    | Requiring external module ts-node/register
api_1    | Working directory changed to /usr/src/app/src/db
api_1    | Created Migration: /usr/src/app/src/db/migrations/20190723173751_test.ts

I was facing the same issue with Knex version 0.16.3.

import * as Knex from 'knex';
^^^^^^

SyntaxError: Unexpected token import
    at createScript (vm.js:80:10)
    at Object.runInThisContext (vm.js:139:10)
    at Module._compile (module.js:617:28)
    at Object.Module._extensions..js (module.js:664:10)

This solution is not encouraged but I simply fixed it by simply adding ts-node/register at the beginning of knexfile.ts file.

require('ts-node/register');
//

Solution

Instead of --knexfile use --cwd

-    "migrate-make": "knex migrate:make --knexfile ./src/db/knexfile.ts",
+    "migrate-make": "knex migrate:make --cwd src/db",

Hi guys

I also had this error I think, the problem is that option --knexfile is wrongly set a directory for knexfile.ts So I set explicit directions with --cwd for the directory with knexfile.ts

It works for me: "knex migrate:make --cwd src" (It is equal this: "cd src knex migrate:make")

For those using tsx runtime i used

scripts: {
    ...
    "knex": "tsx ./node_modules/knex/bin/cli.js"
}

and used it like

npm run knex -- migrate:latest

I still get this error with NodeJS 14.0.0, the command knex migrate:make test, and the following file:

// knexfile.ts

export const config = {

  development: {
    client: "postgres",
    connection: {
      filename: "./dev.sqlite3"
    }
  },

  staging: {
    client: "postgresql",
    connection: {
      database: "my_db",
      user: "username",
      password: "password"
    },
    pool: {
      min: 2,
      max: 10
    },
    migrations: {
      tableName: "knex_migrations"
    }
  },

  production: {
    client: "postgresql",
    connection: {
      database: "my_db",
      user: "username",
      password: "password"
    },
    pool: {
      min: 2,
      max: 10
    },
    migrations: {
      tableName: "knex_migrations"
    }
  }
};

I get this error:

Failed to load external module ts-node/register
Failed to load external module typescript-node/register
Failed to load external module typescript-register
Failed to load external module typescript-require
Failed to load external module @babel/register
(node:6468) UnhandledPromiseRejectionWarning: C:\Users\Flori\WebstormProjects\OragesAuthentication-Backend\knexfile.ts:3
export const config = {
^^^^^^

SyntaxError: Unexpected token 'export'
    at wrapSafe (internal/modules/cjs/loader.js:1101:16)
    at Module._compile (internal/modules/cjs/loader.js:1149:27)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1205:10)
    at Module.load (internal/modules/cjs/loader.js:1034:32)
    at Function.Module._load (internal/modules/cjs/loader.js:923:14)
    at Module.require (internal/modules/cjs/loader.js:1074:19)
    at require (internal/modules/cjs/helpers.js:72:18)
    at openKnexfile (C:\Users\Flori\WebstormProjects\OragesAuthentication-Backend\node_modules\knex\bin\cli.js:26:16)

EDIT: This was fixed by adding ts-node as a dependency. Sorry for the inconvenience.

Maybe it will help someone. Fixed when change in tsconfig.json “module”: “es2015” to “module”: “commonjs” Command in package.json => “migrate”: “ts-node -P ./tsconfig.json node_modules/.bin/knex migrate:latest --knexfile knexfile.ts”.

@brunolm @ShGKme @mmiszy @ilkka This should work better in 0.20.9 thanks to amazing work of @briandamaged. Please give it a try and let me know if the changes were helpful for you.

import * as knex from 'knex'
import * as path from 'path'
import { env } from './env'

const database = {
  client: 'postgresql',
  connection: env.databaseUrl,
  migrations: {
    directory: path.resolve('../db/migrations'),
    tableName: 'knex_migrations',
  },
  seeds: {
    directory:  path.resolve('../db/seeds'),
  },
} as knex.Config

export = database

works 100% on 0.15

Quick update on my end. Not sure if this is useful or not, but my issue was that I was using multiple tsconfig.json files in my project, and knex was using the default. When I overrode this functionality by directly launching knex using ts-node, I was able to get around this error.

My updated package.json:

// ...
"knex": "ts-node --project tsconfig.server.json $(npm bin)/knex --knexfile ./src/server/knexfile.ts",
// ...

How I run migrations now:

npm run knex -- migrate:latest

Hopefully this helps someone.

For those using tsx runtime i used

scripts: {
    ...
    "knex": "tsx ./node_modules/knex/bin/cli.js"
}

and used it like

npm run knex -- migrate:latest

Thanks!!! It worked for me!

This still does not work predictably.

If the project uses tsconfig setting “module”: “ES2022” or similar at the root of the project ts-node will pick it up no matter if You would use --cwd or --knexfile and store the actual knexfile.ts in the nested directory. I presume ts compiler or ts-node itself will try to resolve the closest tsconfig.ts from parent directories.

This results in “Unexpected token bleh blah bling” types of errors.

The fix for me was to have the knexfile in nested directory, and create another tsconfig.json NEXT to the knexfile.ts and have the module property set to “CommonJS”.

Maybe possibility for user to give the used tsconfig as a parameter? Or maybe automatically overwrite the module to “CommonJS” if ts is detected so node can read it?

Anyhow, hopefully this helps someone…

@kibertoad + @brunolm : I’ll try to put something together either later today or tomorrow. I’m still making sure I understand the big picture first. From what I can tell, it looks like the Knex CLI might be duplicating some of the functionality that is already provided by the Liftoff library.

Why is this closed ? It’s totally broke when working with knexfile.ts, tried all I could from this thread … (latest version + typescript 3.6.4)

Open new issue and provide reproduction code (for example a link to example project where your problem occur). This was closed because @brunolm found his solution to his problem.

Thanks for looking into it. I’ll see if I can make liftoff behave in these cases 😄 but yeah, using ts-node directly should work in all cases.

In any case, thank you for reminding me about this issue. I’ll try to take another swing at it on the weekend, hopefully I can at least understand why it worked in the past 😄

@brunolm Haha, @briandamaged is the real hero. Glad it works fine now!

It’s still broken with --cwd:

knexfile.ts:6
export default {
^^^^^^

SyntaxError: Unexpected token export

Solution

Instead of --knexfile use --cwd

-    "migrate-make": "knex migrate:make --knexfile ./src/db/knexfile.ts",
+    "migrate-make": "knex migrate:make --cwd src/db",

Thanks !! It helps me a lot.

Hi guys. So as @mikl said, the problem is, that you are trying to run typescript code on node interpreter. I ran into this problem today when I was trying to create a new migration.

I’ve solved this issue by running knex through ts-node (https://npmjs.com/package/ts-node).

To make this work just add this script inside your package.json file 😃

"migrate:make": "ts-node ./node_modules/.bin/knex migrate:make --knexfile <PATH_TO_YOUR_KNEXFILE>"

Replicate this to migrate:latest, seed:run etc… 😃 Then just run your new script!

For fellow googlers, I had the “unexpected token export” error when trying to migrate up/down with the latest knex 0.19 in full typescript mode.

I turned out I had both a tsconfig.json and a .babelrc in the working directory, I suspect one of those interfered with the transpilation.

When I moved the migration folder and the knexfile.ts in a clean directory, it worked again ✅ .

Had same error. Turned out I have copied wrong tsconfig.json. Now it’s working. Relevant configs:

package.json (workspace)

  "scripts": {
    "migrate:make": "knex --cwd src migrate:make -x ts"
  },
  "dependencies": {
    "knex": "0.19.0",
    "pg": "7.11.0"
  }

package.json (root):

		"ts-node-dev": "1.0.0-pre.40",

(ts-node version is: 8.3.0)

tsconfig.json (workspace):

{
	"extends": "../../tsconfig.node.json",
	"compilerOptions": {
		"rootDir": "./src",
		"outDir": "./build",
	}
}

tsconfig.node.json (root):

{
	"compilerOptions": {
		"target": "es2015",
		"moduleResolution": "node",
		"esModuleInterop": true,
		"strict": true,
		"alwaysStrict": true,
		"declaration": true,
	}
}

src/knexfile.ts:

import { Config } from 'knex'

export = {
    client: 'pg',
    connection: {
      database: 'db',
      user: 'user',
    },
} as Config

Command to run:

yarn migrate:make my_migration_name

@algil I didn’t need to update or start a new project yet, so I’m still using 0.15 for the most part.

But I did make a PR that solves this issue, You can fork knex and apply these changes to it: https://github.com/tgriesser/knex/pull/3005

I think I found maybe a bug on 0.16, or just something weird.

On 0.15 launch is called with configPath https://github.com/tgriesser/knex/blob/0.15.2/bin/cli.js#L260

But on 0.16 it’s called with

    knexfile: argv.knexfile,
    knexpath: argv.knexpath,

https://github.com/tgriesser/knex/blob/0.16.3/bin/cli.js#L303-L304

LiftOff calls var env = this.buildEnvironment(opts); which calls findConfig({ passing configPath (which is no longer provided). Internally it uses configPath and makes no reference to knexfile or knexpath.


I have typescript and ts-node installed in the project and it works when I have v0.15 installed (like the example I provided on the Git repository.

I did some debugging and found this, but I still didn’t figure out why it works on 0.15

knex@0.15.2

Logging the result of this line

var config = require(env.configPath);

https://github.com/tgriesser/knex/blob/0.15.2/bin/cli.js#L55

I get this

api_1    |   require(/usr/src/app/src/db/knexfile.ts)------------ { client: 'postgresql',
api_1    |   connection: 'postgres://user:password@db/api-db',
api_1    |   migrations:
api_1    |    { directory: '/usr/src/app/src/db/migrations1337',
api_1    |      tableName: 'knex_migrations' },
api_1    |   seeds: { directory: '/usr/src/app/src/db/seeds' } }
api_1    | this.config { extension: 'js',
api_1    |   loadExtensions:
api_1    |    [ '.co',
api_1    |      '.coffee',
api_1    |      '.eg',
api_1    |      '.iced',
api_1    |      '.js',
api_1    |      '.litcoffee',
api_1    |      '.ls',
api_1    |      '.ts' ],
api_1    |   tableName: 'knex_migrations',
api_1    |   schemaName: null,
api_1    |   directory: '/usr/src/app/src/db/migrations1337',
api_1    |   disableTransactions: false }

The migration directory is saying directory: '/usr/src/app/src/db/migrations1337',, which is exactly what I have on knexfile.ts

And it’s directly requiring the file .ts

require('/usr/src/app/src/db/knexfile.ts')

knex@0.16.3

The require is to the exact same file, but it fails

// /usr/src/app/src/db/knexfile.ts
env.configuration = require(resolvedKnexfilePath);

after installing also some more packages (ts-node ts-node-dev typescript) it seems that both, 0.15 and 0.16 works just fine here… but indeed your docker setup with node 0.16 is failing and I have no idea why

Mikaels-MacBook-Pro-2:test mikaelle$ rm -fr node_modules/*
Mikaels-MacBook-Pro-2:test mikaelle$ npm install knex typescript ts-node
npm WARN test@1.0.0 No description
npm WARN test@1.0.0 No repository field.

+ ts-node@7.0.1
+ knex@0.16.3
+ typescript@3.2.4
added 295 packages from 184 contributors and audited 1213 packages in 6.59s
found 0 vulnerabilities

Mikaels-MacBook-Pro-2:test mikaelle$ node_modules/.bin/knex migrate:make --knexfile knexfile.ts test
Requiring external module ts-node/register
Created Migration: /xxx/migrations/20190119003358_test.js
Mikaels-MacBook-Pro-2:test mikaelle$ cat knexfile.ts 
import * as knex from 'knex'; export = {client: 'pg'}
Mikaels-MacBook-Pro-2:test mikaelle$ 

I modified your docker-compose.yml to make pretty much the same and it fails like this:

version: '3'

services:
  api:
    image: node:8.14.0
    command: bash -c 'rm -fr api/node_modules; npm i knex ts-node typescript; node_modules/.bin/knex migrate:make --knexfile ./src/db/knexfile.ts test'
    working_dir: /usr/src/app
    volumes:
      - ./api:/usr/src/app
api_1  | npm WARN knex16@1.0.0 No repository field.
api_1  | 
api_1  | + ts-node@7.0.1
api_1  | + knex@0.16.3
api_1  | + typescript@3.2.4
api_1  | updated 3 packages and audited 1176 packages in 9.804s
api_1  | found 0 vulnerabilities
api_1  | 
api_1  | /usr/src/app/src/db/knexfile.ts:1
api_1  | (function (exports, require, module, __filename, __dirname) { import { database } from '../config'
api_1  |                                                               ^^^^^^
api_1  |