NestJs mongoose pre hooks not triggering - node.js

pre('save') and pre('remove') Hooks not triggering in nestjs.
I just started with nestjs. I've encountered an issue in which pre hooks are not working.
I followed official nestjs documentation for mongoose. but nothing works in my case
I want to update the product when review is created, deleted, and updated.
I want to inject productServiceinto hooks.
Below are the relevant snippets.
package.json
{
"name": "server",
"version": "0.0.1",
"description": "",
"author": "",
"private": true,
"license": "UNLICENSED",
"scripts": {
"prebuild": "rimraf dist",
"build": "nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json"
},
"dependencies": {
"#nestjs/common": "^7.5.1",
"#nestjs/config": "^0.6.1",
"#nestjs/core": "^7.5.1",
"#nestjs/graphql": "^7.9.4",
"#nestjs/jwt": "^7.2.0",
"#nestjs/mongoose": "^7.2.4",
"#nestjs/passport": "^7.1.5",
"#nestjs/platform-express": "^7.5.1",
"#nestjs/serve-static": "^2.1.4",
"#types/bcrypt": "^3.0.0",
"apollo-server-express": "^2.19.1",
"bcrypt": "^5.0.0",
"class-transformer": "^0.3.2",
"class-validator": "^0.13.1",
"cloudinary": "^1.23.0",
"cookie-parser": "^1.4.5",
"graphql": "^15.4.0",
"graphql-tools": "^7.0.2",
"graphql-upload": "^11.0.0",
"mongoose": "^5.11.19",
"passport": "^0.4.1",
"passport-jwt": "^4.0.0",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2",
"rxjs": "^6.6.3",
"slugify": "^1.4.6",
"stripe": "^8.132.0"
},
"devDependencies": {
"#nestjs/cli": "^7.5.1",
"#nestjs/schematics": "^7.1.3",
"#nestjs/testing": "^7.5.1",
"#types/cookie-parser": "^1.4.2",
"#types/express": "^4.17.8",
"#types/jest": "^26.0.15",
"#types/node": "^14.14.6",
"#types/passport-jwt": "^3.0.3",
"#types/supertest": "^2.0.10",
"#typescript-eslint/eslint-plugin": "^4.6.1",
"#typescript-eslint/parser": "^4.6.1",
"eslint": "^7.12.1",
"eslint-config-prettier": "7.0.0",
"eslint-plugin-prettier": "^3.1.4",
"jest": "^26.6.3",
"prettier": "^2.1.2",
"supertest": "^6.0.0",
"ts-jest": "^26.4.3",
"ts-loader": "^8.0.8",
"ts-node": "^9.0.0",
"tsconfig-paths": "^3.9.0",
"typescript": "^4.2.3"
},
"jest": {
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"rootDir": "src",
"testRegex": ".*\\.spec\\.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"collectCoverageFrom": [
"**/*.(t|j)s"
],
"coverageDirectory": "../coverage",
"testEnvironment": "node"
}
}
Review Module
#Module({
imports: [
forwardRef(() => ProductModule),
MongooseModule.forFeatureAsync([{
name: Review.name,
useFactory: (
) => {
const schema = ReviewSchema
schema.pre<ReviewDoc>('save', function (next) {
console.log("INSIDE SAVE")
next()
})
schema.pre<ReviewDoc>('remove', function (next) {
console.log("INSIDE REMOVE")
next()
})
return schema
}
}]),
MongooseModule.forFeature([{ name: Product.name, schema: ProductSchema }]),
MongooseModule.forFeature([{ name: Member.name, schema: MemberSchema }]),
MongooseModule.forFeature([{ name: Review.name, schema: ReviewSchema }])
],
providers: [ReviewService, ReviewResolver],
exports: [ReviewService]
})
export class ReviewModule { }
Review Entity
import { SchemaFactory, Schema, Prop } from "#nestjs/mongoose";
import * as mongoose from 'mongoose'
import { Member } from "../member/member.entity";
import { IReviewMember } from "./review.type";
export type ReviewDoc = Review & mongoose.Document
#Schema({ _id: false })
class ReviewMember {
#Prop({ type: mongoose.Schema.Types.ObjectId, ref: Member.name, required: true })
id: string;
#Prop({ required: true })
firstName: string;
#Prop({ required: true })
lastName: string;
#Prop({ type: String })
avatar?: string;
}
export const ReviewMemberSchema = SchemaFactory.createForClass(ReviewMember)
#Schema({
timestamps: true,
toJSON: {
transform: (doc, ret) => {
ret.id = doc._id;
delete ret._id
delete ret.__v
}
}
})
export class Review {
#Prop({ type: ReviewMemberSchema, required: true })
member: IReviewMember;
#Prop({ type: mongoose.Schema.Types.ObjectId, ref: 'products', required: true })
productId: string;
#Prop()
productSlug: string;
#Prop()
comment: string;
#Prop({
set: function (rating: number) {
this._prevRating = this.rating;
return rating;
}
})
rating: number;
}
const ReviewSchema = SchemaFactory.createForClass(Review)
export { ReviewSchema }
Review Service
async createReview({ comment, member: user, productId, rating }: ICreateReview) {
const member = await this.members.findById(user.id)
if (!member) {
throw new NotFoundException(`no member found with member id "${productId}"`)
}
const product = await this.products.findById(productId)
if (!product) {
throw new NotFoundException(`no product found with product id "${productId}"`)
}
const review = await this.reviews.findOne({ "member.id": member.id, productId: product._id })
if (review) {
throw new ConflictException(`review already exist`)
}
// should trigger pre save but not working
const newReview = await this.reviews.create(
{
productId: product._id,
productSlug: product.slug,
member: {
firstName: member.firstName,
lastName: member.lastName,
avatar: member.avatar,
id: member._id
},
rating,
comment,
}
)
if (product.numOfReviews < 3) {
const { comment, member, rating, _id } = newReview
product.reviews.push({ comment, member, rating, id: _id })
await product.save()
}
return newReview;
}```

Related

wrtc can't create offer in nestjs

Newbie is Here!
I am developing media server for sfu.
I want to make sfu media server, so i think it needs RTCPeerconnection like client side.
myProblem is that 'wrtc.RTCPeerConnection.createOffer()' is not work in nestjs
I want to use webrtc api in nestjs like
import * as webrtc from 'wrtc'
const Peer = new webrtc.RTCPeerConnection();
Peer.createOffer();
I want to use methods (createOffer, createAnswer ...etc) and events (onicecandidate, ontrack ...etc)
but it is not working.
It is result of wrtc.RTCPeerConnection().createOffer() in my project
It make "offer" of empty object like this
Promise { <pending> }
in console.log()
there is my code of nestjs
sfu.service.ts
import { Injectable } from '#nestjs/common';
import { Server, Socket } from 'socket.io';
import * as DefaultRTCPeerConnection from 'wrtc';
const {
RTCPeerConnection,
} = DefaultRTCPeerConnection;
#Injectable()
export class SfuService {
private peers: Map<string, RTCPeerConnection>;
private id: string;
constructor() {
this.peers = new Map();
}
getter() {
return this.peers.get(this.id);
}
async createPeerConnection(connectionId) {
const peerConnection = new RTCPeerConnection();
this.peers.set(connectionId, peerConnection);
this.id = connectionId;
// peerConnection.ontrack = (stream) => this.onTrackHandler(stream);
return peerConnection;
}
async createOffer(id, option) {
try {
// Todo option setting
const offer = await this.peers.get(id).createOffer(option);
return offer;
} catch (e) {
console.log(e);
}
}
async createAnswer(id, option) {
try {
// Todo option setting
const answer = await this.peers.get(id).createAnswer(option);
return answer;
} catch (e) {
console.log(e);
}
}
async setLocalDescription(description) {
try {
await this.peers.get(this.id).setLocalDescription(description);
} catch (e) {
console.log(e);
}
}
async setRemoteDescription(description) {
try {
await this.peers.get(this.id).setRemoteDescription(description);
} catch (e) {
console.log(e);
}
}
}
and then my gateway code
sfu.gateway.ts
import { UsePipes, ValidationPipe } from '#nestjs/common';
import {
SubscribeMessage,
WebSocketGateway,
OnGatewayInit,
OnGatewayConnection,
OnGatewayDisconnect,
} from '#nestjs/websockets';
import { Server, Socket } from 'socket.io';
import { OfferDto } from 'src/wss/dto';
import { offerValidationPipe } from 'src/wss/pipes';
import { SfuService } from './sfu.service';
import * as DefaultRTCPeerConnection from 'wrtc';
const { RTCPeerConnection } = DefaultRTCPeerConnection;
#WebSocketGateway({
namespace: 'sfu',
cors: {
origin: [
'http://localhost:4000',
'http://localhost:3300',
'http://localhost:5000',
'http://localhost:3000',
],
},
})
export class SfuGateway
implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect
{
constructor(private service: SfuService) {}
server: Server;
afterInit(_server: Server) {
this.server = _server;
}
handleConnection(socket: Socket, ...args: any[]) {
console.log(socket.id, 'Connected!');
this.service.Test();
}
handleDisconnect(socket: Socket) {
console.log(socket.id, 'DisConnected!');
}
#UsePipes(new ValidationPipe())
#SubscribeMessage('join_room')
async JoinRoom(socket: Socket, roomName: string) {
socket.join(roomName);
socket.emit('welcome', socket.id);
return {};
}
#UsePipes(new offerValidationPipe())
#SubscribeMessage('offer')
async Offer(socket: Socket, data: OfferDto) {
this.service.createPeerConnection(socket.id);
const connection = this.service.getter();
connection.onicecandidate = (e) => {
socket.emit('ice', e.candidate, socket.id);
};
const t = new RTCPeerConnection();
t.setRemoteDescription(data.offer);
console.log('offer Set!', data.offer);
await this.service.setRemoteDescription(data.offer);
console.log('Offer Set Complete\n');
const temp = await this.service.createAnswer(socket.id, {
offerToReceiveAudio: false,
offerToReceiveVideo: false,
});
console.log('Answer ppppppppppp : ', temp);
this.service.setLocalDescription(temp);
const offer = this.service.createOffer(socket.id, {
offerToReceiveAudio: false,
offerToReceiveVideo: false,
});
console.log(offer);
socket.emit('test', offer);
socket.to(data.roomName).emit('offer', data.offer, socket.id);
}
}
my package.json
{
"name": "socketserver",
"version": "0.0.1",
"description": "",
"author": "",
"private": true,
"license": "UNLICENSED",
"scripts": {
"prebuild": "rimraf dist",
"build": "nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json"
},
"dependencies": {
"#nestjs/common": "^8.0.0",
"#nestjs/core": "^8.0.0",
"#nestjs/platform-express": "^8.0.0",
"#nestjs/platform-socket.io": "^9.0.3",
"#nestjs/websockets": "^9.0.3",
"class-transformer": "^0.5.1",
"class-validator": "^0.13.2",
"nestjs-socket-handlers-with-ack": "^2.0.0",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2",
"rxjs": "^7.5.6",
"rxjs-compat": "^6.6.7",
"socket.io-redis": "^6.1.1",
"wrtc": "^0.4.7"
},
"devDependencies": {
"#nestjs/cli": "^8.0.0",
"#nestjs/schematics": "^8.0.0",
"#nestjs/testing": "^8.0.0",
"#types/express": "^4.17.13",
"#types/jest": "27.5.0",
"#types/node": "^16.0.0",
"#types/socket.io": "^3.0.2",
"#types/supertest": "^2.0.11",
"#types/ws": "^8.5.3",
"#typescript-eslint/eslint-plugin": "^5.0.0",
"#typescript-eslint/parser": "^5.0.0",
"eslint": "^8.0.1",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0",
"jest": "28.0.3",
"prettier": "^2.3.2",
"source-map-support": "^0.5.20",
"supertest": "^6.1.3",
"ts-jest": "28.0.1",
"ts-loader": "^9.2.3",
"ts-node": "^10.0.0",
"tsconfig-paths": "4.0.0",
"typescript": "^4.3.5"
},
"jest": {
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"rootDir": "src",
"testRegex": ".*\\.spec\\.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"collectCoverageFrom": [
"**/*.(t|j)s"
],
"coverageDirectory": "../coverage",
"testEnvironment": "node"
}
}
Please Help me!!

Webpack issue when update 4.x to 5.x

I have a problem when i updated in my project the webpack package to V5.x.
Here is the error :
webpack-hot-client: entry Object values must be an Array or Function. Please check your webpack config.
Here is my package.json :
"*.css",
"*.scss",
"*.sass" ], "main": "index.js", "scripts": {
"analyze": "bnr clean:build && bnr analyze",
"build:all": "bnr clean:build && bnr build:client && bnr build:server",
"build:client": "bnr clean:build && bnr build:client",
"build:server": "bnr clean:build && bnr build:server",
"clean": "bnr clean:build",
"dev": "bnr dev",
"docker": "yarn docker:build && yarn docker:start && yarn docker:status",
"docker:build": "docker-compose build --no-cache",
"docker:start": "docker-compose up -d",
"docker:status": "docker-compose logs -f -t",
"flow": "bnr flow",
"flow:stop": "bnr flow:stop",
"lint": "npm-run-all lint:js lint:style lint:json",
"lint:js": "bnr lint:js",
"lint:style": "bnr lint:style",
"lint:json": "bnr lint:json",
"prod": "bnr build:client && bnr build:server && bnr start",
"start": "bnr start",
"sitemap": "node sitemap-generator.js" }, "betterScripts": {
"analyze": {
"command": "npx webpack -p --progress --hide-modules --config ./tools/webpack/production.client.babel.js",
"env": {
"NODE_ENV": "analyze"
}
},
"build:client": {
"command": "npx webpack --hide-modules --config ./tools/webpack/production.client.babel.js && npx gulp --gulpfile
tools/gulpfile.js",
"env": {
"NODE_ENV": "production"
}
},
"build:server": {
"command": "npx babel ./src -d ./dist --copy-files && npx webpack --hide-modules --config
./tools/webpack/production.server.babel.js",
"env": {
"NODE_ENV": "production"
}
},
"clean:build": {
"command": "rimraf ./public/assets && rimraf ./public/webpack-assets.json"
},
"dev": {
"command": "nodemon ./index.js",
"env": {
"NODE_PATH": "./src",
"NODE_ENV": "development",
"PORT": 3000
}
},
"flow": {
"command": "npx flow"
},
"flow:stop": {
"command": "npx flow stop"
},
"lint:js": {
"command": "npx eslint --fix ./src ./tools ./index.js"
},
"lint:json": {
"command": "npx prettier --write src/**/**/*.json"
},
"lint:style": {
"command": "npx stylelint --fix ./src/**/*.css, ./src/**/*.scss"
},
"start": {
"command": "node ./index.js",
"env": {
"NODE_PATH": "./dist",
"NODE_HOST": "0.0.0.0",
"NODE_ENV": "production",
"PORT": 8080
}
} }, "husky": {
"hooks": {
"pre-commit": "lint-staged"
} }, "lint-staged": {
"*.{js,jsx}": "eslint --fix",
"*.{json,md}": "prettier --write",
"*.{scss,sass}": "stylelint --syntax=scss" }, "nodemonConfig": {
"watch": [
"src/server.js",
"src/handler.js",
"src/utils/renderHtml.js",
"src/theme/variables.scss"
] }, "browserslist": [
"> 1%",
"last 3 versions" ], "eslintIgnore": [
"tools/flow",
"public/assets" ], "dependencies": {
"#babel/cli": "^7.14.5",
"#babel/plugin-proposal-export-namespace-from": "^7.5.2",
"#fortawesome/fontawesome-free": "^5.15.1",
"#hapi/address": "^4.1.0",
"#koa/router": "^10.1.1",
"#loadable/component": "^5.10.2",
"#loadable/server": "^5.10.2",
"#tweenjs/tween.js": "^18.3.1",
"ansi-regex": "^6.0.1",
"axios": "^0.23.0",
"bootstrap": "^5.1.3",
"chalk": "^4.1.2",
"classnames": "^2.2.6",
"d3-ease": "^3.0.1",
"del": "^6.0.0",
"esm": "^3.2.25",
"glob-parent": "^6.0.2",
"gulp": "^4.0.2",
"gulp-cache": "^1.1.3",
"gulp-imagemin": "^8.0.0",
"gulp-postcss": "^9.0.0",
"gulp-rename": "^2.0.0",
"i18next": "^21.3.2",
"i18next-browser-languagedetector": "^6.1.2",
"i18next-node-fs-backend": "^2.1.3",
"i18next-resource-store-loader": "^0.1.2",
"i18next-xhr-backend": "^3.1.2",
"imagemin-mozjpeg": "^9.0.0",
"imagemin-pngquant": "^9.0.2",
"koa": "^2.8.1",
"koa-bodyparser": "^4.2.1",
"koa-compress": "^5.1.0",
"koa-favicon": "^2.0.1",
"koa-helmet": "^6.1.0",
"koa-i18next-detector": "^0.7.2",
"koa-i18next-middleware": "^1.1.12",
"koa-i18next-middleware-fixed": "^1.1.10-b3",
"koa-morgan": "^1.0.1",
"koa-mount": "^4.0.0",
"koa-router": "^10.1.1",
"koa-static": "^5.0.0",
"koa-webpack": "^6.0.0",
"koa-webpack-server": "^0.2.4",
"micro-dash": "^8.1.0",
"moment": "^2.24.0",
"p-min-delay": "^4.0.1",
"pm2": "^5.1.2",
"qs": "^6.8.0",
"rc-animate": "^3.1.1",
"rc-queue-anim": "^2.0.0",
"rc-scroll-anim": "^2.6.1",
"rc-tween-one": "^2.6.3",
"react": "^17.0.2",
"react-bootstrap": "^1.0.0-beta.8",
"react-dom": "npm:#hot-loader/react-dom#^16.8.6",
"react-global-configuration": "^1.4.1",
"react-gtm-module": "^2.0.11",
"react-helmet": "^6.1.0",
"react-i18next": "^11.12.0",
"react-icons": "^4.3.1",
"react-motion": "^0.5.2",
"react-player": "^2.9.0",
"react-pose": "^4.0.8",
"react-router": "^5.0.1",
"react-router-config": "^5.0.1",
"react-router-dom": "^5.0.1",
"react-router-last-location": "^2.0.1",
"react-router-sitemap": "^1.2.0",
"react-spring": "^9.3.0",
"react-tilt": "^0.1.4",
"react-typist": "^2.0.5",
"react-youtube": "^7.9.0",
"sass-resources-loader": "^2.0.1",
"serialize-javascript": "^6.0.0",
"styled-components": "^5.3.1",
"terser-webpack-plugin": "^5.2.4" }, "devDependencies": {
"#babel/core": "^7.6.0",
"#babel/node": "^7.14.5",
"#babel/plugin-proposal-class-properties": "^7.5.5",
"#babel/plugin-proposal-export-default-from": "^7.5.2",
"#babel/plugin-proposal-optional-chaining": "^7.6.0",
"#babel/plugin-syntax-dynamic-import": "^7.2.0",
"#babel/preset-env": "^7.14.5",
"#babel/preset-flow": "^7.0.0",
"#babel/preset-react": "^7.14.5",
"#babel/register": "^7.6.0",
"#babel/runtime": "^7.6.0",
"#loadable/babel-plugin": "^5.10.0",
"#loadable/webpack-plugin": "^5.7.1",
"asset-require-hook": "^1.2.0",
"babel-eslint": "^10.0.3",
"babel-loader": "^8.0.6",
"babel-plugin-dynamic-import-node": "^2.3.0",
"babel-plugin-istanbul": "^6.1.1",
"babel-plugin-transform-react-remove-prop-types": "^0.4.24",
"babel-plugin-transform-remove-console": "^6.9.4",
"better-npm-run": "^0.1.1",
"compression-webpack-plugin": "^9.0.0",
"core-js": "3",
"css-loader": "^6.4.0",
"css-modules-require-hook": "^4.2.3",
"cssnano": "^5.0.8",
"eslint": "^8.0.1",
"eslint-config-airbnb": "^18.0.1",
"eslint-config-prettier": "^8.3.0",
"eslint-import-resolver-webpack": "^0.13.1",
"eslint-plugin-flowtype": "^6.1.1",
"eslint-plugin-import": "^2.18.2",
"eslint-plugin-jsx-a11y": "^6.2.3",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-react": "^7.14.3",
"eslint-plugin-react-hooks": "^4.2.0",
"file-loader": "^6.2.0",
"flow-bin": "^0.162.0",
"friendly-errors-webpack-plugin": "^1.7.0",
"html-minifier": "^4.0.0",
"husky": "^7.0.2",
"imagemin-webpack-plugin": "^2.4.2",
"lint-staged": "^11.2.3",
"mini-css-extract-plugin": "^2.4.2",
"nodemon": "^2.0.13",
"normalize.css": "^8.0.1",
"npm-run-all": "^4.1.5",
"optimize-css-assets-webpack-plugin": "^6.0.1",
"postcss": "^8.3.9",
"postcss-loader": "^6.2.0",
"postcss-preset-env": "^6.7.0",
"prettier": "^2.4.1",
"react-dev-utils": "^11.0.4",
"react-hot-loader": "^4.12.13",
"react-router-sitemap-generator": "^0.0.8",
"react-test-renderer": "^17.0.2",
"rimraf": "^3.0.0",
"sass": "^1.43.2",
"sass-loader": "^12.2.0",
"static-site-generator-webpack-plugin": "^3.4.2",
"stylelint": "^13.13.1",
"stylelint-config-prettier": "^9.0.3",
"stylelint-config-recommended-scss": "^4.3.0",
"stylelint-config-standard": "^22.0.0",
"stylelint-scss": "^3.10.1",
"url-loader": "^4.1.1",
"webpack": "^5.58.2",
"webpack-bundle-analyzer": "^4.5.0",
"webpack-cli": "4.9.1",
"webpack-dev-middleware": "^5.2.1",
"webpack-hot-middleware": "^2.25.0",
"webpack-manifest-plugin": "^4.0.2",
"webpack-merge": "^5.8.0",
"webpack-node-externals": "^3.0.0" }, "engines": {
"node": ">=8",
"npm": ">=5" } }```
Here is my base.config.js of webpack :
import webpack from 'webpack'
import { WebpackManifestPlugin } from 'webpack-manifest-plugin'
import MiniCssExtractPlugin from 'mini-css-extract-plugin'
import FriendlyErrorsWebpackPlugin from 'friendly-errors-webpack-plugin'
import LoadablePlugin from '#loadable/webpack-plugin'
import config from './config'
const nodeEnv = process.env.NODE_ENV || 'development'
const isDev = nodeEnv === 'development'
const getPlugins = () => {
const plugins = [
new WebpackManifestPlugin({
fileName: path.resolve(process.cwd(), 'public/webpack-assets.json'),
filter: file => file.isInitial
}),
new MiniCssExtractPlugin({
filename: `${config.cssFileName}.css`,
chunkFilename: `${config.cssChunkFileName}.css`,
ignoreOrder: true
}),
// Setup environment variables for client
new webpack.EnvironmentPlugin({ NODE_ENV: JSON.stringify(nodeEnv) }),
// Setup global variables for client
new webpack.DefinePlugin({
__CLIENT__: true,
__SERVER__: false,
__DEV__: isDev
}),
new LoadablePlugin({ filename: '../loadable-stats.json', writeToDisk: true })
]
if (isDev) {
plugins.push(new FriendlyErrorsWebpackPlugin())
}
return plugins
}
// Webpack configuration
module.exports = {
mode: isDev ? 'development' : 'production',
devtool: isDev ? 'eval-source-map' : 'hidden-source-map',
context: path.resolve(process.cwd()),
entry: ['webpack-hot-middleware/client','./src/index.js'],
optimization: {
splitChunks: {
chunks: 'async'
}
},
output: {
path: path.resolve(process.cwd(), 'public/assets'),
publicPath: '/assets/',
filename: `${config.fileName}.js`,
chunkFilename: `${config.chunkFileName}.js`,
pathinfo: isDev
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel',
options: { cacheDirectory: isDev }
},
{
test: /\.css$/,
include: /node_modules/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css',
options: {
importLoaders: 1,
modules: false,
sourceMap: true
}
},
{ loader: 'postcss', options: { sourceMap: true } }
]
},
{
test: /\.(scss|sass)$/,
exclude: path.resolve(__dirname, '..', '..', 'src/theme/'),
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
hmr: isDev,
reloadAll: true
}
},
{
loader: 'css',
options: {
importLoaders: 2,
modules: {
localIdentName: config.cssModulesIdentifier,
context: path.resolve(process.cwd(), 'src')
},
sourceMap: true
}
},
{ loader: 'postcss', options: { sourceMap: true } },
{
loader: 'sass',
options: {
sassOptions: {
outputStyle: 'expanded'
},
sourceMap: true
}
},
{
loader: 'sass-resources',
options: {
resources: path.resolve(process.cwd(), 'src/theme/_include.scss')
}
}
]
},
{
test: /\.(scss|sass)$/,
include: path.resolve(__dirname, '..', '..', 'src/theme/'),
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
hmr: isDev,
reloadAll: true
}
},
{
loader: 'css',
options: {
importLoaders: 2,
modules: false,
sourceMap: true
}
},
{ loader: 'postcss', options: { sourceMap: true } },
{
loader: 'sass',
options: {
sassOptions: {
outputStyle: 'expanded'
},
sourceMap: true
}
}
]
},
{
test: path.resolve(process.cwd(), 'src/locales'),
loader: 'i18next-resource-store-loader'
},
{
test: /\.(woff2?|ttf|eot|svg|otf)$/,
loader: 'url',
options: { limit: 10240, name: config.staticFilesName }
},
{
test: /\.(gif|png|jpe?g|webp)$/,
// Any image below or equal to 10Kb will be converted to base64
loader: 'url',
options: { limit: 10240, name: config.staticFilesName }
},
{
test: /\.(mp3|mp4|ogv)$/,
loader: 'file',
options: { name: config.staticFilesName }
}
]
},
plugins: getPlugins(),
resolveLoader: {
mainFields: ['loader']
},
resolve: {
modules: ['src', 'node_modules'],
descriptionFiles: ['package.json'],
extensions: ['.js', '.jsx', '.json'],
fallback:{
fs: false,
vm: false,
net: false,
tls: false
}
},
cache: isDev,
stats: { children: false }
I tried a lot of things and i fixed a lot of issues but for me the entry is an Array, so i don't know why i got this error.
Here there is my server.js (he launches all the programs) :
import logger from 'koa-morgan'
import Koa from 'koa'
import bodyParser from 'koa-bodyparser'
import compression from 'koa-compress'
import helmet from 'koa-helmet'
import querystring from 'qs'
import Router from '#koa/router'
import favicon from 'koa-favicon'
import axios from 'axios'
import chalk from 'chalk'
import mount from 'koa-mount'
import serve from 'koa-static'
import Backend from 'i18next-node-fs-backend'
import i18n from 'i18next'
import i18nextMiddleware from 'koa-i18next-middleware-fixed'
import LanguageDetector from 'koa-i18next-detector'
import c from './config'
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0
const app = new Koa()
const router = new Router()
const sendMessage = body =>
new Promise((resolve, reject) => {
const config = {
maxRedirects: 0,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
axios
.post(
'https://go.pardot.com/l/138941/2019-07-22/2h6dgb',
querystring.stringify({ ...body, privacy: true }),
config
)
.then(result => {
resolve(result.status === 200)
})
.catch(e => {
reject(new Error(e))
})
})
const lngDetector = new LanguageDetector()
i18n
.use(Backend)
.use(lngDetector)
.init(
{
debug: false,
fallbackLng: 'fr',
saveMissing: false,
react: {
useSuspense: false
},
detection: {
order: ['path', 'navigator']
},
interpolation: {
escapeValue: false,
formatSeparator: ',',
format: (value, format) => {
if (format === 'uppercase') return value.toUpperCase()
return value
}
},
preload: ['fr'],
load: 'languageOnly',
ns: [
'global',
'landing_references',
'landing_expertises',
'home',
'references',
'expertises',
'contact',
'about',
'partners',
'team'
],
defaultNS: 'global',
backend: {
loadPath: `${path.resolve(process.cwd(), 'src')}/locales/{{lng}}/{{ns}}.json`
}
},
async () => {
// Use helmet to secure Express with various HTTP headers
app.use(helmet())
app.use(bodyParser())
// Compress all requests
app.use(compression())
// Use for http request debug (show errors only)
app.use(logger('dev', { skip: ctx => ctx.status < 400 }))
app.use(favicon(path.resolve(process.cwd(), 'public/favicon.ico')))
app.use(i18nextMiddleware.getHandler(i18n, { locals: 'lng' }))
// Docker serve static trough nginx for better performance
if (!__DOCKER__) {
console.log(chalk.magenta('==> 🐌 Serve statics with koa'))
app.use(mount('/locales', serve(path.resolve(process.cwd(), 'src/locales'))))
app.use(serve(path.resolve(process.cwd(), 'public')))
}
if (__DEV__) {
app.use(mount('/images', serve(path.resolve(process.cwd(), 'src/images'))))
/* Run express as webpack dev server */
const webpack = require('webpack')
const webpackConfig = require('../tools/webpack/base.config')
const compiler = webpack(webpackConfig)
const koaWebpack = require('koa-webpack')
new webpack.ProgressPlugin().apply(compiler)
const options = {
compiler,
devMiddleware: {
publicPath: webpackConfig.output.publicPath,
headers: { 'Access-Control-Allow-Origin': '*' },
hot: true,
writeToDisk: false,
quiet: true, // Turn it on for friendly-errors-webpack-plugin
noInfo: true,
stats: 'minimal',
serverSideRender: true
}
}
const middleware = await koaWebpack(options)
app.use(middleware)
}
router
.post('/contact', async ctx => {
try {
await sendMessage(ctx.request.body)
ctx.body = {
message: 'Votre message a bien été envoyé'
}
ctx.status = 200
} catch (e) {
ctx.body = {
message: 'Une erreur est survenue'
}
ctx.status = 500
}
})
.get('/', async ctx => {
ctx.status = 302
return ctx.redirect(`/${ctx.request.language}`)
})
.get('*', async (ctx, next) => {
return require('./render')(ctx, next)
})
app.use(router.routes()).use(router.allowedMethods())
if (c.port) {
app.listen(c.port, c.host, err => {
const url = `http://${c.host}:${c.port}`
if (err) console.error(chalk.red(`\n==> Error happen ${err}`))
console.info(chalk.green(`\n==> 🌎 Listening at ${url}`))
})
} else {
console.error(chalk.red('\n==> Error : No PORT environment variable has been specified'))
}
}
)
UPDATE :
I put some console.log in the compiler file :
for (const key of Object.keys(entry)) {
const value = entry[key];
console.log(entry)
console.log(value)
console.log(Array.isArray(Object.values(value)))
if (!Array.isArray(value)) {
throw new TypeError(
'webpack-hot-client: `entry` Object values must be an Array or Function. Please check your webpack config.'
);
Console.log return this :
main: { import: [ 'webpack-hot-middleware/client', './src/index.js' ] }
}
{ import: [ 'webpack-hot-middleware/client', './src/index.js' ] }
true
So i think that there is a problem with the declaration of variable, because we have to do an Object.values() to get the array.
So idk what can i do to resolve the problem, i will not change the dependencies files...
Thx for your time and your response!
Regards
It might not be the right example to your situation, but they made some internal changes to the webpack structure:
entry: {} allows an empty object now (to allow to use plugins to add entries)
here's one of the newer examples I found:
module.exports = {
entry: {
about: { import: './about.js', filename: 'pages/[name][ext]' },
},
};
Source: Webpack v5 internal changes: Entry
I found the error. WebPack Hot Client is not update for the last version of webpack (5.x). If you use Webpack Hot Client, you have to use version 4 of Webpack.
Regards

Fix for "Nest can't resolve dependencies of the MovieService."

I keep getting this error but don't know why. If anyone could help me solve it, that would make my day 😁
Error: Nest can't resolve dependencies of the MovieService (?). Please make sure that the argument MovieRepository at index [0] is available in the MovieService context.
This is the structure of my MovieService:
import {Injectable} from "#nestjs/common";
import {InjectRepository} from "#nestjs/typeorm";
import {Repository} from "typeorm";
import {CreateMovieDto} from "./dto/create-movie.dto";
import {Movie} from "./movie.entity";
#Injectable()
export class MovieService {
constructor(
#InjectRepository(Movie)
private readonly movieRepository: Repository<Movie>
) {}
create(createMovieDto: CreateMovieDto): Promise<Movie> {
const movie = new Movie();
movie.path = createMovieDto.path;
movie.title = createMovieDto.title;
movie.originalTitle = createMovieDto.originalTitle;
movie.poster = createMovieDto.poster;
movie.descr = createMovieDto.descr;
movie.year = createMovieDto.year;
return this.movieRepository.save(movie);
}
async findAll(): Promise<Movie[]> {
return this.movieRepository.find();
}
findOne(id: string): Promise<Movie> {
return this.movieRepository.findOne(id);
}
findByPath(path: string): Promise<Movie> {
return this.movieRepository.findOne({path});
}
async remove(id: string): Promise<void> {
await this.movieRepository.delete(id);
}
}
The MovieModule :
import {Module} from "#nestjs/common";
import {TypeOrmModule} from "#nestjs/typeorm";
import {Movie} from "./movie.entity";
import {MovieService} from "./movie.service";
#Module({
imports: [TypeOrmModule.forFeature([Movie])],
providers: [MovieService],
exports: [MovieService],
})
export class MovieModule {}
The Movie entity :
import {Column, Entity, PrimaryGeneratedColumn} from "typeorm";
#Entity()
export class Movie {
#PrimaryGeneratedColumn()
id: number;
#Column()
path: string;
#Column()
title: string;
#Column()
originalTitle: string;
#Column()
poster: string;
#Column()
descr: string;
#Column()
year: string;
}
And the app module :
import {Module} from "#nestjs/common";
import {TypeOrmModule} from "#nestjs/typeorm";
import {AppController} from "./app.controller";
import {AppService} from "./app.service";
import {MovieModule} from "./movie/movie.module";
#Module({
imports: [
TypeOrmModule.forRoot({
type: "mysql",
host: "localhost",
port: 3306,
username: "*****",
password: "*****",
database: "*****",
autoLoadEntities: true,
synchronize: true,
}),
MovieModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Edit 1
I tried copy-pasting the movie folder into a new nest project and it works. I'm even more confused on why I get this error
Here's my package.json
{
"name": "marineris",
"version": "0.0.1",
"description": "",
"author": "",
"private": true,
"license": "UNLICENSED",
"scripts": {
"prebuild": "rimraf dist",
"build": "nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json"
},
"dependencies": {
"#nestjs/common": "^8.0.0",
"#nestjs/core": "^8.0.0",
"#nestjs/platform-express": "^8.0.0",
"#nestjs/typeorm": "^8.0.2",
"bcrypt": "^5.0.1",
"cookie-parser": "^1.4.5",
"hbs": "^4.1.2",
"mysql2": "^2.3.2",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2",
"rxjs": "^7.2.0",
"sync-request": "^6.1.0",
"typeorm": "^0.2.38",
"uuidv4": "^6.2.12"
},
"devDependencies": {
"#nestjs/cli": "^8.0.0",
"#nestjs/schematics": "^8.0.0",
"#nestjs/testing": "^8.0.0",
"#types/cookie-parser": "^1.4.2",
"#types/express": "^4.17.13",
"#types/jest": "^27.0.1",
"#types/node": "^16.0.0",
"#types/supertest": "^2.0.11",
"#typescript-eslint/eslint-plugin": "^4.28.2",
"#typescript-eslint/parser": "^4.28.2",
"eslint": "^7.30.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^3.4.0",
"jest": "^27.0.6",
"prettier": "^2.3.2",
"supertest": "^6.1.3",
"ts-jest": "^27.0.3",
"ts-loader": "^9.2.3",
"ts-node": "^10.0.0",
"tsconfig-paths": "^3.10.1",
"typescript": "^4.3.5"
},
"jest": {
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"rootDir": "src",
"testRegex": ".*\\.spec\\.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"collectCoverageFrom": [
"**/*.(t|j)s"
],
"coverageDirectory": "../coverage",
"testEnvironment": "node"
}
}
I solved my problem. I messed up my imports/exports in some of the files of the project and after double-checking them it worked.

