Abdelrahman Awad
Frontend Engineer @Robusta Studio
Open-source contributor and creator of vee-validate
An open-source library for Vue.js that offers client-side validation
GH Stars | Monthly Downloads | Releases | Commits |
---|---|---|---|
7,100 | 530,000 | 134 | 3,148 |
Early 2016
Early 2016 Code
function updateMessage(el, vm) {
vm.errors = Object.assign({}, vm.errors, {
[el.name]: el.validationMessage
});
}
export const ValidateMixin = {
data: () => ({
errors: {}
}),
computed: {
hasErrors() {
// Check if we have errors.
return Object.keys(this.errors).some(key => {
return !!this.errors[key];
});
}
},
directives: {
validate: {
bind(el, _, vnode) {
const vm = vnode.context;
el.addEventListener("input", e => {
updateMessage(e.target, vm);
});
vnode.context.$on("validate", () => {
updateMessage(el, vm);
});
}
}
},
methods: {
validate() {
this.$emit("validate");
}
}
};
So I searched for a package in Vue.js ecosystem that satisfied my needs
There was `vue-validator` but it wasn't actively maintained due to the author working on vue-i18n.
So I decided to build one
Also called the "Niche market"
Lesson #1
I didn't plan that, I learned that after the fact
Lesson #1: Revised
And it wasn't easy
Vue.js lifecycle
ES6 Promises
And of course....
Vue.js Reactivity
Input Events
Prototypes
Vue.js Rendering Mechanism
JavaScript concurrency
β
β
Lesson #2
React at its simplest level is a rendering layer/organization tool, it lets you describe your application in the form of simple primitives called components
Accepted Every New Feature PR
Implemented every feature-request
I was happy everyone was using my library and I intended to keep it that way, that affected how I see things and cost me a lot down the line
Bundle size went from 55kb to 178kb in under a year
It stayed hovering around that size for another year
So I slowed everyone's apps for around:
1.02s
2G
0.62s
3G
Webpack: Most Popular
Rollup: Was relatively New
Rolling your own bundler with Babel
Browserify: Very limited
Lesson #3
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["VeeValidate"] = factory();
else
root["VeeValidate"] = factory();
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // identity function for calling harmory imports with the correct context
/******/ __webpack_require__.i = function(value) { return value; };
/******/ // define getter function for harmory exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ };
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 32);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
"use strict";
console.log('hello world!');
The cost of running JavaScript
Lesson #4
Why do we even test?
π Confidence
β Backward Compatibility
π Catching Bugs
π€ For contributors
Test Runner
Regression Tests
E2E Tests
Code Coverage
Integration Tests
Unit Tests
Coverage is not a goal its a metric
Start with integration tests
test('listens for input, blur events to set flags', async () => {
const wrapper = mount(
{
data: () => ({
value: ''
}),
template: `
<ValidationProvider rules="required" v-slot="{ errors, ...rest }">
<input v-model="value" type="text">
<li v-for="(flag, name) in rest" v-if="flag" :id="name">{{ name }}</li>
</ValidationProvider>
`
},
{ localVue: Vue, sync: false }
);
const input = wrapper.find('input');
expect(wrapper).toHaveElement('#untouched');
expect(wrapper).toHaveElement('#pristine');
});
With Pure Unit tests I had 300+ tests with 90% coverage
Right now I have a mix of mostly integration tests and some unit tests with a total of 123 tests with 95% coverage
Major
π
Minor
π€©
Patch
π΄
Β Those who use GitHub issues correctly and those who don't
Be patient, there might be a bug.
Don't be dismissive, be appreciative even if you are going to close the issue/PR
If someone is being rude, make it clear that they are overstepping and close/lock the issue.
Always ask for a reproduction via online sandbox tools or an online repo
Use issue templates and Template replies to save time
Reading the manual is one thing, but what about....
Verbosity
Tone
Great read: https://developers.google.com/style
Content
Great read: https://developers.google.com/style
Don't pre-annoucnce stuff
Categorize by Topic and Sub-topics
Great read: https://developers.google.com/style
Always include code snippets and live examples if possible
Marketing
Finding Time
Funding
Attracting Contributors