Skip to content

Writing Vue Applications

To write Vue applications you have to install the vue package:

npm i vue

Importing vue components like in import { createApp } from "vue"; would lead to including the Vue library into your final JavaScript file. To avoid this you can add like before the following externals configuration:

webpack.config.js

const ccWebpack = require("@codecoupler/cc-webpack");
module.exports = (env) =>
  ccWebpack(
    {
      externals: [
       {
          module: "vue",
          global: "Vue",
          entries: ["dist/vue.runtime.global.prod.js"]
        },
        {
          module: "jquery",
          global: "jQuery",
          entries: ["dist/jquery.min.js"]
        },
        {
          module: "bootstrap-icons",
          entries: ["font/bootstrap-icons.min.css"],
          copy: ["font/fonts"]
        },
        {
          module: "bootstrap",
          entries: ["dist/js/bootstrap.bundle.min.js"]
        }
      ]
    },
    env,
    {}
  );

First of all we create a Vue Single File Component with all the parts we have written separately (HTML, JavaScript, CSS).

  • The HTML part was put into the <template></template> section. Only a few small adjustments have been made here. Important: Links to assets have to start with ./.
  • The logic of the class was included in the <script></script> section. This part can be written very briefly. Of course you can use here all proposals as with a regular JavaScript file as described before.
  • The stylesheet was included in the <style lang="postcss" scoped></script> section. Please note the lang="postcss" attribute. This is useful to work Visual Code validator together in combination with the Vetur extension. Of course you can use here all proposals as with a regular CSS file as described before.

srv/amazing-button.vue

<template>
  <div class="amazing-button-vue card h-100">
    <div class="card-header">Amazing Vue Button</div>
    <div class="card-body">
      <p class="card-text">
        <button class="btn btn-secondary" @click="amazingFunction">
          Show number from 1 to {{ maximumNumber }}
        </button>
      </p>
      <div class="result border border-primary mb-2">
        {{ resultingNumber ?? "No Result" }}
      </div>
      <img src="./images/favicon.png" />
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      maximumNumber: 9,
      resultingNumber: null
    };
  },
  methods: {
    amazingFunction() {
      this.resultingNumber = Math.floor(Math.random() * this.maximumNumber);
    }
  }
};
</script>
<style lang="postcss" scoped>
.amazing-button-vue {
  --my-color: #f30000;
  text-align: center;
  & .card-header {
    color: var(--my-color);
    background-image: url(images/favicon.png);
    background-size: contain;
    background-repeat: no-repeat;
    background-position-x: left;
  }
}
</style>

We create a class for the sake of simplicity to keep the same interface and mounts our Vue application:

src/amazing-button-vue.js

import { createApp } from "vue";
import AmazonButtonVue from "./amazing-button.vue";
export default class {
  get maximumNumber() {
    return this.vueApp.maximumNumber;
  }
  set maximumNumber(value) {
    this.vueApp.maximumNumber = value;
  }
  constructor(element) {
    console.debug("Starting Vue Button");
    this.vueApp = createApp(AmazonButtonVue).mount(element);
  }
}

Let's add another container in which we will start the new class:

src/index.js

import createTestContainer from "./create-test-container";

import { default as MyVanillaApp } from "./amazing-button-vanilla";
import { default as MyPackagesApp } from "./amazing-button-packages";
import { default as MyImportApp } from "./amazing-button-import";
import { default as MySvgApp } from "./amazing-button-svg";
import { default as MyDynamicApp } from "./amazing-button-dynamic";
import { default as MyVariableApp } from "./amazing-button-variable";
import { default as MyVueApp } from "./amazing-button-vue";

import "./style.css";

createTestContainer("Testing Vanilla JS", "test-container-vanilla");
let myVanillaInstance = new MyVanillaApp(
  document.getElementById("test-container-vanilla")
);
myVanillaInstance.maximumNumber = 99;

createTestContainer("Testing Packages", "test-container-packages");
let myPackagesInstance = new MyPackagesApp(
  document.getElementById("test-container-packages")
);
myPackagesInstance.maximumNumber = 49;

createTestContainer("Testing Import HTML/CSS/Assets", "test-container-import");
let myImportInstance = new MyImportApp(
  document.getElementById("test-container-import")
);
myImportInstance.maximumNumber = 79;

createTestContainer("Testing Import SVG", "test-container-svg");
new MySvgApp(document.getElementById("test-container-svg"));

createTestContainer("Testing Dynamic Imports", "test-container-dynamic");
let myDynamicInstance = new MyDynamicApp(
  document.getElementById("test-container-dynamic")
);
myDynamicInstance.maximumNumber = 55;

createTestContainer("Testing CSS/EJS Variables", "test-container-variable");
let myVariableInstance = new MyVariableApp(
  document.getElementById("test-container-variable")
);
myVariableInstance.maximumNumber = 45;

createTestContainer("Testing Vue", "test-container-vue");
let myVueInstance = new MyVueApp(document.getElementById("test-container-vue"));
myVueInstance.maximumNumber = 12;

With npm start you should see the running example in your browser.