Skip to content

chrisvfritz/vue-workshop

Repository files navigation

Vue Workshop

We'll cover everything you need to know to get started building world-class Vue applications. Topics will include configuring Webpack for single-file components, setting up the most advanced workflows currently possible, how to organize (and reorganize) increasingly complex applications, and more.

Setup

  1. Install the latest version of Yarn

Development

# Install dependencies
# If you don't have yarn installed: `npm install --global yarn`
yarn install

# Launch and serve with live reload at localhost:9080
yarn dev

# build for production with minification
yarn build

# build for production and view the bundle analyzer report
yarn build --report

# check the formatting for all files
yarn format

# lint all source files
yarn lint

# lint all source files and fix issues, where available
yarn lint:fix

# run unit tests
yarn unit

# run unit tests in watch mode
yarn unit:watch

# run end to end tests
yarn e2e

# run all tests
yarn test

For a detailed explanation on how things work, check out the guide and docs for vue-loader.

Editors

Visual Studio Code

This project is best developed in VS Code. By installing the recommended extensions, you will get:

  • Syntax highlighting for all files
  • Intellisense for all files
  • Format on save for all files
  • Lint on save for all files
  • In-editor results on save for unit tests

Formatting

We use Prettier to format our JavaScript, S(CSS), and Markdown, ensuring a consistent style. In Visual Studio Code, installing the recommended extensions will automatically format on save in any file.

Linting

Linting is included for Vue, JavaScript, (S)CSS, and Markdown. The current rules are pretty opinionated, to not only avoid errors but also ensure a consistent style.

Aliases

While relative paths can be used to import any file in our src, we also have a few useful aliases in build/aliases.js.

HTML

All HTML will exist within Vue components, either:

In the <template> of a .vue file

This will be the case for ~95% of HTML. What you're writing is "normal" HTML, but since Vue has a chance to parse it before the browser does, we can do a few extra things that normally aren't possible in a browser.

For example, any element or component can be self-closing:

<span class="fa fa-comment"/>

The above simply compiles to:

<span class="fa fa-comment"></span>

This feature is especially useful when writing components with long names, but no content:

<InputFileUpload
  title="Upload any relevant legal documents"
  description="PDFs or scanned images are preferred"
  icon="folder-open"
/>

Render functions are alternatives to templates. Components using render functions will be relatively rare, written only when we need either:

  • the full expressive power of JavaScript, or
  • better rendering performance through stateless, functional components

These components can optionally be written using an HTML-like syntax within JavaScript called JSX.

JavaScript

The JavaScript we use is compiled by stage 0 Babel, by way of Webpack. Configuration for Babel is in the .babelrc file at the root of this project and configurations for Webpack are in the .electron-vue folder, also at the root.

Babel allows us to write more modern JavaScript without having to worry about what's supported by Node/Chromium. If you're (relatively) new to features such as const, let, and => (arrow functions), take some time to read about the following features in Babel's ES2015 guide:

Reading these sections alone will get you 99% of the way to mastering Babel code. It's also a good idea to read about Promises, if you don't yet feel comfortable with them. Here's a good intro.

If you have any questions about any features, please don't hesitate to reach out, as it's obviously important that everyone understands our code and feels comfortable modifying it. πŸ™‚

Polyfills

Instead of using Babel's polyfills with babel-plugin-transform-runtime, we use the Polyfill.io service. This serves browser-specific polyfills, so that each visitor downloads the minimum code necessary to use the latest, polyfillable browser features.

Vue

Since Vue is such a huge part of our app, I strongly recommend every read through the Essentials of Vue's guide.

Vue Router

To understand how to manage pages with Vue Router, I recommend reading through the Essentials of those docs.

Vuex (state management)

To wrap your head around our state management, I also recommend reading through those docs, starting at What is Vuex? and stopping before Application Architecture. Then skip down and read Form Handling and Testing

(S)CSS

For our styles, we're using the SCSS modules, which you can activate by adding the lang="scss" and module attributes to style tags in Vue components:

