I have created a Next.js (TypeScript) application, called "vkdgen". Afterwards, I've created and published a small component library for my project called "vkdFramework4NextJS". This second project I can import in other projects and use it.
Then, I've read about npm workspaces and the possibility to manage all projects in a monorepo structure and by this monorepo approach the possibility to work with multiple somewhat-standalone npm modules, but still being able to use all modules/local code without the need for symlinks or republishing all the time.
So I've set up a monorepo structure like this:
vkd-monorepo
|
|-- apps
| |
| |-- vkdgen
|
|-- packages
|
|-- vkdFramework4NextJS
Note: I have not yet tested to use vkdFramework4NextJS in vkdgen via this monorepo setup. Probably it will not work as well.
Now I wanted to benefit from my new approach and create a own npm logger module. I've called it vkdLogger (vkdLogger is the folder name, for npm conventions the name in package.json is "vkdlogger") and it is on the same level as "vkdFramework4NextJS". And I just can't use it in my project vkdgen. I've tried a lot of different configurations and code/import lines, but it will not work. Can anybody spot the problem in my code or maybe even give general guidelines on monorepo/architectural structure when wanting to use cleanly separated npm modules and not do everything in one bloated up project?
packages/vkdLogger/package.json:{ "name": "vkdlogger", "version": "1.0.0", "type": "module", "description": "", "main": "./dist/index.js", "types": "./dist/index.d.ts", "exports": { ".": { "import": "./dist/index.js", "require": "./dist/index.js", "types": "./dist/index.d.ts", "default": "./dist/index.js" } }, "files": [ "dist" ], "scripts": { "build": "tsc", "dev": "tsc --watch" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "pino": "^10.1.0", "pino-pretty": "^13.1.2" }, "devDependencies": { "@types/node": "^24.9.2", "typescript": "^5.9.3" } }packages/vkdLogger/tsconfig.json:{ "extends": "../../tsconfig.base.json", "compilerOptions": { "outDir": "dist", "rootDir": "src", // Explicit output structure control (in vkdFramework4NextJS it's "baseUrl": "src" in addition to include) "declaration": true, "composite": true, "incremental": true }, "include": ["src"], "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"] }Importing file "apps/vkdgen/src/lib/server/utils/generator/generatorUtils.ts": (Commented out import lines are other ways in which I've tried to import the module)
..... Other imports ...... import { handleFileRegeneration } from "@/model/templateUtils"; //import { vkdLogger } from "vkdlogger"; //import { vkdLogger } from "../../../../../../../packages/vkdLogger/dist/index"; import { vkdLogger } from "../../../../../../../packages/vkdLogger/dist/index.js"; ..... /** * Generates the file contents for frontend views based on the architecture model. * @param am Architecture Model with generation strategy ONE_FOR_EACH * @param frontendViewsWAttributes The list of frontend views to process * @param allObjectModels A list of all object models in the project to find links. * @returns An array of generated files */ function generateFileContent4FrontendViewsOneForEach( am: ArchitectureModel, preprocessedFrontendViews: PreprocessedFrontendView[], allObjectModels: ObjectModelWithAttributes[] ): GeneratedFile[] { const generatedFiles: GeneratedFile[] = []; for (const frontendView of preprocessedFrontendViews) { if(process.env.PARAM_DEBUG) console.log(`🚀 Processing frontend view: ${frontendView.name}`); if(process.env.PARAM_DEBUG) console.log('[generatorUtils.generateFileContent4FrontendViewsOneForEach] - Generating file from architecture model:', am.name, 'for frontend view: ', frontendView.name); vkdLogger.fatal('This is a fatal error message'); // TODO JVK: Remove Logs to given time // Log name, type, stateVar and setStateVar of all formAttributes frontendView.formAttributes.forEach(attr => { vkdLogger.info(`Form Attribute - Name X: ${attr.attribute.name}, Type: ${attr.type}, StateVar: ${attr.stateVar}, SetStateVar: ${attr.setStateVar}`); }); // Log preprocessesTable Details frontendView.tables.forEach(table => { console.log(`Preprocessed Table - Name: ${table.name}, Columns: ${table.columns.map(col => col.attribute.name).join(', ')}`); }); ..... REST OF FUNCTION ......The import is ok, the compiler does not complain. Only when executing code and trying to use my "vkdLogger" module, I get a ModuleNotFound error:
Module not found: Can't resolve '../../../../../../../packages/vkdLogger/dist/index.js'apps/vkdgen/package.json:{ "name": "vkdgen", "version": "0.1.0", "private": true, "type": "module", "scripts": { "dev": "next dev --turbopack", "build": "prisma generate && next build", "start": "next start", "lint": "next lint", "rest-server": "node --loader ts-node/esm src/server/index.ts", "test": "jest", "test:watch": "jest --watch" }, "dependencies": { "vkdlogger": "../../packages/vkdLogger", "@clerk/nextjs": "^6.21.0", "@codemirror/lang-javascript": "^6.2.4", "@hello-pangea/dnd": "^18.0.1", "@octokit/rest": "^22.0.0", "@prisma/client": "^6.17.1", "@radix-ui/react-checkbox": "^1.3.2", "@radix-ui/react-dialog": "^1.1.14", "@radix-ui/react-popover": "^1.1.14", "@radix-ui/react-progress": "^1.1.7", "@radix-ui/react-select": "^2.2.5", "@radix-ui/react-slot": "^1.2.3", "@radix-ui/react-tabs": "^1.1.12", "@radix-ui/react-tooltip": "^1.2.7", "@tailwindcss/cli": "^4.1.8", "@uiw/react-codemirror": "^4.25.2", "axios": "^1.9.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cors": "^2.8.5", "date-fns": "^4.1.0", "diff": "^8.0.2", "ejs": "^3.1.10", "express": "^5.1.0", "handlebars": "^4.7.8", "lodash": "^4.17.21", "lucide-react": "^0.513.0", "next": "15.3.3", "openai": "^5.8.2", "pino": "^10.1.0", "pino-pretty": "^13.1.2", "prettier": "^3.6.2", "react": "^19.0.0", "react-day-picker": "^9.8.1", "react-dom": "^19.0.0", "react-grid-layout": "^1.5.1", "react-hot-toast": "^2.5.2", "react-rnd": "^10.5.2", "tailwind-merge": "^3.3.1" }, "devDependencies": { "@eslint/eslintrc": "^3", "@eslint/js": "^9.29.0", "@swc/jest": "^0.2.39", "@tailwindcss/postcss": "^4.1.8", "@testing-library/dom": "^10.4.1", "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.6.1", "@types/cors": "^2.8.19", "@types/diff": "^8.0.0", "@types/diff3": "^0.0.2", "@types/ejs": "^3.1.5", "@types/express": "^5.0.3", "@types/jest": "^30.0.0", "@types/lodash": "^4.17.17", "@types/node": "^20.19.0", "@types/react": "^19", "@types/react-dom": "^19", "@types/react-grid-layout": "^1.3.5", "@types/uuid": "^11.0.0", "autoprefixer": "^10.4.21", "concurrently": "^9.1.2", "dotenv": "^17.2.1", "eslint": "^9.29.0", "eslint-config-next": "15.3.3", "eslint-plugin-next": "^0.0.0", "eslint-plugin-react": "^7.37.5", "globals": "^16.2.0", "identity-obj-proxy": "^3.0.0", "jest": "^30.0.5", "jest-environment-jsdom": "^30.0.5", "postcss": "^8.5.4", "prisma": "^6.18.0", "supabase": "^2.31.8", "tailwindcss": "^4.1.8", "ts-node": "^10.9.2", "tw-animate-css": "^1.3.4", "typescript": "^5.8.3", "typescript-eslint": "^8.34.1" } }package.jsonof vkd-monorepo{ "private": true, "name": "vkd-monorepo", "workspaces": [ "apps/*", "packages/*" ], "scripts": { "build": "npm run build --workspaces", "clean": "del-cli node_modules \"apps/*/node_modules\" \"packages/*/node_modules\" \"packages/*/dist\"", "dev:vkdgen": "cd apps/vkdgen && npm run dev", "install:vkdgen": "cd apps/vkdgen && npm install --no-workspaces" }, "dependencies": { "del-cli": "^7.0.0" } }
Versions in vkdgen:
- node v 24.11.0
- npm v 11.6.3
- tsc v 5.8.3
Versions in vkd-monorepo:
- node v 24.11.0
- npm v 11.6.3
- tsc v 5.9.3
While writing this I've realized the mismatch of tsc versions between my two projects. But this should be fine, right? Or could it be the source of my problem?
I already got the suggestion to switch to pnpm. But until now I've only used npm and it worked fine. I would rather like to first solve my current problem and afterwards undertake such breaking changes, if necessary.