ionic-team / ionic-cli

The Ionic command-line interface
MIT License
1.99k stars 654 forks source link

Impossible to setup a monorepo multi app project. #4093

Open ignition42 opened 5 years ago

ignition42 commented 5 years ago

Description: I've been trying to setup a monorepo multi app project, I've read #3281 issue and most of the linked issues and commits, specially 2d53c99 and multi-app-projects.
And I think this is not working properly.

The angular.json is as it should be for multiple projects, as @stupidawesome pointed in that issue (#3281) and my ionic.config.json is like this:

{
  "defaultProject": "aclient-ionic-app",
  "projects": {
    "aclient-ionic-app": {
      "name": "IonicApp",
      "integrations": {
        "cordova": {
          "root": "integrations/aclient-ionic-app/cordova"
        }
      },
      "type": "angular",
      "root": "apps/aclient/ionic-app/"
    }
  },
  "anotherclient-anotherapp": {}
}

And I intend to a folder structure like this (or at least something that works):

.
├── apps
|   ├── aclient
|   |   ├── ionic-app
|   |   └── ionic-app-e2e
|   └── anotherclient
|   |   ├── anotherapp
|   |   └── anotherapp-e2e
├── integrations
|   ├── aclient-ionic-app
|   |   └── cordova
|   |       ├── build.json
|   |       ├── config.xml
|   |       ├── platforms
|   |       |   ├── ios
|   |       |   └── android
|   |       ├── plugins
|   |       ├── resources
|   |       └── www
|   └── anotherclient-anotherapp
|       ├── cordova
|       └── electron
├── node_modules
├── angular.json
├── ionic.config.json
└── package.json

The problem is that ionic integrations enable cordova --add --project aclient-ionic-app generates resources and config.xml inside apps/aclient/ionic-app and then automatically adds "integrations": { "cordova": {} } in the root of ionic.config.json ouside of projects. I don't think that's the intended behaviour.

Then I try ionic cordova platform add ios --project aclient-ionic-app and throws an error:

$ ionic cordova platform add ios --project aclient-ionic-app
✔ Creating ./integrations/aclient-ionic-app/cordova/www directory for you - done!
[ERROR] Cannot load Cordova config.

        Could not find necessary file(s): config.xml, package.json.

        - ./integrations/aclient-ionic-app/cordova/config.xml
        - ./integrations/aclient-ionic-app/cordova/package.json

        You can re-add the Cordova integration with the following command: ionic integrations enable cordova --add

So, to fix it in a hacky way I moved manually the file config.xml and the resources folder into integrations/aclient-ionic-app/cordova as well as initiate a npm folder inside cordova and thus creating the package.json.
Now running ionic cordova platform add ios --project aclient-ionic-app installs cordova plugins correctly. But the part that runs ionic cordova resources ios --force fails.

...
...
> ionic cordova resources ios --force
> cordova-res ios
[cordova-res] ERROR: Missing source image for "icon" (sources: resources/ios/icon.png, resources/ios/icon.jpg, resources/ios/icon.jpeg, resources/icon.png, resources/icon.jpg, resources/icon.jpeg)
[ERROR] An error occurred while running subprocess cordova-res.

        cordova-res ios exited with exit code 1.

        Re-running this command with the --verbose flag may provide more information.

Ignoring that error by now I pass to the next thing and then, when I run ionic cordova prepare ios --project aclient-ionic-app fails.
Output with verbose:

$ ionic cordova prepare ios --project aclient-ionic-app --verbose
  ionic:lib Terminal info: { ci: false, shell: '/usr/local/bin/bash', tty: true, windows: false } +0ms
  ionic:lib CLI global options: { _: [ 'cordova', 'prepare', 'ios' ], help: null, h: null, verbose: true, quiet: null, interactive: true, color: true, confirm: null, json: null, project: 'aclient-ionic-app', '--': [] } +4ms
  ionic:lib:project Project id from args: aclient-ionic-app +0ms
  ionic:lib:project Project type from config: @ionic/angular (angular) +0ms
  ionic:lib:project Project details: { configPath: '/Users/ignition42/monorepo/ionic.config.json', errors: [], context: 'multiapp', id: 'aclient-ionic-app', type: 'angular' } +0ms
  ionic Context: { binPath: '/usr/local/lib/node_modules/ionic/bin/ionic', libPath: '/usr/local/lib/node_modules/ionic', execPath: '/Users/ignition42/monorepo', version: '5.2.3' } +0ms
  ionic:lib:integrations:cordova:config Loading Cordova Config (config.xml: '/Users/ignition42/monorepo/integrations/aclient-ionic-app/cordova/config.xml', package.json: '/Users/ignition42/monorepo/integrations/aclient-ionic-app/cordova/package.json') +0ms
  ionic:lib:telemetry Sending telemetry for command: 'ionic cordova prepare' [ 'ios',
  ionic:lib:telemetry   '--verbose',
  ionic:lib:telemetry   '--interactive',
  ionic:lib:telemetry   '--color',
  ionic:lib:telemetry   '--project=aclient-ionic-app' ] +0ms
  ionic:lib:build build options: { '--': [],
  ionic:lib:build   engine: 'cordova',
  ionic:lib:build   platform: 'ios',
  ionic:lib:build   project: 'aclient-ionic-app',
  ionic:lib:build   verbose: false,
  ionic:lib:build   configuration: undefined,
  ionic:lib:build   sourcemaps: undefined,
  ionic:lib:build   cordovaAssets: true,
  ionic:lib:build   type: 'angular' } +0ms
Error: ENOENT: no such file or directory, open '/Users/ignition42/monorepo/apps/aclient/ionic-app/package.json'
  ionic Error: ENOENT: no such file or directory, open '/Users/ignition42/monorepo/apps/aclient/ionic-app/package.json' +132ms

Since before enabling cordova added "integrations": { "cordova": {} } in ionic.config.json I tried to add the root.

{
  "defaultProject": "aclient-ionic-app",
  "projects": {
    "aclient-ionic-app": {
      "name": "IonicApp",
      "integrations": {
        "cordova": {
          "root": "integrations/aclient-ionic-app/cordova"
        }
      },
      "type": "angular",
      "root": "apps/aclient/ionic-app/"
    }
  },
  "integrations": {
    "cordova": {
      "root": "integrations/aclient-ionic-app/cordova"
    }
  }
}

It didn't help at all.

Last thing I tried is to copy all cordova files (config.xml, node_modules, package-lock.json, package.json, platforms, plugins, resources, www) into apps/aclient/ionic-app/ and then run ionic cordova prepare ios.

$ ionic cordova prepare ios --project aclient-ionic-app --verbose
  ionic:lib Terminal info: { ci: false, shell: '/usr/local/bin/bash', tty: true, windows: false } +0ms
  ionic:lib CLI global options: { _: [ 'cordova', 'prepare', 'ios' ], help: null, h: null, verbose: true, quiet: null, interactive: true, color: true, confirm: null, json: null, project: 'aclient-ionic-app', '--': [] } +3ms
  ionic:lib:project Project id from args: aclient-ionic-app +0ms
  ionic:lib:project Project type from config: @ionic/angular (angular) +0ms
  ionic:lib:project Project details: { configPath: '/Users/ignition42/monorepo/ionic.config.json', errors: [], context: 'multiapp', id: 'aclient-ionic-app', type: 'angular' } +0ms
  ionic Context: { binPath: '/usr/local/lib/node_modules/ionic/bin/ionic', libPath: '/usr/local/lib/node_modules/ionic', execPath: '/Users/ignition42/monorepo', version: '5.2.3' } +0ms
  ionic:lib:integrations:cordova:config Loading Cordova Config (config.xml: '/Users/ignition42/monorepo/integrations/aclient-ionic-app/cordova/config.xml', package.json: '/Users/ignition42/monorepo/integrations/aclient-ionic-app/cordova/package.json') +0ms
  ionic:lib:telemetry Sending telemetry for command: 'ionic cordova prepare' [ 'ios',
  ionic:lib:telemetry   '--verbose',
  ionic:lib:telemetry   '--interactive',
  ionic:lib:telemetry   '--color',
  ionic:lib:telemetry   '--project=aclient-ionic-app' ] +0ms
  ionic:lib:build build options: { '--': [],
  ionic:lib:build   engine: 'cordova',
  ionic:lib:build   platform: 'ios',
  ionic:lib:build   project: 'aclient-ionic-app',
  ionic:lib:build   verbose: false,
  ionic:lib:build   configuration: undefined,
  ionic:lib:build   sourcemaps: undefined,
  ionic:lib:build   cordovaAssets: true,
  ionic:lib:build   type: 'angular' } +0ms
  ionic:lib:hooks Looking for ionic:build:before npm script. +0ms
  ionic:lib:build Looking for ionic:build npm script. +8ms
> ng run aclient-ionic-app:ionic-cordova-build --platform=ios --cordova-base-path=/Users/ignition42/monorepo/integrations/aclient-ionic-app/cordova
Target 'ionic-cordova-build' could not be found in project 'aclient-ionic-app'.
Error: Target 'ionic-cordova-build' could not be found in project 'aclient-ionic-app'.
    at Architect._getProjectTarget (/Users/ignition42/monorepo/node_modules/@angular-devkit/architect/src/architect-legacy.js:111:19)
    at Architect.getBuilderConfiguration (/Users/ignition42/monorepo/node_modules/@angular-devkit/architect/src/architect-legacy.js:118:29)
    at RunCommand.runSingleTarget (/Users/ignition42/monorepo/node_modules/@angular/cli/models/architect-command.js:160:45)
    at RunCommand.runArchitectTarget (/Users/ignition42/monorepo/node_modules/@angular/cli/models/architect-command.js:201:35)
    at RunCommand.run (/Users/ignition42/monorepo/node_modules/@angular/cli/commands/run-impl.js:14:25)
    at RunCommand.validateAndRun (/Users/ignition42/monorepo/node_modules/@angular/cli/models/command.js:124:31)
    at process._tickCallback (internal/process/next_tick.js:68:7)
    at Function.Module.runMain (internal/modules/cjs/loader.js:832:11)
    at startup (internal/bootstrap/node.js:283:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:622:3)
[ERROR] An error occurred while running subprocess ng.

        ng run aclient-ionic-app:ionic-cordova-build --platform=ios --cordova-base-path=... exited with exit code 1.

        Re-running this command with the --verbose flag may provide more information.
  ionic:utils-process onBeforeExit handler: 'process.exit' received +0ms
  ionic:utils-process onBeforeExit handler: running 1 functions +0ms
  ionic:utils-process processExit: exiting (exit code: 1) +32ms

Moving files around and trying to trick the system is not ideal, but I didn't think of any other way to make it work, I think this is broken or I might have missed something.

My ionic info:

$ ionic info
[ERROR] Error loading @ionic/angular-toolkit package.json: Error: Cannot find module '@ionic/angular-toolkit/package'

Ionic:

   Ionic CLI                     : 5.2.3 (/usr/local/lib/node_modules/ionic)
   Ionic Framework               : @ionic/angular 4.6.2 (/Users/ignition42/monorepo/node_modules/@ionic/angular)
   @angular-devkit/build-angular : 0.13.9 (/Users/ignition42/monorepo/node_modules/@angular-devkit/build-angular)
   @angular-devkit/schematics    : 7.3.1 (/Users/ignition42/monorepo/node_modules/@angular-devkit/schematics)
   @angular/cli                  : 7.3.1 (/Users/ignition42/monorepo/node_modules/@angular/cli)
   @ionic/angular-toolkit        : not installed

Cordova:

   Cordova CLI       : 9.0.0 (cordova-lib@9.0.1)
   Cordova Platforms : ios 5.0.1
   Cordova Plugins   : cordova-plugin-ionic-keyboard 2.1.3, cordova-plugin-ionic-webview 4.1.1, (and 4 other plugins)

Utility:

   cordova-res : 0.6.0
   native-run  : not installed

System:

   NodeJS : v10.16.0 (/usr/local/Cellar/node@10/10.16.0/bin/node)
   npm    : 6.9.0
   OS     : macOS Mojave
ignition42 commented 5 years ago

Maybe @dwieeb who made that commit can shed some light on this.

Thanks

imhoffd commented 5 years ago

I can take a look, but I can't promise anything timely. I am busy with other priorities at the moment. From glancing over this, it's likely a bug. Will look more in depth at a later time. Always accepting PRs. Thanks!

lehmamic commented 5 years ago

We had the same problem.

In my opinion, ionic start in a multi app project should not a local angular.json, but a shared one beside the ionic.config.json as describe by @ignition42.

Good news for whoever tried it, I found a working workaround. Ionic expects a package.json on app level. It is enough to just create an almost bar package.json there:

{ "name": "myapp", "version": "1.0.0", "scripts": { "ionic:build": "cd .. && ng build myapp", } }

Important is only that the ionic:build script gets overwritten so that ionic can build it.

imhoffd commented 5 years ago

@ignition42 I believe https://github.com/ionic-team/ionic-cli/commit/4e8a2268d24498c66e1867c81a62cfd866cc2d4c fixes this issue. I used these steps: https://github.com/dwieeb/ionic-multiapp/commits/master

Please try Ionic CLI 5.2.8 and let me know if it's better.

@lehmamic

In my opinion, ionic start in a multi app project should not a local angular.json, but a shared one beside the ionic.config.json

That is discussed in this issue: https://github.com/ionic-team/ionic-cli/issues/4121

Domvel commented 5 years ago

Do I understand it correctly. We have to change in Ionic that no package is required anymore or set a path to the root and single package.json in a monorepo. We should also consider to do this with the config.xml. In my case I only want one package.json and one config.xml. I change the app-id in the config.xml dynamically. Ok this is maybe a bit special. But the dream of non repetition deps in a monorepo is not special. I think aloud: We could add a option in ionic.config.json for the app which replaces it on build in config.xml. But maybe this is another scope. Anyway... do anyone understand what I mean? If not I pleased to explain it more. Also more infos in this issue #4121

btw. The cordova property in package.json is important for Ionic cli, not the scripts. I have no idea how to design it more or less perfectly. But if we can set the path of package.json and config.xml, it will maybe help. I hope there are no paths issues if we do this.

In short: Ionic should only build the Angular project from the selected app and wrap it in Cordova Android of the root path.

We could extract the cordova property stuff in a separate file. And remove the dependency of package.json in every sub-project. For the config.xml we have to extract all unique properties which are different from app to app. But keeping the same dependencies.

Domvel commented 5 years ago

Is there are workaround? 🤔 To fool Ionic building the root with the Cordova stuff and package.json but trigger the Angular multi-app build. Or build the angular project first and then the Corodva manually. ... Any idea?

Sina7312 commented 4 years ago

Is there any update on this?

imhoffd commented 4 years ago

@ignition42 @Domvel @Sina7312 I just pushed a commit which fixes a couple bugs related to this issue. I was able to create a project structure similar to the original post in my test repo: https://github.com/dwieeb/ionic-multiapp/tree/multiapp-4093. See the commits for steps.

Couple notes:

Please let me know if I'm on the right track. If so, I'll make a release with the fixes for the discovered issues. Thanks!

Domvel commented 4 years ago

@dwieeb Thank you! :) I will look into that in the near future. Just for the overview, in my case I want a Ionic 4 app with Android Cordova and Angular. A monorepo with only one package.json (deps) and a single Cordova setup with variables to build. I've already done that with hacking. I have an official Angular workspace with only one package.json and config.xml (Cordova). And a node build script. I don't use the Ionic build scripts for Cordova. I guess this is still an issue. But anyway... I discontinued this project because of internal decisions. (Not because of the setup. Because of the conversion of the big project and deps compatibility. Anyway...) I'll test it in some free hours. ...

