ecomnazar
ecomnazar

Reputation: 21

Cannot find module '@adminjs/nestjs' or its corresponding type declarations.ts(2307)

Hello Stack Overflow community,

I'm working on a project using NestJS and AdminJS, and I've encountered an issue where TypeScript cannot find the module @adminjs/nestjs or its corresponding type declarations. This issue is preventing me from integrating AdminJS with my NestJS application.

"@adminjs/nestjs": "^6.1.0",

What i tried:

Installation: I first attempted to install the @adminjs/nestjs package using npm, ensuring that the package was correctly added to my project's package.json file. Importing and Usage: After installation, I imported the AdminModule from @adminjs/nestjs into my NestJS module and attempted to use it according to the documentation and examples provided. TypeScript Configuration: I reviewed my TypeScript configuration to ensure that it was set up to recognize the types from @adminjs/nestjs. This included checking my tsconfig.json file for any relevant settings that might affect module resolution. Searching for Solutions: I searched for similar issues on Stack Overflow, GitHub, and other developer forums. I also checked the official documentation and GitHub issues for @adminjs/nestjs to see if others had encountered and resolved the same problem. Environment Check: I verified that my development environment, including Node.js, NestJS, and TypeScript versions, were compatible with the @adminjs/nestjs package requirements.

Upvotes: 1

Views: 1676

Answers (2)

Matej Glasnak
Matej Glasnak

Reputation: 1

I just wanted to share my experience working through the ESM/CJS issues when integrating latest AdminJS, NestJS, and Prisma. After battling with the module resolution issues and figuring out the correct setup, I finally have a working sample project that might be helpful to others who are facing similar challenges.

You can find the full working example here: AdminJS, NestJS, Prisma Sample Project

The sample project includes:

  • AdminJS v7 integrated with NestJS v11
  • Prisma setup and schema
  • Correct module resolution between ESM and CJS formats (project is still in CJS format)

I hope this helps someone out there who’s facing the same setup issues. Feel free to fork the repo and reach out if you run into any questions!

Good luck!

Upvotes: 0

Rares
Rares

Reputation: 41

The newest version of AdminJS is ESM only - meaning it is no longer compatible with a default NestJS application. https://docs.adminjs.co/installation/plugins/nest

You basically have 3 ways to go about this:

  • Revert to an old version of AdminJS (which might cause problems with some database adapters, especially the Mongoose one)
  • Follow their guide and change the tsconfig file - this fundamentally changes how your Nest application handles imports, and depending on your config and dependencies, you might see a lot of stuff breaking
  • And the third one, which, whilst (kind of) hacky, is a good compromise, allowing you to use the newest version of AdminJS (6.1.0 at the time of writing) without modifying the tsconfig file.

The way you go about it is by creating the following method

export const dynamicImport = async (packageName: string) =>
new Function(`return import('${packageName}')`)();

This allows you to import any ESM package from a CommonJS app without it being automatically converted to a 'require' call.

Then, in your Nest app main.ts:

async function bootstrap() {
    const app = await NestFactory.create(AdminDashboardModule);

    app.useGlobalPipes(
        new ValidationPipe({
            transform: true,
            whitelist: true,
        }),
    );

    const adminJSModule = await dynamicImport('adminjs');
    const AdminJS = adminJSModule.default;

    const AdminJSMongoose = await dynamicImport('@adminjs/mongoose');

    AdminJS.registerAdapter({
        Resource: AdminJSMongoose.Resource,
        Database: AdminJSMongoose.Database, // Change with whatever adapter you want to use
    });

    const globalPrefix = 'admin';
    const port = process.env.PORT || 3010;
    await app.listen(port);
    Logger.log(`🚀 Application is running on: http://localhost:${port}/${globalPrefix}`);
}

bootstrap();

In your module imports:

dynamicImport('@adminjs/nestjs').then(({ AdminModule }) => AdminModule.createAdminAsync(.......)

And just in case you were using the uploadComponent (example AWS config for image files):

const uploadModule = await dynamicImport('@adminjs/upload');
const uploadFeature = uploadModule.default;

const adminjs = await dynamicImport('adminjs');
const { ComponentLoader } = adminjs;
const componentLoader = new ComponentLoader();
......
features: [
        uploadFeature({
            componentLoader,
            provider: {
                aws: {
                    region: configService.get(CONFIG_KEYS.AWS_S3.REGION),
                    bucket: configService.get(CONFIG_KEYS.AWS_S3.IMAGE_BUCKET_NAME),
                    accessKeyId: configService.get(CONFIG_KEYS.AWS_S3.ACCESS_KEY),
                    secretAccessKey: configService.get(CONFIG_KEYS.AWS_S3.SECRET_ACCESS_KEY),
                },
            },
            // Set filename as uuidv4 + extension
            uploadPath: (record, filename) => FileUtil.generateFileKey(filename),
            properties: {
                key: 's3Key',
                mimeType: 'mime',
                bucket: 'bucket',
            },
            validation: {
                maxSize: configService.get(CONFIG_KEYS.IMAGE.MAX_IMAGE_SIZE_MB) * 1024 * 1024,
                mimeTypes: ['image/jpeg', 'image/png', 'image/gif', 'image/webp'],
            },
        }),
    ],

SLIGHT EDIT: The above code for the upload functionality will not work. The interface for the AWS provider has been changed. You'll need to set it up like this:

provider: {
    aws: {
        region: configService.get(CONFIG_KEYS.AWS_S3.REGION),
            bucket: configService.get(CONFIG_KEYS.AWS_S3.IMAGE_BUCKET_NAME),
            credentials: {
            accessKeyId: configService.get(CONFIG_KEYS.AWS_S3.ACCESS_KEY),
                secretAccessKey: configService.get(CONFIG_KEYS.AWS_S3.SECRET_ACCESS_KEY)
        }
    },
}

Upvotes: 4

Related Questions