How to create a mono-repo project structure with angular-cli (6.x)
Asked Answered
B

5

3

I'd like to use the angular-cli to generate a new workspace

The only way to do this at the moment is to run:

ng new asdf
cd asdf
ng g application whatever

but then all of the src/ files remain (and the original angular.json info for a project that is now inconsistently stored). There's no way to create a new repo without the src folder... and when I do this using a custom schematic by essentially duplicating angular-cli's ng-new and removing https://github.com/angular/angular-cli/blob/6449a753641340d8fc19a752e1a1ced75f974efa/packages/schematics/angular/ng-new/index.ts#L61 schematic('application', applicationOptions),

Whenever I run it...

$ ng new asdf -c=my-schematic
$ cd asdf
$ ng g application whatever
    {"inlineStyle":false,"inlineTemplate":false,"routing":false,"prefix":"app","style":"css","skipTests":false,"skipPackageJson":false,"name":"whatever"}
CREATE projects/whatever-e2e/protractor.conf.js (752 bytes)
CREATE projects/whatever-e2e/src/app.e2e-spec.ts (304 bytes)
CREATE projects/whatever-e2e/src/app.po.ts (208 bytes)
CREATE projects/whatever-e2e/tsconfig.e2e.json (219 bytes)

Only the e2e files get put into projects/ and the angular.json file remains mostly empty:

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {},
  "cli": {
    "defaultCollection": "my-schematic"
  }
}

I suspect this has to do with something silently failing in the application schematic or a path being off... but I wanted to check first if there was an easier / more preferred way.

$ ng --version                                                 

Angular CLI: 6.1.0-rc.0                                        
Node: 10.1.0                                                   
OS: win32 x64                                                  
Angular: 6.0.7                                                 
... animations, common, compiler, compiler-cli, core, forms    
... http, language-service, platform-browser                   
... platform-browser-dynamic, router                           

Package                      Version                           
------------------------------------------------------         
@angular-devkit/architect    0.7.0-rc.0                        
@angular-devkit/core         0.6.8                             
@angular-devkit/schematics   0.6.8                             
@angular/cdk                 6.3.1                             
@angular/cli                 6.1.0-rc.0                        
@angular/material            6.3.1                             
@schematics/angular          0.6.8                             
@schematics/update           0.7.0-rc.0                        
rxjs                         6.2.1                             
typescript                   2.7.2     

Editing to note I'm familiar about 3rd-party libraries (e.g. Nrwl/Nx) but I'm trying to avoid those. I also posted this issue to GitHub: https://github.com/angular/angular-cli/issues/11402