Domvel commented 4 years ago

Now I created a new repo by following this instructions. (without set a default project.) And it looks great 👍 (note: not fully tested for the real life usage.)

ng new --create-application=false --new-project-root='.' my-monorepo

cd .\my-monorepo\
ionic init --multi-app

ng generate application --minimal --prefix=app --routing --style=css app-one
ng add @ionic/angular --project=app-one

ng generate application --minimal --prefix=app --routing --style=css app-two
ng add @ionic/angular --project=app-two

cd .\app-one\
ionic init app-one --type=angular --project-id=app-one

cd ..
cd .\app-two\
ionic init app-two --type=angular --project-id=app-two

# (No default project.)

But in the angular.json I see that only the first app has all the style files. The seconds app not. It this the reason for a default app is required? Currently I have not set any app as default project. I don't want this.

Finally it works. But see the issue of missing styles for the other app in angular.json. The next step is to fix that and add Cordova. ... Cordova detects a project by the file config.xml and the folder www (empty or not). Both are required to install plugins and run / build the project. Cordova and its resources should only exist once in my monorepo. This means you need variables and replace it in config.xml (app id, name, version) before build. ... Again, I already have a custom monorepo setup with own builder (without Ionic CLI). I'll try to test the Cordova part in the next step for this new Ionic monorepo.

