Vue as an Angular alternative for Ionic: The Components
In this tutorial, we will focus on Vue Components in an Ionic 4 application.
We will first configure the Ionic Team’s Stack from the previous Ionic Vue tutorial to handle the .vue extension, then we will see how a simple TypeScript Component looks like, how Vue Single File Components (SFCs) work and some information on Vue methods.
The Ionic Stack configuration
Well ...
That’s the hardest and most boring part of this tutorial. If you don’t want to use Vue SFC in an Ionic Vue application, just skip this part and the headache.
In the previous Ionic Vue tutorial, we only used HTML, JS and TS files. If we want to create Single File Components (more about that later) in our Ionic Vue application, we need to handle the Vue files.
Let’s start by installing every libraries:
npm install ts-loader vue vue-class-component vue-loader
vue-style-loader vue-template-compiler css-loader --save
We need more than just one Vue library now, we are using the Ionic team’s stack so we already have Webpack and TypeScript configured.
Those libraries:
- Allow us to use Vue
- Allow us to use TypeScript Decorator for Vue Components: vue-class-component
- Allow us to use the .vue files: vue-loader, ts-loader, vue-template-compiler
- Handle the styles: css-loader, vue-style-loader
Take one out and the boat start sinking.
Vue is installed through npm.
However, in our case the Ionic team’s Webpack configuration will always load the wrong library (vue.runtime.esm.js).
We will have to tell Webpack that we want the vue.esm.js file.
If you are quite new to Ionic or Angular, Webpack is the bundler which transforms our TypeScript files to JavaScript, minify, uglify, etc.
If you are using Ionic 4, you will need to make a detour there to see how to integrate a custom Webpack configuration.
Once the extra-webpack.config.json file is used, we can use the following code:
const { VueLoaderPlugin } = require('vue-loader');
console.log('The custom config is used');
const vueAlias = {
extensions: [".ts", ".js", ".vue", ".json"],
alias: {
vue$: "vue/dist/vue.esm.js"
}
};
const vueRule = [{
test: /\.vue$/,
loader: "vue-loader",
options: {
// Since sass-loader (weirdly) has SCSS as its default parse mode, we map the
// "scss" and "sass" values for the lang attribute to the right configs here.
// other preprocessors should work out of the box, no loader config like this
// necessary.
scss: ["vue-style-loader", "css-loader", "sass-loader"],
sass: ["vue-style-loader", "css-loader", "sass-loader?indentedSyntax"]
}
// other vue-loader options go here
}];
module.exports = {
resolve: vueAlias,
plugins: [new VueLoaderPlugin()],
module: {
rules: vueRule
}
}
If you are still using Ionic 3, the process is as follow.
The Webpack configuration is located in the node_modules/@ionic/app-scripts folder. We are not going to edit this file.
Instead, we will reference a new webpack.config.js file in the package.json file:
...
"config": {
"ionic_webpack": "./webpack.config.js"
}
Which is as follow:
const webpackConfig = require("./node_modules/@ionic/app-scripts/config/webpack.config");
const vueAlias = {
extensions: [".ts", ".js", ".vue", ".json"],
alias: {
vue$: "vue/dist/vue.esm.js"
}
};
const vueRule = {
test: /\.vue$/,
loader: "vue-loader",
options: {
// Since sass-loader (weirdly) has SCSS as its default parse mode, we map the
// "scss" and "sass" values for the lang attribute to the right configs here.
// other preprocessors should work out of the box, no loader config like this
// necessary.
scss: ["vue-style-loader", "css-loader", "sass-loader"],
sass: ["vue-style-loader", "css-loader", "sass-loader?indentedSyntax"]
}
// other vue-loader options go here
};
webpackConfig.dev.module.loaders.push(vueRule);
webpackConfig.dev.resolve = Object.assign(webpackConfig.dev.resolve, vueAlias);
I grabbed most of this file’s configuration from this Vue TypeScript guide:
https://github.com/DanielRosenwasser/typescript-vue-tutorial
First, we acquire the Ionic team’s Webpack configuration.
We add vue to the extensions field. Be careful here, the order is very important.
An alias is then created telling Webpack to use the vue.esm.js file when we import the vue library.
A new rule is then created to handle the vue files, those files will be handled by the vue-loader module then loaded into our Ionic Vue application.
Be careful about the terminology here, we always install npm libraries like Ionic Native Geolocation, Ionic Native Storage, etc. In Webpack terms, the vue-loader is called a module. When this npm library is not installed, a similar error should appear:
!!vue-loader module not found …
Finally, we add the rules to the module loaders and merge everything in the resolve field.
The hardest part is now done, we only need to create a vue-shims.d.ts file in the src folder:
declare module "*.vue" {
import Vue from "vue";
export default Vue;
}
This will allow us to finally create Vue Single File Components (SFCs).
We can finally start comparing Vue and Angular now.
The Ionic Vue Components
Let’s start by creating a global Component in the main.ts file:
Vue.component('global-component', {
template: '<div> Hi I am a global component </div>'
});
var app = new Vue({
...
})
A global Component must be registered before the instantiation of the Vue root instance.
After that, it can be used in the index.html file:
<div id="app">
<global-component></global-component>
</div>
We continue with a simple TypeScript Component:
import Vue from "vue";
import Component from "vue-class-component";
// The @Component decorator indicates the class is a Vue component
@Component({
// All component options are allowed in here
template: '<div>{{message}} <button @click="onClick">Click!</button></div>'
})
export default class SimpleTsComponent extends Vue {
// Initial data can be declared as instance properties
message: string = "Hello!";
// Component methods can be declared as instance methods
onClick(): void {
console.log("TypeScript working!");
}
}
As you can see, by using the vue-class-component library, the Vue Component we created here looks exactly like an Angular Component.
We have a Class that get converted to a Component which contains a template, a property and a method.
We can import this Vue (TypeScript) Component in the main.ts file:
import Vue from "vue";
import SimpleTsComponent from "./simple-ts-component";
var app = new Vue({
el: "#app",
components: { SimpleTsComponent }
});
And use it in the index.html file:
<div id="app">
<simple-ts-component></simple-ts-component>
<global-component></global-component>
</div>
From this perspective, Vue is quite similar to Angular. The only difference with Angular here, is that we would have to register the Component using the NgModule Decorator.
Vue is promoting the use of Single File Components. Let’s see how they look in our Ionic Vue stack.
Single File Components (SFCs)
SFCs are Components that are defined in a single file. The HTML template, JavaScript logic and CSS styling are available there.
Be careful not to misunderstand this with React where they are mixed together, each part of the Component here are clearly separated even if they are in the same file.
We can compare this to Angular where the Component Decorator has a style and a template field.
Here is a normal Vue SFC:
<template>
<div>
<div @click="showFirstThis()">Show current this object</div>
<div @click="showSecondThis()">Show global this object</div>
</div>
</template>
<script>
export default {
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
},
methods: {
// Careful of () =>
showFirstThis: function() {
console.log('Basic function', this);
},
showSecondThis: () => {
console.log('Fat arrow', this);
}
}
}
</script>
<style>
div {
width: 100%;
}
</style>
With our Ionic Vue stack, we need to make some changes:
<template>
<div>
<div @click="showFirstThis()">Show first this object</div>
<div @click="showSecondThis()">Show second this object</div>
</div>
</template>
<script lang="ts" src="./component-with-methods.ts"></script>
<style>
div {
width: 100%;
}
</style>
Because of Webpack, at the moment the script part must be located in another TypeScript file (Ionic Vue SFCs will be real SFCs once the Ionic team releases Ionic 4 and we won’t need to play with the webpack.json file).
Here is the component-with-methods.ts file:
import Vue from "vue";
export default Vue.extend({
data() {
return {
msg: "Welcome to Your Vue.js App"
};
},
methods: {
// Careful of () =>
showFirstThis: function() {
console.log("Basic function", this);
},
showSecondThis: () => {
console.log("Fat arrow", this);
}
}
});
This Component also needs registration in the main.ts file:
import Vue from "vue";
import ComponentWithMethods from "./component-with-methods/component-with-methods.vue";
import SimpleTsComponent from "./simple-ts-component";
Vue.component("global-component", {
template: "<div> Hi I am a global component </div>"
});
var app = new Vue({
el: "#app",
components: { SimpleTsComponent, ComponentWithMethods }
});
Two methods to illustrate an example.
If you are like me, you must love the arrow function. It’s very useful when the this object is lost.
However, with Vue, we must slow down a bit.
If we use them at the wrong place (like a Component’s method declaration), it will use to the parent context instead of the Component’s.
Using the Component:
The first one is linked to the ComponentWithMethods Component, the second one to its parent.
One last thing before we end this post.
Here is the DOM from an Ionic Angular application:
And here with Vue:
Angular creates a new parent Element for its Components, Vue doesn’t!
Conclusion
The Ionic team is making the bet to support every JavaScript frameworks.
That’s quite a challenge!
As you can see since the beginning of this Ionic Vue course, there are many ways to write Ionic Vue Components like using pure JavaScript, Vue SFCs, TypeScript files with Decorators.
If we want our stack to be polyvalent, at the end of the day, Webpack is the place to go.