Bleeder answered 28/6, 2018 at 20:12 Comment(10)
I see you say, "but then all of the src/ files remain (and the original angular.json info for a project that is now inconsistently stored). There's no way to create a new repo without the src folder." You have a top level workspace, with a bunch of sub applications. The top level workspace can be committed, and each app committed as a sub module (in git for instance). Each has it's own dev flow, etc. The top level can be used as the composition mechanism for your sub modules (again, each and all having different flows), all in one parent repo. That won't do?Alejandrinaalejandro
I'm trying to do this all with the angular-cli. If I use ng new asdf and then add a few (say 5) "applications" to it (using ng g app)... you'd have one app inside asdf/src/ and 5 apps inside asdf/projects/ all sharing one package.json / angular.json files. Even the e2e tests are in different spots (one in asdf/e2e/ and 5 in asdf/projects/). That's the inconsistency I'm trying to fix. I'd rather ng new have a --blank option (or something) and then just be able to have everything in projects/ without having to manually move stuff.Bleeder
Hmm...I'm not sure I see that as an inconsistency insofar as a mono repo, each module having it's own e2e tests etc. would seem to be consistent with the idea, etc. The one thing that I struggle a bit with is the package.json thing. Say I want to use ngrx in one of the sub apps. I have to do the install etc. in the top-level package.json. Since I can not specify different package.jsons for each app, what ng g application ultimately seems like, is a glorified feature module. Sure I can create different "stage" sub-apps as specific compositors, but the flow starts to get vague there.Alejandrinaalejandro
It's inconsistent from an organization / folder structure perspective. Personally I don't use git submodules (don't see the point) so there isn't a need for separate package.json files (especially with tree-shaking, etc). It also doesn't really affect flow because merge conflicts and such arise from modifying overlapping files. Can still have Pull Requests for the specific applications inside the repo, and one "lead" can review them all for a team.Bleeder
I too believe that it's inconsistent behavior, I mean most of the projects we develop in our company has client and admin side. Currently Client side comes under projectname -> src and admin side goes under project-name->projects->app-name->src which is not a good structure in my opinion. BTW We still can create client directory inside "projects" and move initial src folder there but then we have to change all of it's initial paths based on that, so if we have to do that manually.Silkaline
@Silkaline yeah, that's what led to this post and my feature request on githubBleeder
Hey what ever happend to this? Do you have an example project of this working?Riesling
Please have a look at my repo at github.com/ShubhenduVaid/angularCLI-monorepo. 1. I have used monorepo structure and angular cli v6. 2. Steps are in Readme. 3. As a bonus i have used Service as an Interface too. Let me know if any questions.Panlogism
I don't think you understood my question. I wanted to create a new workspace with all original src and e2e files in the projects folder by default. Meaning as I add applications and libraries to the project I don't want one app to be orphaned while the others are in projects. There currently isn't a way to do this. The hacky workaround is to run ng new <mono-repo name>, cd into it, generate the first app name (ng new application <app-name>) and then remove the original src / e2e folders (rm -rf src e2e) and the corresponding entry in angular.jsonBleeder
Removing the original src / e2e folders (rm -rf src e2e) and the corresponding entry in angular.json is a one time job. After this all libraries,applications will be in projects folder. To have the libraries in a separate folder other than projects is not possible yet. But is accepted as a feature in future versions github.com/angular/angular-cli/issues/11927Panlogism
B
4

There currently isn't a way to do this the way I intend.

The hacky workaround is to run:

ng new <mono-repo name>

cd into it (cd <mono-repo name>)

generate the first app name (ng generate application <app-name>)

and then remove the original src / e2e folders (rm -rf src e2e) and the corresponding entry in angular.json.

From then on whenever libraries / applications are generated everything will be in the projects folder.

Bleeder answered 28/8, 2018 at 14:40 Comment(1)
since Angular 7 --createApplication=false should do the trickGlaucous
B
4

If you don't want your initial application to resides in /src, you can follow these 2 steps:

ng new my-workspace --create-application=false --defaults
  • --create-application tells the Angular CLI not to generate an initial application.
  • --defaults tells the Angular CLI not to prompt you about routing and CSS preprocessor
ng generate application my-app

With these two steps, you will end up with a file structure like this:

.
├── .git/
├── node_modules/
├── projects/
├── .editorconfig
├── .gitignore
├── README.md
├── angular.json
├── package.json
├── tsconfig.json
├── tslint.json
└── yarn.lock

And you will find your application and its corresponding e2e application in the projects folder:

projects/
├── my-app/
└── my-app-e2e/
Bremerhaven answered 11/2, 2019 at 17:33 Comment(0)
D
1

I here is a guide how to do this using Nx and Angular CLI here The easiest is just to start with generating an empty Angular CLI project:

ng new --createApplication false

or if you use NX:

create-nx-workspace myworkspacedemo

From here you can generate apps in the app folder with:

ng g app myapp

And generate libs in the libs folder with:

ng g lib mylib

If you are using NX schematics this will also prompt you for a lot of extra configuration options such as generating lazy loaded modules, routing, use Jest etc...

Disengagement answered 13/4, 2019 at 15:38 Comment(0)
Z
0

Try ng g application {project-name} instead.

Result

enter image description here

And Angular.json

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "mono-repo": {
      "root": "",
      "sourceRoot": "src",
      "projectType": "application",
      "prefix": "app",
      "schematics": {},
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "dist/mono-repo",
            "index": "src/index.html",
            "main": "src/main.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "src/tsconfig.app.json",
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ],
            "styles": [
              "src/styles.css"
            ],
            "scripts": []
          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "extractCss": true,
              "namedChunks": false,
              "aot": true,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true
            }
          }
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": "mono-repo:build"
          },
          "configurations": {
            "production": {
              "browserTarget": "mono-repo:build:production"
            }
          }
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "mono-repo:build"
          }
        },
        "test": {
          "builder": "@angular-devkit/build-angular:karma",
          "options": {
            "main": "src/test.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "src/tsconfig.spec.json",
            "karmaConfig": "src/karma.conf.js",
            "styles": [
              "styles.css"
            ],
            "scripts": [],
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ]
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": [
              "src/tsconfig.app.json",
              "src/tsconfig.spec.json"
            ],
            "exclude": [
              "**/node_modules/**"
            ]
          }
        }
      }
    },
    "mono-repo-e2e": {
      "root": "e2e/",
      "projectType": "application",
      "architect": {
        "e2e": {
          "builder": "@angular-devkit/build-angular:protractor",
          "options": {
            "protractorConfig": "e2e/protractor.conf.js",
            "devServerTarget": "mono-repo:serve"
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": "e2e/tsconfig.e2e.json",
            "exclude": [
              "**/node_modules/**"
            ]
          }
        }
      }
    },
    "project-alpha": {
      "root": "projects/project-alpha/",
      "sourceRoot": "projects/project-alpha/src",
      "projectType": "application",
      "prefix": "app",
      "schematics": {},
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "dist/project-alpha",
            "index": "projects/project-alpha/src/index.html",
            "main": "projects/project-alpha/src/main.ts",
            "polyfills": "projects/project-alpha/src/polyfills.ts",
            "tsConfig": "projects/project-alpha/tsconfig.app.json",
            "assets": [
              "projects/project-alpha/src/favicon.ico",
              "projects/project-alpha/src/assets"
            ],
            "styles": [
              "projects/project-alpha/src/styles.css"
            ],
            "scripts": []
          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "projects/project-alpha/src/environments/environment.ts",
                  "with": "projects/project-alpha/src/environments/environment.prod.ts"
                }
              ],
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "extractCss": true,
              "namedChunks": false,
              "aot": true,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true
            }
          }
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": "project-alpha:build"
          },
          "configurations": {
            "production": {
              "browserTarget": "project-alpha:build:production"
            }
          }
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "project-alpha:build"
          }
        },
        "test": {
          "builder": "@angular-devkit/build-angular:karma",
          "options": {
            "main": "projects/project-alpha/src/test.ts",
            "polyfills": "projects/project-alpha/src/polyfills.ts",
            "tsConfig": "projects/project-alpha/tsconfig.spec.json",
            "karmaConfig": "projects/project-alpha/karma.conf.js",
            "styles": [
              "projects/project-alpha/src/styles.css"
            ],
            "scripts": [],
            "assets": [
              "projects/project-alpha/src/favicon.ico",
              "projects/project-alpha/src/assets"
            ]
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": [
              "projects/project-alpha/tsconfig.app.json",
              "projects/project-alpha/tsconfig.spec.json"
            ],
            "exclude": [
              "**/node_modules/**"
            ]
          }
        }
      }
    },
    "project-alpha-e2e": {
      "root": "projects/project-alpha-e2e/",
      "projectType": "application",
      "architect": {
        "e2e": {
          "builder": "@angular-devkit/build-angular:protractor",
          "options": {
            "protractorConfig": "projects/project-alpha-e2e/protractor.conf.js",
            "devServerTarget": "project-alpha:serve"
          },
          "configurations": {
            "production": {
              "devServerTarget": "project-alpha:serve:production"
            }
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": "projects/project-alpha-e2e/tsconfig.e2e.json",
            "exclude": [
              "**/node_modules/**"
            ]
          }
        }
      }
    }
  },
  "defaultProject": "mono-repo"
}
Ziguard answered 28/6, 2018 at 21:30 Comment(3)
ng g app and ng g application are the same thing and you have to do it inside an already established project (that has the src folder, as described above). This does not answer my questionBleeder
apparently I've been used to using a schematic that aliases app to application. I've edited my question to clarify but it was a typo on my part / didn't impact my intentBleeder
I originally had the same thought, but reread and saw he already knew this and is looking for something else. I've come to the opinion that g app basically creates a glorified feature module; yes it can be run and tested independently...sort of. It's still dependent on the workspace package.json. This is fine if you publish as an npm mod or some such (it'll yank in the deps), but isn't really that mono-repo nirvana. Your project "apps" still need to be composed by a workspace that contains a package.json. I've been working on this myself at a recent contract. Interesting problem to solve.Alejandrinaalejandro
C
0

Okay it's too easy to create a monorepo architecture
let's see

enter image description here

By doing this you specified an architecture without consisting any application. this gives you code like this...

enter image description here

OOoh it seems you have created your architecture
now come into your code editor and now create your application enter image description here

enter image description here

Now time to check if everything works well or not.
let's run with any random port where you want...

enter image description here

you can have multiple application in single architecture and they all would going to use the same node modules
so in future once you update your any module, all your applications would be accessing the updated one so no need to update them one by one

apart from you can run all your applications on different different ports and create the build as separately

enter image description here

Chryselephantine answered 26/3, 2020 at 11:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.