Here is the project I followed the commands above. (without setting a default project). my-monorepo.zip

The app-two entry does not include the Angular Ionic styles.

Domvel commented 4 years ago

New try to reproduce the styles error. New commands order and with default project:

ng new --create-application=false --new-project-root='.' my-monorepo

cd .\my-monorepo\
ionic init --multi-app

ng generate application --minimal --prefix=app --routing --style=css app-one
ng add @ionic/angular --project=app-one
cd .\app-one\
ionic init app-one --type=angular --project-id=app-one
? Would you like to make this app the default project? Yes (but I don't really want a default project. :/)

cd ..

ng generate application --minimal --prefix=app --routing --style=css app-two
ng add @ionic/angular --project=app-two
cd .\app-two\
ionic init app-two --type=angular --project-id=app-two

ng serve --project=app-one

Error:

An unhandled exception occurred: Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.
 - configuration.entry['styles'] should not contain the item '..\my-monorepo\node_modules\@ionic\angular\css\flex-utils.css' twice.
   -> A non-empty array of non-empty strings

Maybe this is because the CLI adds the styles in the wrong app in angular.json. So, all css-files occurs twice.

my-monorepo.zip (see the angular.json app-id.styles array)

imhoffd commented 4 years ago

@Domvel I believe the issue you're describing is that it's trying to add the styles to the same app, and I believe it's an issue with our schematics that's being fixed by this PR: https://github.com/ionic-team/ionic/pull/20768

y0nd0 commented 4 years ago

Ionic / Cordova still not work correctly. On ionic cordova build android --project=app-one it installs the native plugins, but fails on missing package.json in /apps/app-one/ directory. I defined the root to the workspace root. It works for the execution of cordova but not for the plugins installation.

I created my multi-app workspace like:

ng new --create-application=false --new-project-root='./apps' my-monorepo

cd my-monorepo/
ionic init --multi-app

ng generate application --minimal --prefix=app --routing --style=scss app-one
ng generate application --minimal --prefix=app --routing --style=scss app-two

ng add @ionic/angular --project=app-one
ng add @ionic/angular --project=app-two

cd apps/app-one/
ionic init app-one --type=angular --default --project-id=app-one

cd ..
cd ..

cd apps/app-two/
ionic init app-two --type=angular --default --project-id=app-two

Then adding cordova:

ionic cordova platform add android --project=app-one
ionic cordova platform add android --project=app-two

Workspace structure:

my-monorepo
|- apps
|  |- app-one
|  |  |- src/
|  |  |- tsconfig.app.json
|  |- app-two/
|- angular.json
|- config.xml
|- ionic.config.json
|- package.json
|- tsconfig.json
|- tslint.json

The ionic.config.json:

{
  "projects": {
    "app-one": {
      "name": "app-one",
      "integrations": {
        "cordova": {
          "root": "./"
        }
      },
      "type": "angular",
      "root": "apps/app-one"
    },
    "app-two": {
      "name": "app-two",
      "integrations": {
        "cordova": {
          "root": "./"
        }
      },
      "type": "angular",
      "root": "apps/app-two"
    }
  }
}

Btw. I can't find any docs for the integrations > * > properties. I found the property root by accident.

Why only one config.xml? I'll replace the app id, name, etc. later dynamically. All apps sharing the same dependencies and plugins.

Now I want to build the apk.

ionic cordova build android --project=app-one

> cordova.cmd platform add android --save

Using cordova-fetch for cordova-android@^9.0.0
Adding android project...
Creating Cordova project for the Android platform:
        Path: platforms\android
        Package: io.ionic.starter
        Name: MyApp
        Activity: MainActivity
        Android target: android-29
Subproject Path: CordovaLib
Subproject Path: app
Android project created with cordova-android@9.0.0
Plugin 'cordova-plugin-whitelist' found in config.xml... Migrating it to package.json
Plugin 'cordova-plugin-statusbar' found in config.xml... Migrating it to package.json
Plugin 'cordova-plugin-device' found in config.xml... Migrating it to package.json
Plugin 'cordova-plugin-splashscreen' found in config.xml... Migrating it to package.json
Plugin 'cordova-plugin-ionic-webview' found in config.xml... Migrating it to package.json
Plugin 'cordova-plugin-ionic-keyboard' found in config.xml... Migrating it to package.json
Discovered plugin "cordova-plugin-whitelist". Adding it to the project
Installing "cordova-plugin-whitelist" for android

  This plugin is only applicable for versions of cordova-android greater than 4.0. If you have a previous platform version, you do *not* need this plugin since the whitelist will be built in.

Adding cordova-plugin-whitelist to package.json
Discovered plugin "cordova-plugin-statusbar". Adding it to the project
Installing "cordova-plugin-statusbar" for android
Adding cordova-plugin-statusbar to package.json
Discovered plugin "cordova-plugin-device". Adding it to the project
Installing "cordova-plugin-device" for android
Adding cordova-plugin-device to package.json
Discovered plugin "cordova-plugin-splashscreen". Adding it to the project
Installing "cordova-plugin-splashscreen" for android
Adding cordova-plugin-splashscreen to package.json
Discovered plugin "cordova-plugin-ionic-webview". Adding it to the project
Installing "cordova-plugin-ionic-keyboard" for android
Adding cordova-plugin-ionic-keyboard to package.json

Error: ENOENT: no such file or directory, open
'C:\Users\User\projects\ionic\my-monorepo\apps\app-one\package.json

It should access the root package.json. 😞

imhoffd commented 4 years ago

@y0nd0 That error is coming from Cordova, not the Ionic CLI. Cordova projects manage plugin versions and variables as well as other metadata in package.json as well as config.xml. You may need a package.json in each Cordova app directory.

stuartin commented 4 years ago

@dwieeb Thanks for the instructions! I had a few problems running ionic generate commands getting: An unhandled exception occurred: Schematic "page" not found in collection "@schematics/angular".

Fix for me was ng config cli.defaultCollection @ionic/angular-toolkit and all my ionic generate commands work as expected

imhoffd commented 4 years ago

@stuartin Thanks for the feedback! I added that as a troubleshooting note.

blackram commented 3 years ago

For anyone coming to this issue with Angular 12 with Node 16, I have worked through the references above and have a monorepo working as I would expect:

The issues around packages reported above come down to cordova requiring an ' npm init' to be run in the integrations output project.

The one thing that appears to be missing and it may be a good thing is the angular build output doesn't make its way to the integrations www folder for the platforms to be built with the web assets. Either add as symlink for the dist output, or as I did, create a hook script.

I have documented the steps I followed here

https://github.com/blackram/ionic-cordova-monorepo

dgonzalez870 commented 3 years ago

For anyone coming to this issue with Angular 12 with Node 16, I have worked through the references above and have a monorepo working as I would expect:

  • common angular json
  • with an angular app
  • an ionic app
  • a shared library
  • platform sources for at least android to run in Android Studio

The issues around packages reported above come down to cordova requiring an ' npm init' to be run in the integrations output project.

The one thing that appears to be missing and it may be a good thing is the angular build output doesn't make its way to the integrations www folder for the platforms to be built with the web assets. Either add as symlink for the dist output, or as I did, create a hook script.

I have documented the steps I followed here

https://github.com/blackram/ionic-cordova-monorepo

Thanks @blackram , works fine!

harikvpy commented 2 years ago

Came here while researching into the issues I faced while setting up an Ionic Angular with Capacitor integrations monorepo project. I then set it up with NX which went well, until I wanted to use --livereload where it failed. Also, I'm not a great fan of piling on new tools on my project repos and learning their commands, unless it's absolutely necessary.

This eventually led me to try and create a project template that uses only Ionic and Angular CLIs. You can check it out here.

It's tested on Android and works fine. If someone can verify it on iOS, it'll be great. Thanks.