How to easily use Vue 3.x with ICP, step by step guide

Hey there all :slight_smile:

I’ve been looking into the easiest way of using the build installation process for Vue 3.x and implement that into ICP assets canister and since I managed to make it work in a couple of hours of trial and error, I wanted to share the process with the community, hoping that it will help out a lot of people who are wondering what is the easiest way of installing and using Vue with the ICP frontend canister app using the build installation process, which allows you to use Vue the easiest way possible and enables usage of SFP (single file components) etc.

This consists of a few steps, none of them are too complicated, so I will try to make it as streamlined as possible and easy to understand and follow.

I will use screenshots that will have all the file names in them (at the top) so that you can easily see which screenshots correspond to which files that need to be created or edited. I have also marked the lines in webpack.config.js with a red dot next to them so that you know which lines were added in the setup process (these are the lines that need to be added into the config file to make it work with Vue and to make Webpack compile Vue properly).

Let’s start with the general folder / file structure of your frontend canister:

I’ve just used a simple folder structure here, separating generic Vue components into components directory, pages into pages etc. Nothing special here. The index.js is where we bootstrap our Vue app (code to be shown soon).

Next, let’s see our package.json

There are some dependencies that you need to install, they are mentioned in the dependencies block here. You can also see some additional libraries like

“vue-loader”: “^17.0.0”,
“vue-style-loader”: “^4.1.3”,
“vue-template-compiler”: “^2.6.14”

they are in devDependencies and are used when compiling Vue specific things like Vue templates, styles etc… All of these should be added and installed by using npm, as shown in this file.

NOTE: "@vue/composition-api": "^1.4.9" is the library you need IF you are using Vue composition components etc. You don’t need it if you’re not using that. Also note: the latest version of this library does not (for whatever reason) want Vue version > 3.0 so you would be getting error when trying to install it if you’re using Vue version > 3.0 !! To get around this issue (if you wan’t to still use composition, I managed to install it by using --force flag when installing through npm. This might, however, cause issues along the way (don’t know if it will or not, haven’t tried it). So, if you don’t need composition, you can (I believe) safely remove this dependency completely.

Next, let’s look at the most important thing, which is webpack.config.js file (since we want to just use the default, out of the box webpack config that ICP provides us with, without changing the build process all that much). This will consist of 3 screenshots, since the file is longer and I couldn’t take just one SS of it.




In these screenshots, I’ve marked with the “red dot” all the places where there were changes made to this webpack config file in order to make it work with Vue and to compile things properly for us so that we can use Vue the way we are used to. First, we import the VueLoaderPlugin, then we need to uncomment the whole module section (that is initially commented out) and then add a new object to that array of rules that lives inside of the module array. That tells webpack to use the vue-loader to load and compile all the vue files it encounters in it’s build process. The last thing, we just instantiate new VueLoaderPlugin() at the top of the plugins array inside of this config file. This should enable you to compile Vue properly with using the same process like you’ve used to already while developing on ICP.

And for the end, let’s look into the actual index.js, index.html and the two components we have made to just test out the build and the sample test app we have to make sure it does work.


In index.js we simply import createApp from vue as well as our main component called App. Then, we instantiate the app with createApp(App) (passing it the main app component) and then just mount the app to whichever element we want to use as our app holder.

Let’s see our index.html file now to see how it looks like


As you can see, very, very basic… The only interesting part(s) are that we don’t need to import Vue library at all as this is done for us already, we just need to specify the element to which we are mounting our Vue app inside of index.js.

And the last thing would be our two Vue components that are just made in a very simple fashion, to demonstrate that everything works. One of them also tests out interaction with the very simply Motoko canister.



The code in the TestComponent does not really make any sense, since it’s a counter component but has no logic whatsoever in it, but it was only made to demonstrate that nesting components works etc. You can do whatever you want with them. The AppComponent is the one doing the interaction with the hello motoko canister and just logs to the console result of what is returned from that canister once the component mounts.

And basically, that should be it. Try it out and let me know if there are any issues that you’ve found along the way (I didn’t include anything about having to actually run npm run start to build and deploy the frontend app, I guess that is what is taken for granted from my side :slight_smile:

I also hope that there will be more straightforward tutorials about different topics that are of importance to all of us from the community as we’re already in times that are confusing enough to get into the ICP eco system and any easy to follow help would be very appreciated by everyone (I assume)

7 Likes