Dear VueJS devs, VeeValidate might not be worth it
Sdu
Posted on November 24, 2018
In fact, I am not leaving Vuelidate out of this. I wanted to validate user input upon registration/signup so I knew it was best I used a tried and tested package to do validation for me.
Vuelidate is apparently great but...
Although not so much when you're using typescript like me. I'll get into that later but long story short, it was a nightmare trying to get it working with me.
VeeValidate is, I guess, the best. It's just that...
When running npm build
and get a warning that my entry bundle exceeds the recommended size, I panick. See I get paranoid about performance because its those type of choices I make on my project that I think reflects my character as a programmer, others being security and accessibility.
Out of the two libraries I've mentioned, Vuelidate had typing issues when integrated with with a typescript project. An issue that has been posted several times and with possible solutions by devs. In short, there's a passage/rant here that sums up the problem. The part that got to me is the quote below.
There are more issues on GitHub talking about TypeScript integration, and again multiple devs try to kickstart adding typings to the project, providing proof of concepts or first versions over the course of months. Again, the repo owner gets excited. Two months ago, he once again states that he's going to "roll out the typings into the offical package soon". Until today, nothing happened though.
Interestingly enough, thats the same post that introduced me to VeeValidate. And I was happy with its implementation and ease of use until I viewed the build output.
Throughout my whole project, I'm only validating 4 input fields and thats it. But VeeValidate being bundled is larger than all other node_modules packages bundled in my app. Even larger than Vue by at least 1/3rd if not more. I tried lazy loading it but it wasn't being injected into the component that was using it.
Of course the creators acknowledged [this and even provide possible solutions for it(https://baianat.github.io/vee-validate/concepts/bundle-size.html#minimal-bundle) BUT I went through all this not planning to solve problems of solutions that I was looking for.
The answer to my problems was right in front of me already though.
v-bind | computed properties| regex
<input
type="text"
name="email"
@blur="touch('email')"
:class="{error: !emailValid}"
placeholder="Email"
v-model="email">
Along with other fields, when it looses focus, that means it has been touched. So
private touch(item: string) {
this.validate = true;
if (!this.dirty.includes(item)) {
this.dirty.push(item);
}
}
And to show an error in the input field I check whether it has been touched (dirty) and whether whatever input given match the email pattern.
private get emailValid() {
if (this.dirty.includes('email')) {
const valid = /^([\w\.]+@[a-zA-Z_]+?(\.[a-zA-Z]{2,6}){1,2})$/.test(this.email);
if (valid) {
this.dirty.splice(this.dirty.indexOf('email'));
}
return valid;
}
return true;
}
So as inspired by other validators, to get insight, I compute a list of errors like so
private get errors(): string[] {
const field: string[] = [];
if (!this.namesValid) {
field.push('names');
}
if (!this.emailValid) {
field.push('email');
}
if (!this.passwordValid) {
field.push('password');
}
if (!this.passwordConfirmed) {
field.push('password_confirm');
}
return field;
}
But this alone is not enough. Having not touched the input field doesn't mean that they are still valid and to solve that, I must do another check
private get empty(): string[] {
const field: string[] = [];
if (this.names.length === 0) {
field.push('names');
}
if (this.email.length === 0) {
field.push('email');
}
if (this.password.length === 0) {
field.push('password');
}
if (this.pwd2.length === 0) {
field.push('password_confirm');
}
return field;
}
And then finally, when the form is submitted, I wrap up everything together here
private signUp(): void {
if (this.loading) {
return;
}
if (this.empty.length !== 0) {
return;
}
if (this.errors.length !== 0) {
return;
}
this.loading = true;
createUser(this.names, this.email, this.password)
.then((response) => {
this.toSignin();
})
.catch(this.handleNetworkError);
}
}
To conclude
I know that I might be made misinformed on some details of the libraries I mentioned and maybe my solution is not as good as them but it was worth reinventing this wheel. I shedded milliseconds off load time for most well-off potential visitors to the site, and I definitely shedded a second plus some change for the next billion users
Posted on November 24, 2018
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.