not an expert, notably because I wrote and use my own custom asset canister in Juno, but I would say yes, you can install_code as you can install_code in any canister on the IC as long as you are the controller
that said, assuming you want to preserve the canister features, install_code replace the all code so if you want to replace its code, then you will have to use the wasm of the certified canister you have compiled but maybe your goal is to replace the wasm code with something totally different?
I believe the UI canister I’m referring to corresponds to the ic-frontend-canister file. I’m talking about the canister that you get as a result of deploying the frontend code of a project that was created using dfx new. Does that make sense?
I’m pretty sure i want to preserve the canister features. I’m not familiar with what goes on when the frontend canister code is compiled and deployed, but I’ll describe the context to you so that you can derive the goal.
Context: im creating an app that is designed to have many instances deployed to the IC. The app has a frontend canister and backend canister. So each instance of the app that is deployed to the IC will have its own frontend canister (and consequently, it’s own URL) and it’s own backend canister.
I need a way to deliver upgrades to these many different instances of the app that are deployed to the IC. For that, I’ll be using the install_code method to programmatically deliver the upgrades to these many different instances. When calling install_code on the frontend canisters, i need to do so in a manner that does not change the canister ids that are specified within the canister_ids.json file. The reason being is that each instance of the app will have canister Id’s that are unique to that particular instance. Those canister id’s are specified in the canister_ids.json file, therefore, that file needs to be unchanged, while the rest of the code is still delivered to the frontend canister. Will i be able to achieve this using the install_code method to deliver the wasm modules to the UI canister’s? Or will the install_code cause the canister ids specified in the canister_ids.json file to be overwritten?
Personal note: for that type of architecture with multiple instances of the same apps, don’t know your project but, spontaneously, I would personaly go for a solution where I would develop my own canister that does both backend and frontend - i.e. not two canisters but one.
Time consuming to develop but worth it at the end. In Papyrs I got that two canisters approach and retrospectively I think it was an incorrect decision. In Juno I went for one canister - satellite - that does everything.
Of course it depends of the project, scalability etc. but for mine, never been so happy that way.
This does help, however i have 1 clarifying question:
If i make the updates to the JSX and HTML code of my frontend, and then call dfx build on the now-updated frontend code, I’ll get a .wasm file as a result. Are you saying that that .wasm file (if installed to the other instances of frontend canisters using the install_code method) Would not result in the other frontend canisters receiving the updated JSX and HTML? But it would result in them receiving the other updates you describe in the 1.?
Yes that makes sense. It’s unfortunate news for me because now i have no idea how to programmatically propagate updates of the JSX/HTML code to the frontend canister instances. Is there any documentation regarding the process by which the JSX/HTML code is uploaded to the canisters? That’d be a helpful starting point in this new researching arc that i must now embark on
Not really documentation, but the entry point is ic-asset::sync. If you want to run this standalone (without dfx deploying wasm), you’d use icx-asset sync.
The reason for using this install-and-only-after-upload approach is that if we baked all frontend code into the wasm, we’d hit size limits instantly - install_code accepts gzipped input, but still only ~2MB. Most frontends are larger than that, so we had to choose a different approach.
I see three ways forward for you: 1) Either write your own asset canister that bakes assets into it, the same way the NNS frontend dapp does it (and you’d be limited to the 2MB total asset size). 2) Or you can write your own syncing logic in a canister so that your canisters can automatically push/pull new frontend versions. 3) Or you manually use ic-asset::sync from your own computer, which would require access to all of your service’s canisters
This option sounds like the best option, but what’s stopping this option from encountering the same 2MB issue? I’m assuming some chunking would have to be written into the logic then, right? Option 1 prohibitively limited and option 3 wouldn’t be possible since i wouldn’t be the canister controller of the other canisters that are due to receive the updates.
Now, what i need to do is understand the syncing logic and then implement it. Is there any reason why i wouldn’t be able to implement the syncing logic in Motoko? I don’t know rust at all. If necessary, I’ll bite the bullet and learn it, but would rather avoid adding such a task to my To-do list.
@Severin , I noticed that the commit_batch method (along with several others) isn’t an asynchronous method. I mean to make it so that a motoko canister can call the commit_batch method of an assets canister in order to perform the upgrade for the JSX/HTML code within the asset canister. The fact that the commit_batch method isn’t an async method implies that this method cannot be called from another canister, correct?
Every function in any canister interface is an async method. Here’s how it gets called in the code that uploads assets via dfx.
If you’re referring to this function declaration, then you should not think of it as ‘not async’, but instead as an update function because it has #[candid_method(update)], which makes it callable from the outside, no matter if it is async fn or fn