typeorm-seeding icon indicating copy to clipboard operation
typeorm-seeding copied to clipboard

Cannot use import statement outside a module

Open nodegin opened this issue 10 months ago • 13 comments

After upgrading to latest release (7.0.0), I got this error:

/Users/user/Desktop/project/node_modules/@jorgebodega/typeorm-seeding/dist/cli.js:2
import { bootstrap } from './commands/seed.command';
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at internalCompileFunction (node:internal/vm:77:18)
    at wrapSafe (node:internal/modules/cjs/loader:1290:20)
    at Module._compile (node:internal/modules/cjs/loader:1342:27)
    at Module._extensions..js (node:internal/modules/cjs/loader:1437:10)
    at Object.require.extensions.<computed> [as .js] (/Users/user/Desktop/project/node_modules/ts-node/src/index.ts:1608:43)
    at Module.load (node:internal/modules/cjs/loader:1212:32)
    at Function.Module._load (node:internal/modules/cjs/loader:1028:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:142:12)
    at phase4 (/Users/user/Desktop/project/node_modules/ts-node/src/bin.ts:649:14)
    at bootstrap (/Users/user/Desktop/project/node_modules/ts-node/src/bin.ts:95:10)

nodegin avatar Mar 27 '24 16:03 nodegin

Hey @nodegin you can use this lib as an executor, mine was fixed when use this lib.

package.json:

    "typeorm": "tsx ./node_modules/typeorm/cli",
    "seeding": "tsx ./node_modules/@jorgebodega/typeorm-seeding/dist/cli",
    "migration:generate": "npm run typeorm -- -d ./src/db/typeorm.config.ts migration:generate ./src/db/migrations/$npm_config_name",
    "migration:run": "npm run typeorm -- -d ./src/db/typeorm.config.ts migration:run",
    "migration:revert": "npm run typeorm -- -d ./src/db/typeorm.config.ts migration:revert",
    "seed:run": "npm run seeding -- seed -d ./src/db/typeorm.config.ts ./src/db/seeds/*.ts"

terminal:

npm run seed:run

rashgaroth avatar Apr 08 '24 09:04 rashgaroth

v7 switched from CommonJS to ESM. It is not mentioned in the breaking changes, but it is a breaking change for projects that are using CommonJS

alumni avatar Apr 19 '24 10:04 alumni

As far as I tried, I did not change anything to be ESM-only (TypeORM is still supporting CommonJS).

If you are sure of this problem, a PR would be appreciated.

jorgebodega avatar Apr 19 '24 11:04 jorgebodega

Introduced by PR #303 in tsconfig.json by changing: compilerOptions.module: node16 (v6) -> es2022 (v7)

This change replaced the requires with imports. It's true that package.json doesn't contain type: module, so the package is still CommonJS, but the scripts are using ESM imports.

Probably the best option for consistency would be to use node16 or nodenext when transpiling: https://www.typescriptlang.org/tsconfig#module. If you take a look at @tsconfig/node20, they are using module: node16.

alumni avatar Apr 19 '24 11:04 alumni

Normally since it's a CLI tool, it shouldn't matter whether it's CommonJS or ESM, but it does if you are forced to call dist/cli.js directly from your own project. We do that because both the seeds and the typeorm config are written in TypeScript, so we are executing e.g. ts-node typeorm-seeding/dist/cli.js *.seed.ts -d ormconfig.ts.

Later edit: ts-node supports --esm (and it also provides ts-node-esm), so probably not a big deal, will need to check if it solves the issue for me.

alumni avatar Apr 19 '24 11:04 alumni

ts-node --esm does not work (obviously) and tsx doesn't work either because it uses esbuild which is not good at transpiling TypeScript (especially decorators in the TypeORM entities).

I'll update the tsconfig.json to use tsconfig/node18 probably and submit a PR.

alumni avatar Apr 19 '24 13:04 alumni

Since neither ts-node nor tsx are working and since ESM imports in CommonJS modules are not allowed anyway, I opened PR #325 to set the TypeScript target module type back to node16 (auto-detect, based on package.json config) instead of es2022 (forced ESM). This changes the ESM imports back to CJS requires and solves this issue.

In general, I would not change from node16 to anything else since this is the option that detects the module type automatically (unless multiple compilation targets are needed, e.g. to publish both CJS and ESM in one package).

alumni avatar Apr 22 '24 14:04 alumni

@jorgebodega/typeorm-factory has the same issue.

