Compiling code from another workspace project in a nestjs api - Unexpected token 'export'
Asked Answered
D

3

8

I'm trying to create a monorepo containing a NestJs API, a React app, and many other smaller projects shared between them

The monorepo is set up with yarn workspaces

The React app using Vite imports and compiles the common projects flawlessly, but the NestJs api never compiles, usually giving the SyntaxError: Unexpected token 'export' error.

I made a minimal repository with just a basic Nest project and a common folder to try to get a single function import working with the following structure :

.
├── common                  # Sample common project
│   ├── tsconfig         
│   ├── src        
│   │   └── test.ts         # The file called from the api
│   └── package.json   
├── api                     # NestJs API
│   ├── tsconfig      
│   ├── src        
│   └── package.json             
└── package.json            # Yarn workspace setup

The main package.json:

{
    "name": "mono",
    "workspaces": [
        "common",
        "api"
    ]
}

The common package.json

{
    "name": "@test/common",
    "version": "1.0.0",
    "main": "index.ts"
}

The common tsconfig

{
  "compilerOptions": {
    "module": "CommonJS",
    "allowSyntheticDefaultImports": true,
    "baseUrl": ".",
    "esModuleInterop": true,
    "composite": true,
    "sourceMap": true,
    "declaration": true,
    "declarationMap": true
  }
}

And its complicated test function in src/test.ts

export const hi = () => 'Hello there';

And here's the main.ts file from which I call this function :

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { hi } from '@test/common';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);

  console.log('All fine', hi());
}
bootstrap();

The api package.json

{
  "name": "api",
  "scripts": {
    "start": "nest start",
    ...other commands
  },
  "dependencies": {
    "@nestjs/common": "^9.0.0",
    "@nestjs/core": "^9.0.0",
    "@nestjs/platform-express": "^9.0.0",
    "@test/common": "*",
    "reflect-metadata": "^0.1.13",
    "rxjs": "^7.2.0",
    "webpack-node-externals": "^3.0.0"
  },
  "devDependencies": {
    ...nest deps
    "ts-jest": "29.0.3",
    "ts-loader": "^9.2.3",
    "ts-node": "^10.0.0",
    "tsconfig-paths": "4.1.1",
    "typescript": "^4.7.4"
  },
  "jest": {
    ...jest config
  }
}

And api's tsconfig

{
  "compilerOptions": {
    "module": "CommonJS",
    "declaration": true,
    "removeComments": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "allowSyntheticDefaultImports": true,
    "target": "es2017",
    "sourceMap": true,
    "outDir": "./dist",
    "baseUrl": "./",
    "incremental": true,
    "skipLibCheck": true,
    "strictNullChecks": false,
    "noImplicitAny": false,
    "strictBindCallApply": false,
    "forceConsistentCasingInFileNames": false,
  },
  "include": [
    "../common",
    "./src/*"
  ],
  "references": [
    {
      "path": "../common"
    }
  ],
  "paths": {
    "@test/common/*": [
      "../common/*"
    ]
  }
}

When running yarn run start on the nest project, the produced dist folder seems to contain the correct file structure:

dist structure

But leads to the same error again and again

C:\<path>\MonoNest\api>yarn run start
yarn run v1.22.19
$ nest start
C:\<path>\MonoNest\common\index.ts:1
export * from './src/test';
^^^^^^

SyntaxError: Unexpected token 'export'
    at Object.compileFunction (node:vm:360:18)
    at wrapSafe (node:internal/modules/cjs/loader:1088:15)
    at Module._compile (node:internal/modules/cjs/loader:1123:27)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1213:10)
    at Module.load (node:internal/modules/cjs/loader:1037:32)
    at Function.Module._load (node:internal/modules/cjs/loader:878:12)
    at Module.require (node:internal/modules/cjs/loader:1061:19)
    at require (node:internal/modules/cjs/helpers:103:18)
    at Object.<anonymous> (C:\<path>\MonoNest\api\src\main.ts:3:1)
    at Module._compile (node:internal/modules/cjs/loader:1159:14)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

The minimal reproduction project is available on Github if you want to test it out

