Using single-file components in a Vue.js portlet

Extending Liferay's npm-vuejs-portlet

A few weeks ago I started Maximilian Schwarzmüller's Udemy training Vue JS 2 - The Complete Guide, a highly recommend training for anyone who wants to learn Vue.js.

While I was doing the training I was testing the examples immediately in a Liferay portlet, because my goal for learning Vue.js is to use it as a front-end technology in Liferay.

Creating the Vue.js portlet

The base for this Liferay portlet I generated using Liferay's blade cli tool and the npm Vue.js portlet template:

blade init liferay-vuejs-examples
cd liferay-vuejs-examples/
blade create -t npm-vuejs-portlet triberay-vue-portlet

This results in a bundle with the following structure:

As you can see there is just one javascript file in the lib folder. This file contains all the Vue.js javascript code.
This was totally fine for the first sections of the Udemy training, which were just very basic Vue.js scripts.

SVG Graph Example

At this point, I also tried out some of the examples from the Vue.js website, like this SVG Graph example. I just copied the JavaScript code from the example in the portlet's file, as well as the html code in the portlet's view.jsp (but making sure to still use the <portlet:namespace />-1 id instead of the demo id from the example).
This also worked perfectly so far.


When I came to the section in the Vue course that introduced Vue Components as separate .vue files (e.g. App.vue), I noticed that the liferay-npm-bundler did not process the .vue files at all. 

We can see in Liferay's npm-vuejs-portlet template that the build script in package.json first processes the javascript with babel and then packages the code with the liferay-npm-bundler:

"scripts": { 
    "build": "babel --source-maps -d build/resources/main/META-INF/resources src/main/resources/META-INF/resources && liferay-npm-bundler" 

In order to make sure that all files of our Vue.js app are processed, including all the .vue components,  we'd have to run vue-cli-service first before being packaged by the liferay-npm-bundler.

So, the solution is to call "vue-cli-service build" instead of Babel. Therefore we first have to add the required dependencies to the project:


The build script then looks like this:

"scripts": { 
    "build": "vue-cli-service build --dest build/resources/main/META-INF/resources/lib --target lib --name index src/main/resources/META-INF/resources/**/*.js && liferay-npm-bundler" 

This processes all files in the META-INF/resources/lib folder with vue-cli-service and outputs it as one file "index.common.js" in the build folder, where the liferay-npm-bundler can then pick it up afterward. More about the vue-cli-service command(s) can be found here

The same command can actually be run from the command line as well:

./node_modules/.bin/vue-cli-service  build --dest build/resources/main/META-INF/resources/lib --formats commonjs --target lib --name index src/main/resources/META-INF/resources/**/*.js

The output looks like this:

We can see that vue-cli-service created 2 files in our build folder: index.common.js and index.css. The Javascript file will be picked up by the liferay-npm-bundler.  We'll talk about how  to handle the CSS file in the next section.

Scoped CSS

One of the neat things about using Vue Components is that you can add your CSS for that component into the same .vue file and make sure the scope is limited to that component.



More Blog Entries


Đỗ Hưng 8 Months Ago
Bep The gioi 8 Months Ago

Bep The gioi 8 Months ago in reply to Bep The gioi .