strategy builder: frontend build

assumptions:

  • you know what github and javascript/Vue is
  • you know a bit about how Node/yarn works
  • you know/don't care about all the specifics of how webpack works
  • you don’t know how frontend stuff is built/runs

topics:

  • vue-build-system and what's in it
  • things that are magic (webpack)
  • design-system and how to connect
  • third party libraries (axios, brace, draggable)
  • brief overview of testing (maybe)

vue-build-system

what is it?

  • An Infusionsoft github repo that contains shared webpack and build configurations.
  • https://github.com/infusionsoft/vue-build-system 
  • When you run yarn dev in build system, you are running the dev-server configuration from the vue-build-system.
  • Package.json:
"scripts": {
    "dev": "node build/dev-server.js",
    ...
}

build/dev-server

The infusionsoft dev-server does most of the heavy lifting. It provides us:

  • Express app server
  • Wiring in of webpack
  • Hot reloading middleware

You can view it here:  https://github.com/infusionsoft/vue-build-system/blob/master/build/dev-server.js

const server = require('@infusionsoft/vue-build-system/build/dev-server.js');
const webpackConfig = require('./webpack.dev.config');

server.start(webpackConfig, 10229);

build/webpack.dev.config:

Infusionsoft’s webpack.dev.config pulls in the base config and then adds to it, enabling:

  • Source Maps

  • CDN wiring for webpack

  • Friendly errors plugin

 

const merge = require('webpack-merge');
const cdnOptions = require('./cdn');
const sharedDevWebpack = require('@infusionsoft/vue-build-system/build/webpack.dev.config')(cdnOptions);
const baseWebpack = require('./webpack.base.config');

module.exports = merge(sharedDevWebpack, baseWebpack);

The @infusionsoft/vue-build-system also handles:

  • Minifying/compressing code in prod

  • Vue and scss file compiling

  • Some eslinting

  • process.env.NODE_ENV js variable

vue-build-system - TL;DR:

  • It's what handles most of the stuff that runs when you run yarn dev
  • Contains things that you need to set up once when you start and then never touch
  • Cons: if it breaks it's hard to find out why
  • Pros: everyone is using it so it's everyone's problem

webpack

webpack

  • A popular third-party bundler/builder
  • takes all of your frontend assets (.vue files, .js files, images, .sass files, everything) and bundles them in a way that the browser can read and understand.
  • It also handles magical things like hot reloading.

Pros

  • It’s super powerful and solves all your bundling needs
  • There’s basically no competitors

