Home

Awesome

HitCount Build Status codecov Github actions

Vue3

Please use vue3-vite-vue-class-component for vue3 vite setup.

Vue-webpack-typescript project starter

This project is generated via vue-webpack-minimal and features:

Get started

Install dependencies:

Run development server

This runs the development server w/o a linter on.

yarn start

Tests

There're multiple things you can do with test:

Headless cypress upon static server

The command bellow builds static files with coverage babel plugin information, creates a http server and runs cypress (e2e) tests located in the integrationFolder against that server in headless mode.

yarn test

You can check reports in nyc directory, including coverage information.

Headful cypress upon webpack-dev-server

This command is useful during development. You can click and inspect in live mode in cypress, and just develop while your tests are being ran automatically on file save. I usually have cypress test on one display, IDE on another one, and browser on 3rd one. So I instantly see which changes my code introduces.

  1. Start dev-server in test mode. yarn start won't work, cause of missing coverage info and some other polyfills and tweaks required.
yarn start:test
  1. Open cypress in debug mode. This mode means you can inspect the cypress UI directly in the browser and your test could automatically run upon file save.
yarn run test:cypress:debug

Lint

To check the styleguide use:

yarn lint

Build for productions to static files:

yarn run build:prod

Configurations

Environment variables

Configuration files

WebStorm IDE

Indentation

Set indentation to 2 2 4for html, sass, js, ts in settings -> editor -> code style

Set template

  1. New
  2. Edit files templates...
  3. Vue single file component
<template>
  <div>#[[$END$]]#</div>
</template>

<script lang="ts">
import {Component, Prop, Vue, Watch, Ref} from "vue-property-decorator";

@Component
export default class ${COMPONENT_NAME} extends Vue {

}
</script>
<!-- eslint-disable -->
<style lang="sass" scoped>

</style>

Disable tslint

Tslint is not used for files, since it's deprecated. Use eslint instead and disable tslint

  1. Settings
  2. Typescript
  3. Tslint
  4. Disable tslint

Disable inspections [Optional]

To avoid mixing warnings from eslint and jetbrains, you can turn them off by default

  1. project preferences
  2. editor
  3. inspection
  4. javascript
  5. turn off everything, but leave: Code quality tools -> eslint

Max line length

  1. Editor
  2. Code style
  3. Hard wrap at 120

Exclude directories from indexing

Mark nyc and dist directories ex excluded. Mouse 2 on the directory in the project explorer tree -> mark directory as -> excluded

Style guide and how to

Code samples with libs it belongs to

typescript

Typescript (or ts shortly) allows to write typesafe code:

const a: number = 3;

vue

Vue allows to write SFC that would generate html to the page. Vue is only responsible for UI layer, this is not an MVC framework. The only thing that it does is creates <div></div codeblocks. Everything else is handled by libraries below .

vuex

Vuex is a state management pattern. It allows multiple vue components to have single model/data (source of truth). So if you have a user object like {age: 3, name: 'eric'} it can be accessible in multiple places. This is redux/mobx analogue for React.

vueRouter

Vue router allows navigation across pages in vue, w/o sending get request to the server. And produces access to URL parameters. The examples of routes is here:

new VueRouter({
  routes: [{
    path: '/posts', // this is url address
    component: PostsPage // this is vue component
  }]
});

sass

Sass allows to write code that would be compiled into css

$font-stack:    Helvetica, sans-serif
body
  font: 100% $font-stack
  a
    display: block

vue-class-component

Vue class component allows to write vue component in class manner instead of object:

export default class App extends Vue {
  // initial data
  msg = 123

  // use prop values for initial data
  helloMsg = 'Hello, ' + this.propMessage

  // lifecycle hook
  mounted () {
    this.greet()
  }

  // computed
  get computedMsg () {
    return 'computed ' + this.msg
  }

  // method
  greet () {
    alert('greeting: ' + this.msg)
  }
}