After installing NestJS 8.0.1 >> NestJS Error: Nest can't resolve dependencies of the (controller name)

full error:
ERROR [ExceptionHandler] Nest can't resolve dependencies of the CommitteesController (?).
Please make sure that the argument CommitteesService at index [0] is available in the CommitteesModule context.
Potential solutions:
- If CommitteesService is a provider, is it part of the current CommitteesModule?
- If CommitteesService is exported from a separate #Module, is that module imported within CommitteesModule?
#Module({
imports: [ /* the Module containing CommitteesService */ ]
})
at Injector.lookupComponentInParentModules (C:\Sites\AM-API-MDD\node_modules\#nestjs\core\injector\injector.js:193:19)
at async Injector.resolveComponentInstance (C:\Sites\AM-API-MDD\node_modules\#nestjs\core\injector\injector.js:149:33)
This was working with NestJS 7.6, but I upgraded the version to 8.0.1 and started getting this error.
There are several other modules that don't get an error, however, this is the first module in the list. The processor may not get to the other modules after returning this error.
committees.services.ts
import { Injectable } from '#nestjs/common';
import { PrismaService } from '../database';
import { defaultIncludeQuery, PER_PAGE_COUNT } from './constant';
import { Prisma } from '#prisma/client';
#Injectable()
export class CommitteesService {
constructor(private readonly prisma: PrismaService) {}
committees() {
return Promise.all([
this.prisma.committee.findMany({
include: {
PersonCommittee: {
include: {
Person: {
select: {
PKPersonID: true,
LastName: true,
FirstName: true,
MiddleName: true,
PreferredFirstName: true,
DisplayName: true,
EmploymentStatus: true
}
}
}
}
},
where: {
Active: true,
OR: [
{ PersonCommittee: { some: { Person: { EmploymentStatus: 'A' } } } },
{ PersonCommittee: { some: { Person: { EmploymentStatus: 'B' } } } },
{ PersonCommittee: { some: { Person: { EmploymentStatus: 'C' } } } },
],
}
})
])
}
committees.controller.ts
import {
Body,Controller,DefaultValuePipe,Delete,Get,Param,ParseIntPipe,Post,Put,Query,
} from '#nestjs/common';
import { CommitteesService } from './committees.service';
import { RESOURCE_BASE_ROUTE } from '../constant';
import { PER_PAGE_COUNT } from './constant';
import { Prisma } from '#prisma/client';
const Route = RESOURCE_BASE_ROUTE.committees;
#Controller()
export class CommitteesController {
constructor(private readonly committeesService: CommitteesService) {}
#Get(`${Route}`)
all() {
return this.committeesService.committees();
}
#Get(`${Route}/:id`)
byId(#Param('id', ParseIntPipe) id: number) {
if ( id == -1 ) {
return this.committeesService.committees()
}
return this.committeesService.committee({
CommitteeID: id,
});
}
committees.modules.ts
import { Module } from '#nestjs/common';
import { CommitteesController } from './committees.controller';
import { CommitteesService } from './Committees.service';
#Module({
imports: [],
controllers: [CommitteesController],
providers: [CommitteesService],
exports: [ CommitteesService],
})
export class CommitteesModule {}
package.json
{
"name": "am-api-mdd",
"version": "2.0.1",
"description": "",
"author": "",
"private": true,
"license": "UNLICENSED",
"scripts": {
"prebuild": "rimraf dist",
"build": "nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json"
},
"dependencies": {
"#angular/router": "^6.1.10",
"#nestjs/common": "^8.0.10",
"#nestjs/core": "^8.0.6",
"#nestjs/microservices": "^7.6.18",
"#nestjs/platform-express": "^7.6.18",
"node-windows": "^1.0.0-beta.5",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2",
"rxjs": "^6.6.7"
},
"devDependencies": {
"#nestjs/cli": "^8.1.2",
"#nestjs/schematics": "^7.3.1",
"#nestjs/testing": "^7.6.18",
"#prisma/client": "^3.1.1",
"#types/express": "^4.17.13",
"#types/jest": "^26.0.24",
"#types/node": "^14.17.7",
"#types/supertest": "^2.0.11",
"#typescript-eslint/eslint-plugin": "^4.29.0",
"#typescript-eslint/parser": "^4.29.0",
"eslint": "^7.32.0",
"eslint-config-prettier": "7.2.0",
"eslint-plugin-prettier": "^3.4.0",
"jest": "^26.6.3",
"prettier": "^2.3.2",
"prisma": "^3.1.1",
"supertest": "^6.1.4",
"ts-jest": "^26.5.6",
"ts-loader": "^8.3.0",
"ts-node": "^9.0.0",
"tsconfig-paths": "^3.10.1",
"typescript": "^4.3.5"
},
"jest": {
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"rootDir": "src",
"testRegex": ".*\\.spec\\.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"collectCoverageFrom": [
"**/*.(t|j)s"
],
"coverageDirectory": "../coverage",
"testEnvironment": "node"
}
}

Sequelize is not working with #babel/register

I am trying to use import export statements in the sequelize migrations, have tried all the things in the other questions and github issues. Following are the files I am using to make it work.
.sequelizerc
require('#babel/register');
require('#babel/polyfill');
const path = require('path');
module.exports = {
'config': path.resolve('config', 'config.json'),
'models-path': path.resolve('models'),
'seeders-path': path.resolve('seeders'),
'migrations-path': path.resolve('migrations')
}
package.json
{
"name": "sideproject3",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "nodemon --exec babel-node --experimental-specifier-resolution=node ./bin/www.js",
"start": "node --experimental-specifier-resolution=node ./bin/www.js",
"lint": "eslint --ignore-path .gitignore \"**/*.js\"",
"lint-fix": "eslint --ignore-path .gitignore --fix \"**/*.js\""
},
"dependencies": {
"cookie-parser": "~1.4.4",
"debug": "~2.6.9",
"dotenv": "^8.2.0",
"express": "~4.16.1",
"express-jwt": "^6.0.0",
"http-errors": "~1.6.3",
"jade": "~1.11.0",
"jsonwebtoken": "^8.5.1",
"morgan": "~1.9.1",
"mysql2": "^2.2.5",
"sequelize": "^6.6.2"
},
"devDependencies": {
"#babel/cli": "^7.13.16",
"#babel/core": "^7.13.16",
"#babel/node": "^7.13.13",
"#babel/polyfill": "^7.12.1",
"#babel/preset-env": "^7.13.15",
"#babel/register": "^7.13.16",
"eslint": "^7.25.0",
"eslint-config-google": "^0.14.0",
"nodemon": "^2.0.7",
"sequelize-cli": "^6.2.0"
}
}
.babelrc
{
"presets": [
[
"#babel/preset-env"
]
]
}
migration.js
'use strict';
import { TABLE_NAMES, REQUEST_STATUS } from '../constants';
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable('Requests', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER,
},
message: {
type: Sequelize.TEXT,
},
status: {
type: Sequelize.ENUM([Object.values(REQUEST_STATUS)]),
},
requested_time: {
type: Sequelize.DATE,
},
requested_by_id: {
type: Sequelize.INTEGER,
references: {
model: TABLE_NAMES.USERS,
key: 'id',
},
},
requested_to_id: {
type: Sequelize.INTEGER,
references: {
model: TABLE_NAMES.USERS,
key: 'id',
},
},
reject_response: {
type: Sequelize.TEXT,
},
response_time: {
type: Sequelize.DATE,
allowNull: true,
},
type: {
type: Sequelize.STRING,
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
},
});
},
down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable('Requests');
},
};
Solutions by others tell that using #babel/register and using preset-env should have worked, but it is not working and giving the following error
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module:
... require() of ES modules is not supported.

Resources