I want to migrate a SQlite database:
knex --knexfile knexfile.ts migrate:latest
However this gives the following typescript error:
⨯ Unable to compile TypeScript:
knexfile.ts:1:18 - error TS2307: Cannot find module 'path' or its corresponding type declarations.
1 import path from 'path';
~~~~~~
knexfile.ts:4:1 - error TS2580: Cannot find name 'module'. Do you need to install type definitions for node? Try `npm i --save-dev @types/node`.
4 module.exports = {
~~~~~~
knexfile.ts:7:28 - error TS2304: Cannot find name '__dirname'.
7 filename: path.resolve(__dirname, 'src', 'database', 'database.sqlite'),
~~~~~~~~~
knexfile.ts:10:29 - error TS2304: Cannot find name '__dirname'.
10 directory: path.resolve(__dirname, 'src', 'database', 'migrations'),
~~~~~~~~~
knexfile.ts:13:29 - error TS2304: Cannot find name '__dirname'.
13 directory: path.resolve(__dirname, 'src', 'database', 'seeds'),
~~~~~~~~~
TSError: ⨯ Unable to compile TypeScript:
knexfile.ts:1:18 - error TS2307: Cannot find module 'path' or its corresponding type declarations.
1 import path from 'path';
~~~~~~
knexfile.ts:4:1 - error TS2580: Cannot find name 'module'. Do you need to install type definitions for node? Try `npm i --save-dev @types/node`.
4 module.exports = {
~~~~~~
knexfile.ts:7:28 - error TS2304: Cannot find name '__dirname'.
7 filename: path.resolve(__dirname, 'src', 'database', 'database.sqlite'),
~~~~~~~~~
knexfile.ts:10:29 - error TS2304: Cannot find name '__dirname'.
10 directory: path.resolve(__dirname, 'src', 'database', 'migrations'),
~~~~~~~~~
knexfile.ts:13:29 - error TS2304: Cannot find name '__dirname'.
13 directory: path.resolve(__dirname, 'src', 'database', 'seeds'),
~~~~~~~~~
Bellow is my knexfile
:
import path from 'path';
import 'dotenv/config';
module.exports = {
client: 'sqlite3',
connection: {
filename: path.resolve(__dirname, 'src', 'database', 'database.sqlite'),
},
migrations: {
directory: path.resolve(__dirname, 'src', 'database', 'migrations'),
},
seeds: {
directory: path.resolve(__dirname, 'src', 'database', 'seeds'),
},
useNullAsDefault: true,
};
How can I address such issue? I am using the following dependencies:
devDependencies | dependencies |
---|---|
"@types/bcryptjs": "^2.4.2", | "@vscode/sqlite3": "^5.0.8" |
"@types/cors": "^2.8.7", | "bcryptjs": "^2.4.3" |
"@types/express": "^4.17.7", | "cors": "^2.8.5" |
"@types/jsonwebtoken": "^8.5.8" | "dotenv": "^8.2.0" |
"@types/node": "^17.0.24" | "express": "^4.17.1" |
"knex-types": "^0.3.2" | "jsonwebtoken": "^8.5.1" |
"ts-node-dev": "^1.0.0-pre.56" | "knex": "^1.0.7" |
"typescript": "^4.6.3" | "ts-node": "^8.10.2" |
"sqlite3": "^5.0.3" |
package.json
file{
"name": "imonitor-server",
"version": "1.0.0",
"description": "",
"main": "src/server.ts",
"scripts": {
"start": "node build/src/server.js",
"postinstall": "tsc",
"dev": "tsnd --transpile-only --ignore-watch node_modules --respawn src/server.ts",
"knex:migrate": "knex --knexfile knexfile.ts migrate:latest",
"knex:seed": "knex --knexfile knexfile.ts seed:run",
"knex:rollback": "knex --knexfile knexfile.ts migrate:rollback",
"build": "tsc"
},
"repository": {
"type": "git",
"url": "git+https://github.com/lucasbbs/imonitor-backend.git"
},
"keywords": [],
"engines": {
"node": "16.14.0",
"npm": "8.3.1"
},
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/lucasbbs/imonitor-backend/issues"
},
"homepage": "https://github.com/lucasbbs/imonitor-backend#readme",
"devDependencies": {
"@types/bcryptjs": "^2.4.2",
"@types/cors": "^2.8.7",
"@types/express": "^4.17.7",
"@types/jsonwebtoken": "^8.5.8",
"@types/node": "^17.0.24",
"knex-types": "^0.3.2",
"ts-node-dev": "^1.0.0-pre.56",
"typescript": "^4.6.3"
},
"dependencies": {
"@vscode/sqlite3": "^5.0.8",
"bcryptjs": "^2.4.3",
"cors": "^2.8.5",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"jsonwebtoken": "^8.5.1",
"knex": "^1.0.7",
"pg": "^8.3.0",
"sqlite3": "^5.0.3",
"ts-node": "^8.10.2"
}
}
The immediate issue here is that you're trying use TypeScript at runtime, but you've defined @types/node
as a development dependency. By default, Heroku strips devDependencies
from your project after building it.
One option is to skip the pruning step, which will leave your devDependencies
in place, but that likely isn't the right choice. Normally you'll want these dependencies to be stripped. Among other reasons, this reduces the size of your application slug.
Another option is to move @types/node
from devDependencies
to dependencies
. But I don't think that's the right move here, either. My gut says you shouldn't be using TypeScript at all in production.
Since your build
script simply runs tsc
, I wonder if it has already compiled your knexfile.ts
to knexfile.js
. If it did, you can try running the JavaScript file directly:
knex --knexfile knexfile.js migrate:latest
Since that's the default file that Knex looks for, you can actually skip the argument entirely:
knex migrate:latest
This should get your migrations going, but you're going to run into another issue: Heroku's ephemeral filesystem makes SQLite a poor database choice.
Any changes you make to the database, including schema changes introduced by your migrations, will be lost whenever your dyno restarts. This happens frequently (at least once per day).
To resolve that issue, you'll want to switch from SQLite to a client-server database. Heroku's own Postgres service is a reasonable starting point, but there are other database addons if you prefer. You can also host your own database elsewhere on the cloud, e.g. on Microsoft Azure or AWS.