vue-property-decorator

Since vue-class-component forces you to have decorators above the class like this:

@Component({
  props: {
    propMessage: String
  }
})
export default class App extends Vue {}

the following construction can be used instead:

import { Vue, Component, Prop, Watch, Emit, Ref } from 'vue-property-decorator'

@Component
export class MyComp extends Vue {

  @Ref
  button: HTMLInputElement;

  @Prop readonly propA!: number;

  @Watch('child')
  onChildChanged(val: string, oldVal: string) { }

  @Emit()
  changedProps() {}
}

vuex-module-decorators.

This is a wrapper with static getters for vuex. Check store/users instead of writing vuex modules as a dict, for instance:

import { Module, VuexModule, Mutation, Action } from 'vuex-module-decorators'

@Module
export default class UserState extends VuexModule {
 count = 0
 @Mutation
 increment(delta: number) {
   this.count += delta
 }
 // action 'decr' commits mutation 'increment' when done with return value as payload
 @Action({ commit: 'increment' })
 decr() {
   return 5
 }
}

State can be injected into the vue component this way:

class A extends Vue {
    @UserState
    public readonly count!: number;
}

mocha

This test library: allows to write

describe('console', () => {
  it('should print', () => {
    console.log('Hello world')
  })
})

chai and chai-as-promised

Those are assertion libraries that adds bdd assertions:

expect([1, 2]).to.be.an('array').that.does.not.include(3);

sinon

This is mocking library that allows you to write:

const myAPI = { method: function () {} };
const spy = sinon.spy();
const mock = sinon.mock(myAPI);
mock.expects("method").once().throws();

sinon-chai

To to write tests in BDD-like:

expect(mySpy).to.have.been.calledWith("foo");

lines-logger

This wrapper provides a single interface to console.log and displays the origin source file location:

logger.log('Hello world')(); // pay attention to () in the end.

cypress

A testing framework that allows running test-cases directly in chrome (alternative to Selenium, that runs it on server) That part you've already seen on mocha above can be appended with cypress assertions and helpers:

it("should contain 5 elements", (): void => {
  cy.get("[data-cy=filtered-users-container]").children().should("have.length", 1);
});

Build process libraries

Typescript compilation libraries

Typescript is compiled via babel, this means that it doesn't have typechecks, this speeds up build a lot! But since we still want to take advantages of typechecks we run typescript compiler runs in a separate process, giving errors to stdout.

Test libraries

Lint libraries

Continuous integration

This project has support for continuous integration servers:

You don't need to have all of them. So I recommend leave only 1. I would pick github actions since it doesn't require any setup.

Github actions

In order to setup continuous delivery via github:

Cmnd_Alias RESTART_TORNADO = /usr/bin/systemctl restart tornado
http ALL=(ALL) NOPASSWD: RESTART_TORNADO

Tips

How to ignore linting errors

Where I find icons?

Repo uses material desing icons (mdi). Check materialdesignicons.com. And node_modules/@mdi/font/scss/_variables.scss directory, this vars are prefixed with mdi-, like mdi-home.

What's the import order in typescript:

  1. Multiple imports go before singular
  2. Uppercase letter go before lowercase
  3. Imports are aligned alphabetically

For example:

import VueRouter, {RawLocation, Route, RouteRecord} from "vue-router"; // Multiple imports with `VueRouter` that starts with an UpperCase letter
import {globalLogger, jwtStorage} from "@/utils/singletons"; // multiple imports start with lowercase `globalLogger`
import DemoPage from "@/components/pages/DemoPage.vue"; // single import with lowercase
import HomePage from "@/components/pages/HomePage.vue"; // single import with lowercase but alphabetically next
import {ROUTER_HISTORY_MODE} from "@/utils/consts"; // this is still a single import from a capital letter
import {defaultModule} from "@/store/default"; // this is a single import with a lower letter

Debugging

Be aware

TODO