To make things clear, i'm trying to make a "real" monorepo, where the parent folder only contains paths the the different projects.

I'm not interested in the 'official' nestjs monorepo doc which makes the root repository include most nestjs packages and config that I do not want within my other projects

Diacritic answered 6/1, 2023 at 18:6 Comment(2)
I point out in prev answer that the error is thrown because, after compilation, the package.json of test modules refers to index.ts file, which is not parseable by javascript, and you have mentioned this is related to the yarn workspace. After I had some investigations I found the correct structure. So you don't need to worry about the nest, and for the test workspace, as API depends on it(according to the tsconfig.json), You need to change the main key of package.json to point to a js file. So kindly change index.ts to dist/index in common's package.json and let's see what happens.Demount
@MostafaFakhraei answer works for me. And it makes a lot of sense: check your build/dist folder. Isn't it outputting a .js file? So in your package.json you can't have a "main": "index.ts" with a hardcode .ts - just change it to "main": "index"Appropriate
B
1

What I have tried is,

while sharing code from a package (core) under packages, I at first transpiled it with tsup and served the index.js file and d.ts files.

My package.json for core package:

{
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "scripts": {
    "dev": "tsup src/index.ts --dts --watch",
    "build": "tsup src/index.ts --dts --minify"
  },
  "dependencies": {
    "typescript": "^5.1.6"
  },
  "devDependencies": {
    "tsup": "^7.1.0"
  }
}

I'm using turborepo

As it is under the workspace [packages/], when I run yarn dev it runs turbo run dev and as the dev command matches the dev command and runs the dev command of core package.

Here is the file structure:

- apps
   |-- server-monolith
   |   |-- nest-cli.json
   |   |-- package.json
   |   |-- src
   |   |   |-- app.module.ts
   |   |   |-- main.ts
   |   |-- tsconfig.build.json
   |   |-- tsconfig.json
   |-- web-next
   |   |-- app
   |   |   |-- layout.tsx
   |   |   |-- page.tsx
   |   |-- next.config.js
   |   |-- package.json
   |   |-- tsconfig.json
- packages
   |-- core
   |   |-- dist
   |   |   |-- index.cjs
   |   |   |-- index.d.ts
   |   |   |-- index.js
   |   |-- package.json
   |   |-- src
   |   |   |-- index.ts
   |   |-- tsconfig.json
   |-- ui
   |   |-- Button.tsx
   |   |-- index.tsx
   |   |-- package.json
   |   |-- tsconfig.json
- package.json
- turbo.json

It works, but the main problem is I want to jump back to the exact implementation from my apps when I click the reference. It redirects me to the index.d.ts file as I have said explicitly in the package.json file of core package.

Link to the reference:

https://github.com/adiathasan/nest-reactor

Blodget answered 2/7, 2023 at 14:39 Comment(0)
B
1

At last, I found something. In my case what I did:

  • rm -rf node_modules/ for each packages & apps

  • upgrade to the latest nest.js. For me, it is ^10.0.5

  • cd <root>/

  • yarn / installs all the deps

  • remove the package eg. core from the package.json of the imported app/package

    eg. root/apps/server-monolith/package.json

       {
         "core": "*"
       }
    

    ^ remove it

  • Direct import from the package/app

    eg. import { add } from ../../packages/core

  • or make a path alias in the tsconfig.json -> compilerOptions of app/package

    eg. "@core": ["../../packages/core/src"]

    enter image description here

  • now run yarn dev to view.

  • make sure you put the correct sourceRoot in the nest-cli.json

    eg. "sourceRoot": "apps/server-monolith/src",

It worked for me but don't know if it works for you as well.

Play with it!

https://github.com/adiathasan/nest-reactor

Blodget answered 3/7, 2023 at 20:55 Comment(0)
G
0

It is because you are trying to use a Pure ESM package within a project that is not Pure ESM. Sometimes there are workarounds such as using module name mappers (in Jest). Other times...there is not. You could attempt to make your package Pure ESM and that would work...but I am not familiar enough with that process to be any help with that.

Gerigerianna answered 11/1, 2023 at 15:42 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.