Open Domvel opened 5 years ago
@Domvel The Ionic CLI doesn't have opinions about how you structure your monorepo. People could choose to have apps connected with a single angular.json
or one for each app, or something in between. People could choose to install dependencies in each project or at the root, or something in between (this is what the Ionic CLI repo does, but it uses lerna to hoist dependencies). This goes for any of the tools which have config files and could be used at a higher level (.gitignore
, tsconfig.*.json
, tslint.json
).
Remember, the CLI docs (aside from command reference) don't assume you're using Angular. One could create Ionic React apps alongside Ionic Angular apps and the multi-app feature would continue to work, blissfully unaware of the project's internals.
If you don't want these config files in your apps, delete them and make it work for your preferences.
I actually hit this issue last night. I have a mono-repo which contains back end code and multiple front end apps, the general structure is something like the following
- /apps/
---- /app1/
... An Angular App. No deps or angular.json here
---- /app2/
... An Angular App. No deps or angular.json here
- /back-end/
... back end source code and configuration
- /libs/
... shared code
- /node_modules/
... All deps for all projects here
- angular.json
- ionic.config.json
- package.json
- tsconfig.json
I came to add app3
using the ionic cli and tried the following command:
$ ionic start --no-deps
? Project name: apps/app3
? Starter template: sidemenu
The cli then went and made an app called apps-app-3
in the root of my repo. Where I was hoping it would make an app called app3
in the apps
folder. So I deleted the project it had made and re-ran the command from the apps
folder. Not much of a problem, however the cli assumes that you want to have an angular.json
file in the project folder. For me (and a reasonable amount of people using mono-repos), I want to have one angular.json
file in the root of my repo. To get to where I wanted to be I then had to copy the project
property from the created angular.json
and add it the one at the root of my repo, changing all of the paths and target names which was tedious.
I was wondering if it would be possible for the cli to infer values from an existing angular.json
file if creating an angular app.
For instance, if creating a new angular ionic app, then the cli could use the newProjectRoot
property from the angular.json
file in the same folder if it exists.
Or, leave the start
functionality the same, and add an application
option to the generate command which adds an application to the existing workspace. This is similar to how ng
allows you to create mutiple angular apps in the same workspace.
@johneast The apps-app-3
behavior is probably worth a separate issue.
As for the angular.json
stuff, did you read my comment above? I'm not convinced the behavior should change at this moment. I understand that it's awkward to have to delete the extra angular.json
and add the app config to the root angular.json
. Let me go into why it likely won't change for a while:
Right now we use an old-fashioned way of starting projects. We download an archive that contains a working app, and make file changes from there. The Angular CLI and Vue CLI both use a more modern approach, where files and their contents are conditionally provisioned in a template/logic-based approach.
I would argue if we're going to start making changes to framework-based files (which change constantly, i.e. .angular-cli.json
-> angular.json
) after the starter is downloaded, then we should change our approach. See https://github.com/ionic-team/ionic-cli/issues/3499 for this. This will require a lot of work, and it's work we likely won't be able to prioritize for a while.
"The Ionic CLI doesn't have opinions about how you structure your monorepo."
@dwieeb Then what is the Ionic CLI doing? Kinda detecting that ionic.config.json
has a projects
attr and stuffing config in that? And also honoring the --project
flag and passing that onto lower level CLIs?
If the end result is that I still have to make manual changes to various angular.json(s) and modify them accordingly, shouldn't I have to do that for my ionic.config.json(s) as well? And if I have to do that, why bother with this ionic CLI at all?
What's extremely difficult to get past is that the docs as they stand today leave us with a non-functioning app. I understand there's a world of flexibility in setting up a monorepo, so maybe the CLI can't just create one, but if that's the case, could we work to build some example apps that others could leverage as a starting point?
I think it's also worth noting that the ionic CLI, generally speaking, is opinionated about how an app is structured. So we're all used to running ionic start
and ionic generate
and the CLI spitting out a viable app structure. This is an extremely positive thing.
But then this multi-tenant philosophy, without opinions, comes out of left field and leaves everyone spinning not knowing what to do.
@Domvel - it seems odd your apps each have an ionic.config.json
. Mine don't. Check out this repo I put together. It has explicit steps based on the Ionic CLI Documentation (even a setup.sh script!) to create the repo. Did you do something different? In the steps you outlined above I don't see that you cd apps
before running ionic start
maybe that has something to do with it?
@josh-m-sharpe To be clear, I agree. I understand how Angular monorepos are expected to work, and that ng generate application
has the intended effect, and that the equivalent functionality is missing in Ionic. I mentioned at the end of my second comment what I think is a prerequisite for continuing work on the multi-app feature.
What's implemented now is a bare-bones effort to get the Ionic CLI to even operate in a monorepo, which wasn't easy to begin with. Step 2 is adding intelligence around the framework files, which in my opinion requires us to rethink our starters. Luckily, Step 1 allowed the Ionic CLI to be flexible enough for power users to do what they needed to do.
What's extremely difficult to get past is that the docs as they stand today leave us with a non-functioning app
Yeah, we're missing a full tutorial for setting up an Ionic Angular monorepo, which would utilize the multi-app feature and the Angular monorepo feature. The docs as they are today are meant to be a reference for how the Ionic CLI deals with multiple apps in a project (not how to setup an opinionated, full-featured monorepo). We haven't pushed this feature very hard because it still requires manual work, but we should still have the documentation for what exists today. If you like, we can use your issue to track that.
@dwieeb Thanks for the reply.
I appreciate how awkward it can be to code against frameworks that can change at any given time. The process at the moment is a little awkward, however it is workable and the fact that once the projects in the repo are all set up everything works is great.
I like the sound of #3499. It definitely sounds like the way to go in order to make ionic start
extensible and future proof.
Some documentation or walkthroughs about how to setup a mono-repo and add ionic projects to it would be good. I'd be happy to contribute if need be.
Now I have my multi-app. π But can't execute ionic cordova run android
for a specific project.
Does not work:
ionic cordova run android --project=app1
Sorry! ionic cordova run can only be run in an Ionic project directory.
Workspace (not all files listed)
root
|- src
| |- libs (folder with shared stuff)
| |- apps
| |- app1 (same for app2)
| |- main.ts
| |- app.module.ts
|- angular.json
|- ionic.config.json
|- config.xml
|- package.json
ng serve --project=app1
works well.
Background of my workspace:
It's a monorepo with 2 apps with minimal differences. So the main part is in the libs
folder.
There is a common package.json
and deps. Also the android platform is shared.
Only the angular module is different because of some pages etc.
It works in browser when using the Angular CLI ng
and project
property.
But the Ionic commands does not work. I think the project
option is ignored?
It tells me that there is no ionic.config.json
but it is. Look:
ionic.config.json
{
"name": "my-apps",
"integrations": {
"cordova": {}
},
"type": "angular",
"projects": {
"app1": {
"name": "App1",
"integrations": {
"cordova": {}
},
"type": "angular",
"root": "src/apps/app1"
},
"app2": {
"name": "App2",
"integrations": {
"cordova": {}
},
"type": "angular",
"root": "src/apps/app2"
}
}
}
Any my angular.json is also set up well, I think. Angular serve works well. The json is huge. I post it on Stackblitz. I can't believe that the Angular config file is a json and no js-file. There is so much repeated code. But this is another topic. ... angular.json And heres the package.json
What are the criteria for the error message?
Sorry! ionic cordova run can only be run in an Ionic project directory.
If I run ionic init
and enter the name, nothing will change. Because it already exists. What's wrong? π€
@Domvel I just walked through this again. Here's my repo: https://github.com/dwieeb/ionic-multiapp
I ran into a couple weird things with integrating Cordova, which must've been recent bugs, so I fixed them up: https://github.com/ionic-team/ionic-cli/commit/167a68cc2c581c1e82e7c8cd8498317fed15c960 and https://github.com/ionic-team/ionic-cli/commit/4e8a2268d24498c66e1867c81a62cfd866cc2d4c
I'm not getting the "can only be run in an Ionic project directory" error that you're seeing, though. Could you go through my steps and see where we might differ?
@dwieeb Thanks. Yes, I did the same, more or less. I created the sub-apps manually without ionic start
. But the workspace was initially create by the Ionic CLI. Whatever, I wondering how do Ionic detect a non-ionic repo?
Here is my workspace demo. ng serve works. It's a reduced minimal application from my original project. I hope I didn't missed anything. The philosophy of this project is to avoid code repetition. Also for the project setup. I don't want the same stuff for each app as copy. I use one setup and only load different Angular modules. Angulars apps only differs from the bootstrapped module. Only one package.json, tsconfig.ts etc. Also only one Cordova Android for both apps. The app-id is replaced later automatically in Jenkins or manually by scripts. The apps are really identically by the base. Only a few pages etc. are different. This should work.
Maybe the problem is that the apps do not have projects-setups like the root. I don't want a package.json etc. for each app. That's nonsense in my case. Because each app uses the same deps, same base etc. It sould only build the Angular app and wrap it in Cordova for Android. But what's wrong?
ionic info
[ERROR] Error while loading config (project config: .\ionic.config.json)
Unknown project file structure. Run ionic init to re-initialize your Ionic project. Without a valid project
config, the CLI will not have project context.
[WARN] You are not in an Ionic project directory. Project context may be missing.
Ionic:
Ionic CLI : 5.2.5
Utility:
cordova-res : not installed
native-run : 0.2.8
System:
NodeJS : v10.15.3
npm : 6.4.1
OS : Windows 10
ionic init
? Project name: my-apps
[OK] Your Ionic project has been initialized!
(ionic init without changes.)
Ok, now I am one step further.
I removed the root stuff from the ionic.config.json
.
From:
{
"name": "my-apps",
"integrations": {
"cordova": {}
},
"type": "angular",
"projects": {
"app1": {
"name": "App 1",
"integrations": {
"cordova": {}
},
"type": "angular",
"root": "src/apps/app1"
},
"app2": {
"name": "App 2",
"integrations": {
"cordova": {}
},
"type": "angular",
"root": "src/apps/app2"
}
}
}
to:
{
"projects": {
"app1": {
"name": "App 1",
"integrations": {
"cordova": {}
},
"type": "angular",
"root": "src/apps/app1"
},
"app2": {
"name": "App 2",
"integrations": {
"cordova": {}
},
"type": "angular",
"root": "src/apps/app2"
}
}
}
Now Ionic tells me what is wrong or what it is expecting.
ionic cordova run android --project=app1
β Creating .\src\apps\app1\www directory for you - done!
[ERROR] Cannot load Cordova config.
Could not find necessary file(s): config.xml, package.json.
- .\src\apps\app1\config.xml
- .\src\apps\app1\package.json
You can re-add the Cordova integration with the following command: ionic integrations enable cordova --add
Hmmm π€ It looks like I have to create the package.json and config.xml stuff for each app. But is there a way to use this what is in my root folder? As I wrote. Each app should use the same deps and Android config. The app-id, name, resources, etc. will be changed later by scripts. (e.g. Jenkins) Should I keep the root integrations cordova? I expected that Ionic just build the Angular app by the angular build commands and wrap it in Cordova Android from the root.
I understand why it needs separated package.json and config.xml. Because of the name and id. But the rest is equal to each app. I don't want copies.
UPDATE: Now I added the config.xml and package.json by the Ionic and NPM CLI. It works. It's just a dummy package json without deps but have the cordova property from root. It's duplicated code but I if this is the only solution for now I have to use it. I create a branch on github for it ...
UPDATE 2:
Ok, it works until apk is created and installed. But on runtime I get the error:
net::ERR_CONNECTION_REFUSED (http://localhost/)
Here's the current branch about Cordova Android build. But on runtime it fails on localhost connection refused. Maybe I have to set up each app with the complete package json and deps. But I don't like it. Because as I wrote: I have to manage the same stuff in each app. This is really annoying and error prone.
Can I set the package and config xml in ionic.config.json? A common use for all apps. But I understand the inconsistency. Each app requires an own id, name and resources. But maybe there is a way for my case of replacing the id, etc. by a build script (Jenkins). No need for package.json and config.xml in each app. But it looks like that this is not the working way.
Now I'm with NX to check this way. I see that there is only one package.json in the root. But each app have separated tslint.json (but extends from root tslint file). But because of the missing package.json in the apps directory, Ionic will fail too. I think we have to change this. Ionic Cordova should work with multi-apps monorepos like from NX created. Maybe Xplat is the solution.
Update: I tried nx. Ionic fails because requires the package.json for each sub-app. -.-
It feels like pseudo-multi-app / pseudo-monorepo. Because it's nothing else as multiple ionic apps in one folder. For what is the no-deps
option? Currently it's not really a multi-app Ionic workspace. Ok, for Angular it is a multi-app workspace. But for Ionic it's better to create seperated repositories because it does not really support multi-app monorepos. The project in ionic.config.json is just for shortcut reasons. Same as cd
to the folder and execute the regular commands. - I'm tired.
TL;DR: How to use one package.json deps like Ionic and Angular for all apps? Currently Ionic requires to have a package.json for each app. But maybe it's possible to leave the deps blanks and use it from the root package? Maybe it's a node_module folder path option. idk In best case I also want only one config.xml and the other project setup stuff like tslint.json too. Ok, the app id is different. But this could be a option. e.g. in ionic.config.json?
At this moment I have a working "multi-app" monorepo. With 2 apps but 3 package json with exactly the same deps. One for app1, one for app2 and one for the lib folder. ...
A workaround (more or less) could be to refer the packages in the dummy package of an Ionic App. (Inspired by Xplat). Not tested. (I'll test it next week).
root
ββ apps
β ββ app1
β β ββ package.json
β β ββ config.xml
β ββ app2
β ββ package.json
β ββ config.xml
ββ package.json
ββ angular.json
The root package.json
contains all deps. And the package.json for each app contains a reference to the root node_modules as file-ref.
A app package json:
{
"name": "foobar",
"version": "0.0.0",
"dependencies": {
"@ionic/angular": "file:../../node_modules/@ionic/angular",
"rxjs": "file:../../node_modules/rxjs",
"zone.js": "file:../../node_modules/zone.js",
"...": "etc. this is just a comment from me. :)"
}
}
But note: Xplat uses Ionic Capacitor for the apps. There fore no config.xml is required at this place. Also note that you need the cordova
property in your package.json to build Ionic Corodva. Xplat uses the capacitor.config.json
file for the Android build. I have no experiences about Ionic Capacitor. Not yet. Once difference is, that you also commit the Android folder to your repo and have the native code running in Android Studio... At this moment, I don't want to use Capacitor. And I don't like this way. Ionic Cordova should just optional package.json and config.xml. With this workaround above you still have to provide the cordova-property in package.json in each app. I don't know how to refer.
This is an Angular mutli app and library workspace: Take a look to the tag of my repository. Demo here
Created by the commands:
ng new my-workspace --createApplication="false"
ng generate application app1
ng generate application app2
ng generate library shared-lib
Note that there is no need for a package.json for the library folder. It's created e.g. because you could export this library as npm package. Generelly there is no need to have multiple package.json files in your workspace. See app1 and app2 they have no package.json.
Ionic Cordova should repect this workspace (multi-app / monorepo) structure and behavior. This is generated by Angular and official recommended. Ionic v4 is still a special Angular project. Especially the Cordova part. This should be fixed by:
*1
*1
extends
.*1)
This could be optional. Each app or shared from root and handled manuelly. e.g. change the app id before build.
Generally we want only one project / workspace setup with one place to manage the dependencies. And do not repeat your self. (DRY). So we do not want to have the same configurations for each app in the workspace. Unfortunately the angular.json is still "messy". In my opinion it should be a js-file to reuse configurations. You could handle it with a node js-file. But I do not want special "hacks". Follow the mainstream / the standards to reduce the project maintenance.
@dwieeb What are the build commands of Ionic CLI doing? (see below) My idea is to seperate the Angular build and the Ionic Cordova Build.
www
folder.Is this possble? Trigger the build manually in separated parts?
Maybe only use ng
and cordova
without ionic
cli? But I do not want to miss anything.
My scripts (maybe not up to date. It's from Ionic v3. But I think they have not changed.):
Run on Android
ionic cordova run android
Build for Android
ionic cordova build android --release --prod --generateSourceMap false
Update: Ok, I built the Angular project and build the Cordova app. I have a white screen. I have put a text between the app-root
tag in the index.html to see "Loading...". And it's still displayed. So Angular does not load. I think it's because Angular needs a server. Not just locally view the index.html. But where is the magic? What is Ionic doing?
Solution Ok, I figured it out: We need the ionic-webview
for Cordova.
Do we need the script-tag cordova.js
in the index.html in Ionic v4?
Hey,
I've got the same problem. I'm refactoring multiples apps in a monorepo using angular 8 and ionic 4. I could use the ng serve or ionic serve perfectly using the --project argument but i'm totally unable to build or run using ionic cordova command. It failed saying that i can't find the project.
@youuri It's because Ionic requires a package.json
(with cordova property) and config.xml
for each project (app). If you don't want this you have to setup a pure Angular and Cordova project. In my case I built up a Angular multi-app workspace with only one package.json and config.xml and replace the app id. I also use Ionic for the UI and native plugins (Cordova wrapper). But I don't use the Ionic CLI. I just build my Ionic app using ng
(Angular CLI) to www folder and build the apk with Cordova. Works great. But this is just a workaround.
@Domvel i got a dumb package.json in each of my apps with the cordova config & plugins in it. I also have a config.xml in each project and it worked as i want in this case.
But when i run ionic cordova run android --project="app1"
it failed saying that project could not be found. I've investigate in the vendor file and it seems that's related to angular cli (and it's strange cause when i served the code it's good).
So i think i got a configuration issue between angular.json
file and ionic.config.json
.
@youuri Maybe you should use the command without quotes?
ionic cordova run android --project=app1
. And check the ionic.config.json
.
{
"projects": {
"app1": {
"name": "App 1",
"integrations": {
"cordova": {}
},
"type": "angular",
"root": "apps/app1"
}
}
ONLY the projects
property! No other stuff in the root.
And the project should also available in your angular.json
.
btw: In my case I only have the angular.json and no ionic.config.json. (as I wrote above). I'll upload a demo now to my repo.
A multi-app monorepo build by the official guides of the docs of Angular. Using Ionic for UI and native plugin wrapper and the webview (required for Angular). And build with Cordova. No Ionic CLI.
Note: You have to change the app id in config.xml for each app. You can do it automatically by a node script or a build system like Jenkins.
Disclaimer: Maybe it's not comfortable to add more Cordova plugins. Because proberply you have to complete the integration on installing new plugins. Install the plugins by Cordova, not Ionic. Maybe you have to add the plugins to config.xml too. But this is simple, just look to the package.json. If you want to install new plugins from the Ionic docs. Just remove the ionic
keyword of the command.
... It's a promising project setup. But not yet used for real world usage. But I'll use it in the future. But I would appreciate if Ionic will solve the problem we have here soon ..
I'm not sure it's viable in my case. I'll need to have a config.xml & package.json for each ionic app cause they not share all the sames plugins. But it could be if the apps shared the same stack.
I think there is not the only one workspace setup. It depends on what you want. I have common dependencies because each app uses the same base app (shared lib) and they only differ from the main page etc. But if you have completely different apps who uses separate dependencies like your setup, you need a package.json and config.xml for each app. So Ionic should be more flexible to use these kinds of multi-apps.
Another way is to export a shared library as npm package and use separate repositories with a simple single app Ionic setup and use the shared lib using npm package. One repo for the libs, and a repo for each app. This stops some Monorepo problems, but brings other problems. Such as the use of Angular modules. Especially in conjunction with 3rd party libraries, build and import problems, etc. No system is perfect. You will always have advantages and disadvantages. Either from your source code, IDE or workflow. You have to choose what is the right way for your application. - I have followed the principle of NX and Xplat, but uses the official Angular way for multi-app without the NX stuff to have a lightweight and less special setup. Only the Ionic Cordova CLI brought me some problems.
Conclusion: There is no perfect way to develop multiple apps with the same code base (shared library). There is always one component in your source code, your IDE or build system that causes problems or you have to do without a feature.
For Ionic CLI I just wish some more options to use Cordova for single deps like in my monorepo. I think this could be done by setting some paths and maybe a config file for each app to manage the app id and name. ...
π Hey all, please see this comment and this wiki article for the latest on Ionic multi-app projects and Angular Monorepos. Using ng generate
(not ionic start
) with ng add @ionic/angular
and ionic init
provides a pretty smooth experience, as far as I can tell. Please let me know what you think. Monorepos are hard.
It seems to be related to that: Wrong build path on Windows 10
We're doing research into Ionic; created a new React Ionic app; there's no config anywhere; adding it manually does nothing? Any ideas?
@ollyde Have you found a solution?
@Rossella-Mascia-Neosyn I started using Svelte with Capacitor. Both SSR and SPA; it's excellent.
@Rossella-Mascia-Neosyn I started using Svelte with Capacitor. Both SSR and SPA; it's excellent.
Can you explain how you did it?
@Rossella-Mascia-Neosyn sure but I'm not in software anymore after 20 years; in hardware now, so this might be outdated.
import { vitePreprocess } from "@sveltejs/vite-plugin-svelte";
import adapterNode from "@sveltejs/adapter-node";
import adapterStatic from "@sveltejs/adapter-static";
// Determine the mode - this can be set as an environment variable or changed manually
const BUILD_MODE = process.env.BUILD_MODE || "SSR"; // default to SSR, change to 'SPA' for SPA mode
let adapterOptions = {};
// Switch depending on the mode
if (BUILD_MODE === "SPA") {
adapterOptions = {
pages: "build_spa",
assets: "build_spa",
strict: true,
fallback: "index.html",
};
} else {
adapterOptions = {
pages: "target/classes/static/",
assets: "target/classes/static/",
fallback: "index.html",
};
}
const adapter = BUILD_MODE === "SSR" ? adapterNode(adapterOptions) : adapterStatic(adapterOptions);
/** @type {import('@sveltejs/kit').Config} */
const config = {
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
// for more information about preprocessors
preprocess: vitePreprocess(),
kit: {
adapter,
},
};
export default config;
Here's my build SPA bash script for example
#!/bin/bash
# Build the SvelteKit app for Mobile (SPA)
# Function to rename +layout.server.ts files to +layout.server.ts.bak
rename_layout_files() {
find $SRC_DIR -type f -name "+layout.server.ts" -exec mv {} {}.bak \;
find $SRC_DIR -type f -name "+page.server.ts" -exec mv {} {}.bak \;
}
# Function to rename +layout.server.ts.bak files back to +layout.server.ts
restore_layout_files() {
find $SRC_DIR -type f -name "+layout.server.ts.bak" -exec sh -c 'mv "$0" "${0%.bak}"' {} \;
find $SRC_DIR -type f -name "+page.server.ts.bak" -exec sh -c 'mv "$0" "${0%.bak}"' {} \;
}
# Trap to ensure that restore_layout_files is called if the script exits early due to an error
trap 'restore_layout_files' EXIT
# Abort on any error (including if find or npm run fails)
set -e
# Set env
export PUBLIC_DEV=TRUE
export BUILD_MODE=SPA
SRC_DIR="./src"
# Rename +layout.server.ts files before the build
rename_layout_files
vite build --mode production --base
# Rename +layout.server.ts files back after successful build
# The restore_layout_files function will also be called here due to the trap if the script hasn't exited early
restore_layout_files
npx cap sync
# npx cap open ios
# npx cap open android
# Clear the trap
trap - EXIT
Describe the bug https://ionicframework.com/docs/cli/configuration#config-file
Is this correct for the latest version of Ionic? I created the multi-apps with
no-deps
parameter and both apps also have their ownionic-config.json
. Also .gitignore, tslint.json, package.json.To Reproduce
ionic start my-apps
(blank template)ionic.config.json
and add the property"projects": {}
.ionic start app1 --no-deps
. (app1 and app2) (blank template)ionic.config.json
.Expected behavior I'm not sure how the multi-app feature of Ionic works. I though I have a root project with all the project files like
package.json
andionic.config.json
. And the "sub-apps" only contains the sources without separated configuration files etc. Ok they can have a package.json. But why are there all the dependencies, even though the root dependencies should be used? Or do I understand something wrong? Or is the documentation wrong?Screenshots If applicable, add screenshots to help explain your problem.
Browser and OS (please complete the following information):
Additional context I want to create one app base (root) with multi-app feature. Each apps should use the shared root components, services, etc. But an app can also have their own components. TSLint, TSConfig, Unit-Test-Config, gitignore, etc. should be shared. But currently each subapp have a own config. Exactly the same. DRY. Maybe this is a bug for the Ionic core repository or CLI? But perhaps it's only a documentation issue. I don't know who this should actual work. This is my first attempt of building a multi-app. But the fact is, each app in a multi-app project has its own ionic.config.json. The docs says there should only be one shared in the root. Or does this mean, I should delete the config files in my sub-apps?