submodule analysis of a huge monorepo with yarn workspaces

Author: marosivancoCreated Jan 9, 2025Updated Jan 30, 2025
Labelsquestion

Summary

We have a huge monorepo with yarn workspaces. The codebase has the following structure:

/app1
   /page1
   /page2
   ...
   tsconfig.json
   webpack.config.js
/app2
   /page1
   /page2
   ...
   tsconfig.json
   webpack.config.js
...
/packages
   /i18n
   /ui
...

/package.json defines yarn workspaces:

"workspaces": [
        "app1",
        "app2",
        ...
        "packages/*"
    ]

Each app (1...N) has its own webpack/esling/ts configuration. Each app can use different version of babel, typescript... Each app imports modules using paths:

  • relative to module, e.g. import '../dir1/dir2/module'
  • relative to app, e.g. import '@/dir1/dir2/module'
  • relative to package, e.g. import '@base/i18n/module'

webpack.config.js and tsconfig.json properly set the aliases:

webpack.config.js

   resolve: {
        alias: {
            classnames: 'clsx',
            'lodash-es': 'lodash',
            '@': path.resolve('src'),
        },
    },

tsconfig.json

       "paths": {
            "@/*": ["src/*"],
            "@base/i18n": ["../packages/i18n/src/index.ts"],
            "@base/ui/*": ["../packages/ui/*"]
        }

Since the repo is huge, I would like to analyze only a submodule pageM of a appN. I initialized cruiser with: depcruise --init in /. Then I am tried variations of depcruise --include-only "pageM" --output-type dot appN/src | dot -T svg > dependencygraph.svg but cannot get sensible results. Module in a packages is resolved in SVG sometimes as ../packages/ui/src/module sometimes as @base/ui/src/module, that is as two modules instead of one. Modules with app root alias @/page1/module are resolved as different from page1/module - seams as if @ alias is not handled properly.

depcruise --info reported that neither babel nor typescript is used. So I installed them in the /. I tweaked the exclude and doNotFollow options to make the SVG more readable. I ended up with: depcruise --output-type dot appN/src/pageM | dot -T svg > dependencygraph.svg

Aside the aforementioned path resolving issues, I get tons of not-to-unresolvable edges in SVG. I have also noticed, that if moduleA imports symbol S from moduleB, the resulting SVG includes not just symbol S but all the other symbols of moduleB and their transitive dependencies. Webpack implements tree-shaking to get rid of unused symbols and dependencies. Maybe the depcruiser could implement something similar.

The configuration is quite complex so maybe I am missing a setting or a combination.

To sum things up:

  1. module is included multiple times - path aliases are not resolved properly. Could you please confirm that this is an error?
  2. resulting graph has many not-to-unresolvable edges. I have no idea why. Any suggestions?
  3. resulting graph should contain only the modules, that are really used. Is there a setting or a combination? Any idea how to achieve that?

I am not sure if I am hitting bug, feature, feature request or maybe I just need to use a combination of settings. Any response, that will move me forward is appreciated.

Context

I am trying to get helicopter view of the react component subset in a huge repository.

Source: sverweij/dependency-cruiser