<style lang="scss" module>
  /* Styles go here */
</style>

Otherwise, the tag is assumed to just contain normal CSS.

SCSS

SCSS is just a superset of CSS, meaning any valid CSS is also valid SCSS. This allows you to easily copy properties from other sources, very much in the CodePilot.ai spirit. πŸ˜„ It also means you can stick to writing the CSS you're still comfortable with while you're learning to use more advanced SCSS features.

I specifically recommend reading about:

Those are the features you'll use 99% of the time.

Global CSS

Only src/app.vue should contain global CSS and even that should only include base element styling and some utility classes (e.g. for grid management).

CSS Modules

As mentioned earlier, every Vue component will be a CSS module. That means the classes you define are not actually classes. When you write:

<!-- src/components/app-input.vue -->
<style lang='scss' module>
.inputLabel {
  /* ... */
}

.input {
  /* ... */
}
</style>

You're actually defining values on a $style property of the Vue instance such as:

$style: {
  inputLabel: 'app-input__inputLabel__3EAebB_0',
  input: 'app-input__inputLabel__3EAebB_1'
}

The values contain automatically generated classes with:

  • the name of the component
  • the name of the class
  • a random hash

Do you know what that means?! You can never write styles that interfere with another component. You also don't have to come up with clever class names, unique across the entire project. You can use class names like .input, .container, .checkbox, or whatever else makes sense within the isolated scope of the component.

Design variables

To import CSS from a Webpack alias, you must use the ~ prefix. So for example, to import design.scss, which is aliased to @design for convenience, you will write:

@import '~@design';

This makes all the variables in that file available in your component. These variables can also be made available in your JavaScript by placing them inside an :export in design.scss (see that file for more information).

Images, fonts, and other miscellaneous files

These will all go in the assets folder and can be accessed from each language's module system.

Importing assets in JavaScript

import logo from '@assets/images/logo.png'

Referencing assets in CSS

To access the @assets alias from CSS, you have to use the ~ prefix:

background-image: url('~@assets/images/logo.png');

Referencing assets in HTML

The ~ prefix is also necessary in HTML:

<img src="~@assets/images/logo.png" alt="Logo">

Tests

To run all the tests:

yarn test

Unit tests

yarn unit # Run all tests once
yarn unit:watch # Run tests and then

Unit tests are first-class citizens, meaning they live alongside our source code files. For example, to create unit tests for a file called, foo.js, you would create a file next to it called foo.unit.js.

Jest

We use Jest for our tests, which uses a Behavior-Driven Development (BDD) syntax that looks like this:

describe('thing you want to test', () => {
  it('what you expect it to do', () => {
    // ... Setup ...
    expect(...).toEqual(...)
  })
})

As for the assertions you can make, expecting a variable or property to have a specific value is just the tip of the iceberg. It's a good idea to skim the Jest docs for a more complete picture of the syntax.

vue-test-utils

To make it easier to test Vue components, we use Vue Test Utils. Check out the API docs and existing examples for details.

VS Code integration

Through a recommended extension in .vscode/extensions.json, VS Code users can automatically be notified in their editor of failing unit tests.

End-to-end tests

# Run the app in dev mode, alongside a graphical
# interface for your end-to-end tests, so that you
# can write and track tests as you develop.
yarn dev

# Run all end-to-end tests in headless mode, on a
# production build of your app.
yarn e2e

End-to-end tests are first-class citizens. Whenever we launch our app for development, a graphical interface for the end-to-end tests runs alongside them. That means tests are no longer an afterthought. If you break something, you know immediately. And instead of slowing down development, Cypress provides you with tools to speed up development and more quickly debug.

Cypress

We use Cypress for our end to end tests. If you've never used it before, don't worry. There's not too steep of a learning curve. It uses a BDD syntax inherited from Chai. See the documentation on assertions and commands for examples of the kinds of tests you can write. This kitchen sink spec also provides a lot of complete examples for a wide range of testing use cases, including mocking endpoints, creating fixtures, and testing responsive layouts.