Error: Cannot find module 'max-api' (using Typescript and NestJS)
Hello,
i am trying to combine a Max patch with NestJS. The first basic steps worked so far. Starting the NestJS Application from Max.
Now i created a Max service for interacting with Max. Running standalone creates an expected error:
Error: Cannot find module 'max-api'
But within Max i am getting also an error:
TypeError: Cannot read properties of undefined (reading: post)
import { Injectable, Logger } from "@nestjs/common";
import maxAPI from 'max-api';
@Injectable()
export class MaxService {
private readonly logger = new Logger(MaxService.name);
onApplicationBootstrap() {
this.logger.log('Doing something...');
maxAPI.post(`Running in MAX_ENV: ${process.env.MAX_ENV as string}`);
}
}
Maybe somebody has a hint to me?
And is there some kind of workaround to run the NestJS app standalone without max-api?
Regards and thx
Ralf
Adding esModuleInterop to the tsconfig.json fixed the TypeError within Max:
"esModuleInterop": true
Hi Ralf,
glad you got it working. I think your best bet to get to use your NestJS application standalone and with Max via [node.script]
is to encapsulate the part that uses the max-api
in a module and then determine at runtime whether to dynamically import it or if you'd like to use other functionality.
As already shown in your code you can rely upon MAX_ENV
(more docs on that are available here) to determine if the script has been started from Max or outside of it.
One way to abstract that is to wrap the logic in your MaxService, maybe similar to this:
import { Injectable, Logger } from "@nestjs/common";
@Injectable()
export class MaxService {
private readonly logger = new Logger(MaxService.name);
private readonly isInMax = process.env.MAX_ENV !== undefined;
onApplicationBootstrap() {
this.logger.log('Doing something...');
if (this.isInMax) {
maxAPI.post(`Running in MAX_ENV: ${process.env.MAX_ENV as string}`);
} else {
// Do something different!?
}
}
}
or alternative you can write a module that implements the API of max-api
and at runtime decide whether to load that or the one provided by [node.script]
. The API to implement is available as part of the @types/max-api
package.
Something like the following should work assuming that you provide some sort of mock version of the max-api
in ./max-api.mock.js
const modPath = process.env.MAX_ENV !== undefined ? "max-api" : "./max-api.mock.js";
const maxAPI = await import(modPath);
Does that help?
Hello Florian,
thx alot for your reply and ideas. I guess, i'll try a mock for this - tomorrow.
Regards
Ralf
For now i solved it without mockup:
import { Injectable, Logger } from '@nestjs/common'
import MaxAPIStatic from 'max-api'
@Injectable()
export class MaxService {
private readonly logger = new Logger(MaxService.name)
private readonly isInMax = process.env.MAX_ENV !== undefined
async onApplicationBootstrap() {
if (!this.isInMax) {
this.logger.warn('maxApi missing!')
return
}
const maxAPI = await this.loadMaxModule('max-api')
maxAPI.post(`Running in MAX_ENV: ${process.env.MAX_ENV}`)
maxAPI.addHandler('onTest', (event) => {
this.logger.log('onTest', event)
maxAPI.outlet('result', Math.random())
})
}
async loadMaxModule(modulePath: string): Promise<typeof MaxAPIStatic> {
const module = await import(modulePath)
return module.default as typeof MaxAPIStatic
}
}