For the canister wasm to be created I need to either call dfx build or dfx deploy. The problem is they require the canister_id to be provisioned beforehand otherwise I get an error that looks like this
Error: Failed to determine id for canister ‘individual_user_template’.
Caused by: Failed to determine id for canister ‘individual_user_template’.
Cannot find canister id. Please issue ‘dfx canister create individual_user_template’.
Can dfx build be decoupled from the canister ID provision step and just build the resulting WASM without requiring an already present canister. Otherwise I will have to spend cycles and provision an unnecessary canister.
The problem with this approach is that dfx does some minification and gzipping that this won’t do. The type: "rust" specified in the dfx.json is much more ergonomic and having to do all the build steps ourself is error prone and counter productive.
It would be much more ergonomic to just be able to ask dfx to build without needing to get the canister_id in valid cases such as this.
For dynamically deployed canisters, does dfx need to know the canister IDs? It could just build the canister and call it a day, no? Are there drawbacks to this that I’m not seeing?
Ah, I see. We have a todo item that would expose the optimization through a dfx command, but it just hasn’t been prioritized so far. For the moment it’s still possible to use ic-cdk-optimizer to shrink your wasm. cargo install ic-cdk-optimizer will install it. It won’t be around forever since it’s been deprecated, but for now it still performs the exact same optimization dfx would do otherwise.
Honestly, so far we haven’t really considered dynamically deployed canisters. And you are right, the id is not necessary in quite a few cases, so I agree that restriction could probably be lifted. (But I’ll double-check with those that know the build system in a bit more detail.)
The biggest drawback I can come up with (not claiming this is a show-stopping issue) is that in some cases compilation could run for a while until the error appears even though it could’ve been detected much earlier if no canister IDs are present.
Potential workaround for now: Create a script that does the following
Looking through the code I don’t think dfx already zips up the wasm, but I may be wrong. You can just gzip canister.wasm though and put the resulting .gz file either as your canister’s wasm in dfx.json or manually upload it with dfx canister install --wasm canister.wasm.gz (May require the 0.12.0 beta).
binaryen is run with both dfx (which uses the ic-wasm crate) and ic-cdk-optimizer (just grep for binaryen), so you can use either to minimize your wasm (or to read the source if you want to do it yourself).
Got it. I ended up using a hack for now. By setting the canister ID in the canister_ids.json to aaaa-aa. I remember reading that since that ID corresponds to the management canister, it’s ignored by dfx but the build passes.
I believe the drawback you suggested would mostly not be relevant for folks running dfx build, because most folks whose build expect the canister ID to be present would be using dfx deploy instead of dfx build. I believe dfx build should be decoupled for that reason.
Consider this thread a feature request if you decide to add this to your roadmap
So, I just learned that ic-wasm can be used as a CLI tool! You can install it with cargo install ic-wasm. This would mean that you can ditch ic-cdk-optimizer for good. See ic-wasm -h for the available commands, the one you’re most likely looking for is shrink.
Thanks for that info. Starred that repo. Will try. To be honest, if dfx build just worked without needing canister ID provisioning, that would be ideal. But will bookmark ic-wasm in case I need to do manual canister creation/optimization in the future
I’m happy to provide as many details as you want. I’ll just start with a relatively high-level overview so I don’t spend too much time on stuff you’re not interested in. Let me know what you want to know more about.
L45-L60: Figure out from CLI options and dfx.json settings which canisters are supposed to be built, plus figure out for which canisters’ canister ID and candid interface have to be available for the build commands
L62-L76: enforce that canisters have to be created before the canisters are built. I’d love to lift that entirely, but there’s some issues with that. Not sure if you were involved in the last discussions around that…
What you are probably most interested in is the Rust specialisation of the CanisterBuilder trait: RustBuilder. This contains all the Rust-specific compilation details. Build step here, shrink step refers to this method.
Hey, just wanted to mention that if you need to create a canister that can self spawn itself, the pattern of storing the wasm binary at build time can quickly get out of hand (self importing gets almost as weird as time traveling, once you re-build your project). I’ve found a better pattern to handle such cases, check it out and consider this as an alternative.
Instead of importing the bytes directly, you define somewhere a wasm variable of type Vec<u8>
I think that’s doing the same twice. If DFX_NETWORK is set and no --network is provided then it should act as if --network was set to DFX_NETWORK
Yes, these lines set the envvars so that the right canister ids are available. The pool contains the right IDs for the network. But I’ve never looked at that in detail, so I’d have to investigate the details too