alumni avatar Apr 25 '24 14:04 alumni

You may don't need anything at all. at least some typescript runner eg bun

// create-users.ts

import dataSource from "@demo-app/backend/db/seeds/datasource";

import { UsersEntity } from "@demo-app/backend/src/users/users.entity";

const users: Partial<UsersEntity>[] = [ {
    email: "[email protected]",
    password: "test",
} ];

await dataSource.createEntityManager().save(
    users.map( user => Object.assign( new UsersEntity(), user ) )
);
// datasource.ts

import { DataSource } from "typeorm";

import DatabaseConfig from "@demo-app/backend/config/database.config";

const dataSource = await ( new DataSource( DatabaseConfig ) ).initialize();

export default dataSource;
// database.config.ts

import { UsersEntity } from "@demo-app/backend/src/users/users.entity";

import type { TypeOrmModuleOptions } from "@nestjs/typeorm";

const config : TypeOrmModuleOptions  = {
    type: "sqlite",
    database: "db/database.sqlite",
    logging: "all",
    logger: "advanced-console",
};

function shouldSynchronize( config: TypeOrmModuleOptions ) {
    // If database exists, do not synchronize
    if ( "sqlite" === config.type ) {
        return ! require( "fs" ).existsSync( config.database );
    }

    // TODO: Implement for other database types
    return false;
}

export default {
    ...config,

    entities: [ UsersEntity ],
    synchronize: shouldSynchronize( config ),
};
 bun run --bun create-users.ts

iNewLegend avatar Jul 01 '24 16:07 iNewLegend

FYI bun doesn't work properly with TypeORM.

Or rather, TypeORM has some incorrect package.json config that makes bun interpret imports incorrectly. See https://github.com/oven-sh/bun/issues/7633 or a few other tickets in the bun repo.

alumni avatar Jul 01 '24 17:07 alumni

Hey @nodegin you can use this lib as an executor, mine was fixed when use this lib.

package.json:

    "typeorm": "tsx ./node_modules/typeorm/cli",
    "seeding": "tsx ./node_modules/@jorgebodega/typeorm-seeding/dist/cli",
    "migration:generate": "npm run typeorm -- -d ./src/db/typeorm.config.ts migration:generate ./src/db/migrations/$npm_config_name",
    "migration:run": "npm run typeorm -- -d ./src/db/typeorm.config.ts migration:run",
    "migration:revert": "npm run typeorm -- -d ./src/db/typeorm.config.ts migration:revert",
    "seed:run": "npm run seeding -- seed -d ./src/db/typeorm.config.ts ./src/db/seeds/*.ts"

terminal:

npm run seed:run

Thank you, we can follow this temp solution to fix this

duongductrong avatar Jul 20 '24 17:07 duongductrong

tsx and bun didn't work for my for the reasons specified above. My current solution was to update to 7.1.0-next.1 and patch the dynamic import in commandUtils.js until this is properly fixed.

diff --git a/dist/utils/commandUtils.js b/dist/utils/commandUtils.js
index 0a922d09f28843382e947501307f775b4181a1f3..febe6d3d13660918072d81c6de0aad19228f1356 100644
--- a/dist/utils/commandUtils.js
+++ b/dist/utils/commandUtils.js
@@ -8,7 +8,7 @@ async function loadDataSource(dataSourceFilePath) {
     return CommandUtils_1.CommandUtils.loadDataSource(dataSourceFilePath);
 }
 async function loadSeeders(seederPaths) {
-    const seederFileExports = (await Promise.all(seederPaths.map((seederFile) => import(seederFile))))
+    const seederFileExports = (await Promise.all(seederPaths.map((seederFile) => Promise.resolve().then(() => require(seederFile)))))
         .map((seederExport) => seederExport.default?.default ?? seederExport.default)
         .filter((seederExport) => Boolean(seederExport));
     if (seederFileExports.length === 0) {

Instead of the dynamic import, the actual solution would be to use importOrRequireFile from typeorm/util/ImportUtils - then the seeders would be loaded in the same way ormconfig, entities, subscribers and migrations are loaded.

Or even better, we could completely rely on TypeORM for loading the classes from the globs, using importClassesFromDirectories (from typeorm/util/DirectoryExportedClassesLoader).

alumni avatar Jul 22 '24 12:07 alumni

I just opened two PRs, #338 and #339.

I prefer #339 since it relies on more on TypeORM build-in functions, so there's less code in this repo to maintain.

alumni avatar Jul 22 '24 14:07 alumni