Cons

  • There’s basically no competitors
  • It’s huge, and hard to understand re: magic
  • When it breaks it’s hard to debug (but there’s almost definitely something wrong with your config file(s)…
  • we have config files several in different places.

Important webpack things

  • Aliases
  • CDN
  • Minify

Aliases

Shortcut for the base location of where to find import definitions.

// build/webpack.base.config

const path = require('path');

module.exports = {
    resolve: {
        alias: {
            app: path.resolve('./src/app'),
            ...
        },
    },
    ...
};

then in your component...

import Component from 'app/components/Component';

CDN

  • “Content Delivery Network”
  • A place to put external resources (things you know will be needed by everyone using your project - example: Vue framework, vuex) and are easily cached/not going to be changed any time soon.
  • You put links to js files that are hosted on a CDN in webpack’s cdn configs, and make sure you mark them as “external” so webpack doesn’t try to package them with your app js files.

CDN

Remember in build?

// build/webpack.dev.config.js

const merge = require('webpack-merge');
const cdnOptions = require('./cdn');
const sharedDevWebpack = require('@infusionsoft/vue-build-system/build/webpack.dev.config')(cdnOptions);
const baseWebpack = require('./webpack.base.config');

module.exports = merge(sharedDevWebpack, baseWebpack);

CDN

// build/cdn.js

const path = require('path');

// get version from package.json
const version = (name) => {
    return require(path.join(__dirname, '../node_modules', name, 'package.json')).version;
};

// if in dev don't get the minified version
const min = process.env.NODE_ENV !== 'dev';
const minCheck = min ? '.min' : '';

// using unpkg.com for cdn; this is usually reliable
const cdnjs = [
    `//unpkg.com/vue@${version('vue')}/dist/vue${minCheck}.js`,
    `//unpkg.com/vuex@${version('vuex')}/dist/vuex${minCheck}.js`,
    `//unpkg.com/vue-router@${version('vue-router')}/dist/vue-router${minCheck}.js`,
    `//unpkg.com/vue-i18n@${version('vue-i18n')}/dist/vue-i18n${minCheck}.js`,
    `//unpkg.com/moment@${version('moment')}/min/moment-with-locales${minCheck}.js`,
];

const cdncss = [];

module.exports = {
    cdnjs,
    cdncss,
    externals: {
        vue: 'Vue',
        vuex: 'Vuex',
        'vue-router': 'VueRouter',
        'vue-i18n': 'VueI18n',
        moment: 'moment',
    },
};

If you want to externalize a script, you would do it here

Hot Reloading

  • the browser will reload source files that have been changed without you having to manually reload the page.
  • IMO this is one of the best/most useful features of webpack but it can also be the most temperamental.

Minify

  • Files should be minified/obfuscated in prod environments, to help with performance.
  • Check out vue-build-system webpack configs to see this code in action

webpack - TL;DR:

  • magic.gif
  • it does all the build things
  • there is a huge community
  • use on big projects that use frameworks and have multiple environments
  • hot reloading is the BEST

design-system

design-system

  • For all your design assets that are shared across products.
  • production link: https://infusionsoft.github.io/design-system
  • Go to Product -> components to see all the different components
  • Product -> Foundations has things like typography, colors, and icons.

 

How does it attach?

app/main.js

...
import Vue from 'vue';

const DesignSystem = require('@infusionsoft/design-system');

Vue.use(DesignSystem);
...

Now we have access to design system's

  • vue components (like Icon and Editable)
  • styles and sass vars (like $gp and $color-xxx)
  • js vue functions (like $error and $toast)

Making changes

TEST your design-system changes with the web app

design-system> yarn dist:debug // builds js/css bundle
design-system> yarn link // creates a symlinkable folder for d-s

your-project> yarn link @infusionsoft/design-system 
// symlinks to what was created
Your-project> yarn dev

You can look in node_modules/@infusionsoft/design-system to make sure your d-s changes are there

Then when you tweak d-s, run yarn dist:debug again and your changes should show up without having to restart your web server

Cutting a release

TL;DR:

  • Use semver
  • link to your PR in the notes of your release
  • Once the release is out, update package.json with the new design-system version.

design-system TL;DR:

  • It keeps things consistent across products
  • Making updates/keeping updated can be a pain but it's worth it

third party libraries

// package.json

"dependencies": {
    "@infusionsoft/design-system": "git+ssh://git@github.com/infusionsoft/design-system.git#~7.0.0",
    "axios": "0.16.2",
    "brace": "0.10.0",
    "fastclick": "1.0.6",
    "lodash.debounce": "4.0.8",
    "moment": "2.18.1",
    "vue": "2.5.9",
    "vue-i18n": "7.0.4",
    "vue-router": "2.7.0",
    "vuedraggable": "^2.14.1",
    "vuex": "3.0.1",
    "vuex-persistedstate": "2.4.2"
},

Axios

// app/main.js

...
import Vue from 'vue';
import axios from 'axios';

axios.defaults.headers.put['Content-Type'] = 'application/json;charset=UTF-8';
Vue.prototype.$http = axios;
...

Brace

  • https://github.com/thlorenz/brace
  • Browserify-compatible version of the Ace editor (syntax highlighter and formatter for code writing in the browser, currently used for HTML email writing)

FastClick

  • https://labs.ft.com/fastclick/
  • "FastClick is a simple, easy-to-use library for eliminating the 300ms delay between a physical tap and the firing of a click event on mobile browsers. The aim is to make your application feel less laggy and more responsive while avoiding any interference with your current logic."
// app/main.js

...
import FastClick from 'fastclick';
...

FastClick.attach(document.body);

Vue-draggable

// package.json

"dependencies": {
    "@infusionsoft/design-system": "git+ssh://git@github.com/infusionsoft/design-system.git#~7.0.0",
    "axios": "0.16.2",
    "brace": "0.10.0",
    "fastclick": "1.0.6",
    "lodash.debounce": "4.0.8",
    "moment": "2.18.1",
    "vue": "2.5.9",
    "vue-i18n": "7.0.4",
    "vue-router": "2.7.0",
    "vuedraggable": "^2.14.1",
    "vuex": "3.0.1",
    "vuex-persistedstate": "2.4.2"
},

strat builder package.json dependencies

Note: these are Dependencies and not
dev-dependencies, which are different.

TPL - TL;DR:

  • Don't re-invent the wheel
  • When you want to add a new one DEFINITELY let people know PLEASE - slack channel #dev-frontend
  • The biggest problem with TPL is unknown breakages; Don't update the version without researching
  • yarn lock is your friend

testing

Libraries used in frontend unit tests

  • Mocha  it's the test framework: the 'describe' and 'it' parts.
  • Karma  it runs the tests on a browser When you run npm test or yarn test, it's probably pointing to karma for running them.
  • Chai  it's the expectation library. so in Chai you would say
    • expect(myThing) .to.equal(thisThing).
    • If you were using Jasmine (a different expectation library) you'd say expect(myThing) .toEqual(thisThing), like some kind of animal.
  • Sinon  the mocking / spying library. It's great for unit testing / stubbing out functions that you don't want to run, but you want to see if that function was called.
  • vue-testing-utils  Frameworks for mounting / shallow mounting vue components for testing.

How are the tests run?

  • README - how to run tests

  • look at test command in package.json

  • go to karma.config.js

  • files: index.js

Writing good frontend tests

TL;DR:

Made with Slides.com