As I’m writing more and more Motoko, it would be nice to have a playground to quickly test code. The quickest way I’ve found to test a function is to run this after each modification:
dfx deploy && dfx canister call my_can myFunc
Even with minimal code, this takes roughly 30 seconds before the output of myFunc is reported.
Is there a faster way to test changes to my code?
If you’ve only made changes to a single canister you can run:
dfx build my_can && dfx canister install my_can -m upgrade && dfx canister call my_can myFunc
You can check the options for any of these commands with the --help flag too, eg:
dfx canister install --help
We are going to release a web-based playground for Motoko to allow you deploy canisters online soon
The live edits in the SDK website is a lightweight version of the playground, if you want to explore small Motoko code snippets.
Something like Remix would reach Solidity devs;
@Ori For some reason, when I try to build just the one canister I’m working on, it fails with
import error, canister alias "credits" not defined
even though I do have a canister named
credits in the project that can be built successfully with
dfx build credits
Everything builds and runs successfully when I use
dfx build or
dfx deploy, so I’m not sure why building just a single canister fails when it is importing another canister.
Have you tried running dfx deploy once first, then using the commands I suggested for any further single canister changes?
Yup. The first command,
dfx build serve fails, complaining that
credits is not found.
serve is one canister that imports the
credits canister which is in the same project and both exist in the canister_ids.json file:
% dfx build serve
The build step failed for canister 'ryjl3-tyaaa-aaaaa-aaaba-cai' with an embedded error: The command '"/Users/mikem/.cache/dfinity/versions/0.6.16/moc" "/Users/mikem/OneDrive/Projects/Web/videate/credits/src/serve/main.mo" "-o" "/Users/mikem/OneDrive/Projects/Web/videate/credits/.dfx/local/canisters/serve/serve.did" "--idl" "--actor-idl" "/Users/mikem/OneDrive/Projects/Web/videate/credits/.dfx/local/canisters/idl/" "--actor-alias" "serve" "ryjl3-tyaaa-aaaaa-aaaba-cai" "--package" "base" "/Users/mikem/.cache/dfinity/versions/0.6.16/base"' failed with exit status 'exit code: 1'.
/Users/mikem/OneDrive/Projects/Web/videate/credits/src/serve/main.mo:19.1-19.34: import error, canister alias "credits" not defined
import Credits "canister:credits"; to import the
credits canister and the
credits code is parallel to the
serve code. Both are able to be deployed with
dfx deploy commands; building works just fine in that case.
Ah, you’ll need to add the credits canister as a dependency of the serve canister in your dfx.json, like this:
Then the above steps should work, so…
First run only:
Subsequent runs for single canister changes:
dfx build serve && dfx canister install serve -m upgrade && dfx canister call serve myFunc
Oh interesting. Odd that the deploy command works without the dependency, but the build command doesn’t. I thought deploy just used build under the hood. Something else is going on?
dfx deploy will be doing the same as
dfx build --all, which will work too, but to build an individual canister it needs the dependencies listed.
Hi all! I’d like to revive this thread now that a year and a half has gone by to see what the community is doing to quickly test code changes.
Is it still best practice to use
dfx build myCanister && dfx canister install myCanister -m upgrade each time I make changes to myCanister? It certainly works a lot faster than
dfx deploy myCanister.
I found that using a pre-built Internet Identity Wasm will allow for quicker testing by using the
II_DUMMY_AUTH feature flags to speed up the Internet Identity account creation and login process (see the Development or Test prebuilt Wasm modules), but I feel like there must be some more tips out there to further speed up UI development and iteration time.
Maybe I’m expecting too much at this point, but I would love to have a page just hot reload with my code changes. Developing for mobile devices using Google’s Flutter has spoiled me, I guess. How close can we get to that when developing on the IC?
During development I run a separate dev server that has hot reload enabled. I’m using esbuild. I think
dfx new sets up a webpack dev server.
Oh cool! If I run my canisters using
npm start, I can access the frontend canisters using port 3000, which will hot reload when I save a .tsx file.
My next challenge: Internet Identity now doesn’t work due to the port mismatch, so I can’t test using hot reload on any pages accessible only after successful login.
After logging in with Internet Identity, when I’m returned to my page, the following error prints out in the console that ran
[webpack-dev-server] [HPM] Error occurred while proxying request localhost:3000/api/v2/status to http://localhost:8000/ [ECONNREFUSED] (https://nodejs.org/api/errors.html#errors_common_system_errors)
Seems like webpack can’t connect to my local Internet Identity canister. It didn’t have a problem loading the Internet Identity login page on port 8000, but for some reason seems to be trying to proxy it through 3000 along with my frontend stuff.
The solution to this similar issue was to run the application server in one terminal and the webpack (via yarn) in another, but I am already doing that: I ran
dfx start in one terminal (which makes port 8000 work for the backend canisters) and I ran
npm start in another (which makes port 3000 work for the frontend canisters).
I also noticed that when I use
npm start, I no longer need to specify the canisterId for my asset canister. It loads my asset canister no matter what I specify for the canisterId query parameter.
Anyone know how to resolve this port issue? What’s the proper workflow for being able to hot reload your pages that are only available after logging in through a locally running Internet Identity canister?
@kpeacock you do a lot of IC frontend development, surely you are able to hot reload pages post-login? How are you able to get around the port issue described above and succeed with the login?
Yes, I do this and can still access parts of my site that require users to be logged in.
I’ll try to respond tomorrow with info on how I do it.
@paulyoung I’d love to see your process, as I’m still facing this issue. My current workaround is to develop the pages by placing them before sending the user to login, then moving them after they look good.
I’m not sure how to help other than to describe what I’m doing;
Dev server (
Then in my app I use the above URL for Internet Identity when running locally.
Localhost domains are supported in Chromium browsers, so I’m using Brave.
I’m currently struggling with the following error when trying to do the proxying by modifying webpack.config.js:
Error occurred while proxying request r7inp-6aaaa-aaaaa-aaabq-cai.localhost:3000/api/v2/status to http://r7inp-6aaaa-aaaaa-aaabq-cai.localhost:8000/ [ENOTFOUND] (https://nodejs.org/api/errors.html#errors_common_system_errors)
If I navigate to http://r7inp-6aaaa-aaaaa-aaabq-cai.localhost:8000/api/v2/status directly it responds successfully, but not when proxied through webpack I guess.
In addition to the default webpack that was set up for me (which I assumed is there to do exactly the thing I’m trying to do), i.e. the following:
// proxy /api to port 8000 during development
I’ve tried a million variations including explicit things like:
I’ll have to pick this up tomorrow. It seems my next steps might be to use esbuild or icx-proxy as you do. I have no experience working with those, but I’ll play around tomorrow. Thanks for your help!
I think I saw something about this being broken on nodejs 17, in case you’re using that.