Home > Net >  Yarn workspaces - monorepo - react 17, react 18, nestjs, shared/common layer
Yarn workspaces - monorepo - react 17, react 18, nestjs, shared/common layer

Time:10-11

I want to have a monorepo using yarn workspaces in which I hold:

  • a react 17 app
  • a react 18 app
  • a nestjs app
  • a shared layer with common functions for all of them (e.g: date format func)

I cloned this project https://github.com/mightyhorst/medium-react-nestjs-monorepo and it manages to share types between them. I had to add typescript and react stuff to nohoist so it doesn't hoist the wrong versions and it works fine - both react apps & nest can use the shared types. The problem comes when I add a function in the common layer.

workspaces/common/src/index.ts

WORKS

export interface User {
  email: string
}

DOESN'T WORK

export interface User {
  email: string
}
export function hello() { console.log('world') }

I get this error when running any react app (although there is nothing wrong with the type):

../common/src/model.ts 4:7
Module parse failed: Unexpected token (4:7)
File was processed with these loaders:
 * ./node_modules/@pmmmwh/react-refresh-webpack-plugin/loader/index.js
You may need an additional loader to handle the result of these loaders.
| $RefreshSetup$(module.id);
| 
> export interface User{
|     email: string;
|     firstName?: string;

I get this error when running nestjs:

export * from "./model";
^^^^^^

SyntaxError: Unexpected token 'export'
    at wrapSafe (internal/modules/cjs/loader.js:984:16)
    at Module._compile (internal/modules/cjs/loader.js:1032:27)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1097:10)
    at Module.load (internal/modules/cjs/loader.js:933:32)
    at Function.Module._load (internal/modules/cjs/loader.js:774:14)
    at Module.require (internal/modules/cjs/loader.js:957:19)
    at require (internal/modules/cjs/helpers.js:88:18)
    at Object.<anonymous> (/home/elbit/Projects/medium-react-nestjs-monorepo/workspaces/nestjs/dist/src/main.js:5:18)
    at Module._compile (internal/modules/cjs/loader.js:1068:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1097:10)

I feel like this is a common thing but I cannot find the solution.

CodePudding user response:

I got it working using:

  • yarn-workspaces without lerna to handle all the packages
  • set "workspaces": { "nohoist": ["**"] } within each package (in package.json)
  • craco to handle common package and aliases (via craco-alias)
  • @ef-carbon/tspm to resolve tsconfig.compilerOptions.paths for any package that isn't React

My craco.config.js

const path = require("path");
const { getLoader, loaderByName } = require("@craco/craco");
const CracoAlias = require("craco-alias");

const packages = [];
packages.push(path.join(__dirname, "../common"));

module.exports = {
  webpack: {
    configure: (webpackConfig, arg) => {
      const { isFound, match } = getLoader(
        webpackConfig,
        loaderByName("babel-loader")
      );
      if (isFound) {
        const include = Array.isArray(match.loader.include)
          ? match.loader.include
          : [match.loader.include];

        match.loader.include = include.concat(packages);
      }

      return webpackConfig;
    },
  },
  plugins: [
    {
      plugin: CracoAlias,
      options: {
        source: "tsconfig",
        baseUrl: ".",
        tsConfigPath: "./tsconfig.paths.json",
      },
    },
  ],
};


My tsconfig.json of a non-react app

{
  "compilerOptions": {
    "allowJs": true,
    "baseUrl": "./",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "isolatedModules": true,
    "module": "commonjs",
    "moduleResolution": "node",
    "outDir": "build",
    "paths": { "@ui/common/*": ["../common/src/*"] },
    "resolveJsonModule": true,
    "rootDirs": [".", "../common/build"],
    "skipLibCheck": true,
    "strict": true,
    "target": "es5"
  },
  "include": ["src", "../common/src"]
}
  • Related