better-sqlite3 TypeError: o.default is not a constructor

304 Views Asked by At

I am creating a vscode extension in typescript, webpack and better-sqlite3. I try to create a database in the C:\Users\userName\AppData\Roaming\Code\User\globalStorage\ folder.

But i get the error:

TypeError: o.default is not a constructor

This is my code:


import Database from 'better-sqlite3';
import * as fs from "fs";
import { DatabaseNames } from "./database-names.enum";
import { PersistenceRepository } from './persistence.repository';

export class BetterSqliteAdapter implements PersistenceRepository {

    private static instance: BetterSqliteAdapter | null = null;

    db: Database.Database | null = null;

    private constructor() { };


    ;

    public static getInstance() {
        if (!this.instance) {
            this.instance = new BetterSqliteAdapter();
        }
        return this.instance;
    }

    createDatabase(name: DatabaseNames, globalStoragePath: string): void {
        const dbPath = globalStoragePath + "\\" + name + ".db";
        console.log('dbPath :>> ', dbPath);
        if (!fs.existsSync(globalStoragePath)) {
            throw new Error('Extension folder don\'t exist');
        }
        if (!fs.existsSync(dbPath)) {
            try {
                this.db = new Database(dbPath);

            } catch (error) {
                console.log(`Error creating database: ${name}.db ...  error: ${error}`);
            }
        }
    }

this is my tsconfig.json:

{
  "compilerOptions": {
    "module": "CommonJS",
    "target": "ES2020",
    "lib": ["ES2020", "DOM"],
    "sourceMap": true,
    "rootDir": "src",
    "strict": true ,
    "jsx": "react",
    "esModuleInterop": true
  }
}

i also tried this (How to correctly and fully import BetterSqlite3's Database class in typescript?) but it doesn't work. Still get the same error.

Update:

The persistence.repository.ts:

import { DatabaseNames } from './database-names.enum';

export interface PersistenceRepository {

    /**
     * This method will check if a database with a specific name existe, if not, it will be created.
     * @param name name of the database to check if exist or create.
     */
    createDatabase(name: DatabaseNames, globalStoragePath: string): void;

}

Since it's a vscode extension development, i launch it pressing F5. This is the launch.json (it is the default launch.json from yo-code extension creator):

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Run Extension",
            "type": "extensionHost",
            "request": "launch",
            "args": [
                "--extensionDevelopmentPath=${workspaceFolder}"
            ],
            "outFiles": [
                "${workspaceFolder}/dist/**/*.js"
            ],
            "preLaunchTask": "${defaultBuildTask}"
        },
        {
            "name": "Extension Tests",
            "type": "extensionHost",
            "request": "launch",
            "args": [
                "--extensionDevelopmentPath=${workspaceFolder}",
                "--extensionTestsPath=${workspaceFolder}/out/test/suite/index"
            ],
            "outFiles": [
                "${workspaceFolder}/out/**/*.js",
                "${workspaceFolder}/dist/**/*.js"
            ],
            "preLaunchTask": "tasks: watch-tests"
        }
    ]
}

this is the tasks.json:

{
    "version": "2.0.0",
    "tasks": [
        {
            "type": "npm",
            "script": "watch",
            "problemMatcher": "$ts-webpack-watch",
            "isBackground": true,
            "presentation": {
                "reveal": "never",
                "group": "watchers"
            },
            "group": {
                "kind": "build",
                "isDefault": true
            }
        },
        {
            "type": "npm",
            "script": "watch-tests",
            "problemMatcher": "$tsc-watch",
            "isBackground": true,
            "presentation": {
                "reveal": "never",
                "group": "watchers"
            },
            "group": "build"
        },
        {
            "label": "tasks: watch-tests",
            "dependsOn": [
                "npm: watch",
                "npm: watch-tests"
            ],
            "problemMatcher": []
        }
    ]
}

this is the package.json scripts and dependencies:

"scripts": {
    "vscode:prepublish": "npm run package",
    "compile": "webpack --mode development --progress",
    "watch": "webpack --mode development --progress --watch",
    "package": "webpack --mode production ",
    "compile-tests": "tsc -p . --outDir out",
    "watch-tests": "tsc -p . -w --outDir out",
    "pretest": "npm run compile-tests && npm run compile && npm run lint",
    "lint": "eslint src --ext ts",
    "test": "node ./out/test/runTest.js"
  },
  "devDependencies": {
    "@types/better-sqlite3": "^7.6.5",
    "@types/glob": "^8.1.0",
    "@types/mocha": "^10.0.1",
    "@types/node": "20.2.5",
    "@types/react": "^18.2.21",
    "@types/react-dom": "^18.2.7",
    "@types/vscode": "^1.81.0",
    "@typescript-eslint/eslint-plugin": "^5.59.8",
    "@typescript-eslint/parser": "^5.59.8",
    "@vscode/test-electron": "^2.3.2",
    "drizzle-kit": "^0.19.13",
    "eslint": "^8.41.0",
    "glob": "^8.1.0",
    "mini-css-extract-plugin": "^2.7.6",
    "mocha": "^10.2.0",
    "terser-webpack-plugin": "^5.3.9",
    "ts-loader": "^9.4.3",
    "typescript": "^5.1.3",
    "webpack": "^5.85.0",
    "webpack-cli": "^5.1.1"
  },
  "dependencies": {
    "@vscode/webview-ui-toolkit": "^1.2.2",
    "better-sqlite3": "^8.6.0",
    "drizzle-orm": "^0.28.6",
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  }

Update 2:

i deleted the node modules, uninstalled better-sqlite3 and re-installed it. Now i have the following error: TypeError: Cannot read properties of undefined (reading 'indexOf').

If i remove the try / catch clause, no error are thrown.

Update 3:

i deleted the node modules, uninstalled better-sqlite3 and re-installed it AGAIN. Now I have the first error message again

Update 4:

I just tried to create a file directly with 'fs' to check that I have permissions and that my project is not misconfigured. It has worked perfectly. The code i changedis:

 createDatabase(name: DatabaseNames, globalStoragePath: string): void {
    ...
    fs.writeFileSync(dbPath, '');
    ...
}
1

There are 1 best solutions below

0
vktop On

After many hours of research, at the moment it is not possible to directly use any library for SQLite when developing a vscode extension. At least if you want to work with local files instead of an in-memory database. This is because to use SQLite, each operating system must have different binaries. One of the possible solutions is to use this configuration in the webpack.config.js:

    externals: {
      "better-sqlite3": "commonjs better-sqlite3",
    },

But you will have to find a way for the user to have the necessary binaries installed on their computer.

sources of that information: