12

I have 2 CRA projects in a mono-repo - P1 and P2.

root/
  projects/
    p1/
      package.json
      tsconfig.json
      src/
        shared/
          **/*.ts
    p2/
      package.json
      tsconfig.json
      src/
        **/*.ts

P1 contains some shared infrastructure source files, which I want to reuse in P2.

Note: I know about the disadvantages and negative sides of this approach, but...

What I tried:

  1. Include P1 from P2 and import:

    • P1 tsconfig.json modified with

      "include": [..., "root/projects/p1/src/shared/**/*.ts]

    • P2 source file imports .ts files by relative path

    Result:

    You attempted to import <path> which falls outside of the project src/ directory. Relative imports outside of src/ are not supported.
    You can either move it inside src/, or add a symlink to it from project's node_modules/
    
  2. Use yarn workspaces

    This one is easy. Yarn does not allow to have workspaces outside of the project root

    You cannot and must not reference a workspace that is located outside of this filesystem hierarchy.

  3. Typescript 3.0+ projects references:

    • Update p1 tsconfig.json with

    "compilerOptions": { "composite": true }

    • Add reference to P1 tsconfig.json

    references: [ { "path": "{...}/p1/" ]

    • Build P1 with tsc -b to produce declaration files

    • now I need to import it somehow.

      • create tsconfig.paths.json to configure paths section

      • add rootDir tp P1 tsconfig.json to point to root/ folder

      • add paths "@lib/*": ["<relative-path-to-p1>/p1/src/shared/*"]

    Result:

    Cannot find module: '@lib/....'. Make sure this package is installed

    Also I see that VSCode recognizes my configuration properly and import intellisense works properly

  4. Use react-app-rewired

    in my config-overrides.js I added something like

    module.exports = function override(config, env) {
      config.resolve.alias = {
        "@lib": path.resolve(__dirname, '...p1/src/shared/')
      }
    }
    

    This works for all aliases inside the project. But in my case it fails with

    You attempted to import <root>/p1/src/shared... which falls outside of the project src/ directory. Relative imports outside of src/ are not supported.
    You can either move it inside src/, or add a symlink to it from project's node_modules/
    

2 Answers 2

6
  1. Add customize-cra and react-app-rewired packages

  2. Add to referenced tsconfig.json:

{
  "compilerOptions": {
    ...
    "composite": true,
    "declaration": true,
    "declarationMap": true
}
  1. Create tsconfig.paths.json in the base project
{
  "compilerOptions": {
    "baseUrl": "src",
    "paths": {
      "@alias/*": ["..relative/to/base/url/path/*"]
    }
  }
}
  1. In tsconfig.json add such lines:
{
  "extends": "./tsconfig.paths.json",
  "compilerOptions": {
    "baseUrl": "<the same value as in paths file>"
  },
  "references": [
    { "path": "../relative/path/to/referenced/project/tsconfig.json/file" }
  ]
  1. Create config-override.js file in the project root
const { override, removeModuleScopePlugin, getBabelLoader, addWebpackAlias } = require("customize-cra");
const path = require("path");
const fs = require('fs');

const updateAliases = (config) => {
  const aliases = {
    "@alias": ["absolute/path/to/base/url"]
  };

  return addWebpackAlias(aliases)(config);
};

const updateIncludes = (config) => {
  const loader = getBabelLoader(config, false);
  const commonPath = path.normalize(path.join(process.cwd(), "../relative/path/to/referenced/project/tsconfig.json/file")).replace(/\\/g, "\\");
  loader.include = [loader.include, commonPath];
  return config;
};

module.exports = override(
  updateAliases,
  updateIncludes,
  removeModuleScopePlugin()
);

  1. Use react-app-rewired instead of react-scripts in package.json

Note: This is the modified code, so some minor changes may be required.

Sign up to request clarification or add additional context in comments.

2 Comments

It could be really helpful if instead ../all/of/those/random/paths you could use the correct paths of a given structure.
please show me your case, so maybe I'll be able to help with it. it is literally a relative path to the referenced project. actually it builds an absolute path in this code from relative. you can change it as you wish
0

So, I don't know if this is the "right" way or not, but I've done this before by using file watcher (watchman, gulp, etc.) to sync files from Project B into a shared folder in Project A.

When using this approach, make sure to .gitignore the copied files.

Project A
|_ package.json
|_ src
..|_ index.ts
..|_ shared
.....|_ someSharedFile.ts

Project B
|_ gulpfile.js
|_ src
...|_ someSharedFile.ts

https://css-tricks.com/gulp-for-beginners/

--

Another alternative would be to create an NPM package from Project B and install it to Project A.

3 Comments

thank you for this option. I'm trying to keep a single copy of files (including mirroring of files)
"You can either move it inside src/, or add a symlink to it from project's node_modules/" So I never tried adding a symlink, but it might be worth a shot.
I thought about this approach as well. this is my emergency plan. I thought it would be possible to solve this reference with a more straightforward approach e.g. project reference, workspace, etc.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.