Andrew Welch
Published , updated · 5 min read · RSS Feed
Please consider 🎗 sponsoring me 🎗 to keep writing articles like this.
A Little Taste of Petite-Vue
Petite-Vue is a tiny 5.8kb JavaScript library that gives you the power of Vue.js, but slimmed down & optimized for sprinkling small bits of interaction on your web pages
Many web developers want to add some interactivity to their web pages, but using a full framework like React or Vue.js or Svelte is overkill for them, and jQuery or vanilla JS isn’t quite enough.
This is especially true of server-rendered HTML systems, such as Craft CMS, Laravel, Statamic, Ruby on Rails, etc. where much of the “state” is controlled by the backend.
If this sounds like you, I have fantastic news: Petite-Vue is for you!
Petite-Vue bills itself as a micro-framework (only 5.8kb in size) that is optimized for progressive enhancement, allowing you to “sprinkle” interactivity on the frontend of pages rendered by a server-side backend.
If this sounds somewhat like Alpine.js, then you’re right! Alpine.js is a fantastic framework with goals similar to Petite-Vue, but there are some advantages of using Petite-Vue that we’ll explore in this article.
Link Petite-Vue vs. Alpine.js
True to its name, Petite-Vue is a slimmed-down version of the popular Vue.js frontend framework. Check out the Comparison with standard Vue section of the Petite-Vue repository if you want to see a breakdown of the actual differences.
Like Alpine.js, it can be used without a build step or bundling process at all, just include the CDN link and away you go:
<script src="https://unpkg.com/petite-vue" defer init></script>
The biggest advantage of Petite-Vue is its pedigree. Because the API is Vue compatible, good things can happen:
- If you don’t know Vue.js, learning Petite-Vue is learning a subset of Vue, which opens up a much larger world to you
- If you do know Vue.js already, then using Petite-Vue on projects will allow you to hit the ground running, without having to learn new syntax
- If you start a project with Petite-Vue, and the requirements change, moving it to full-blown Vue.js gives you a very smooth migration path rather than a dead-end
- You can leverage a large, existing ecosystem of documentation, knowledge, and code that exists already for Vue.js
- You will have an easier time hiring people who have Vue knowledge to work on your project (or getting yourself hired based on your Vue knowledge)
- Petite-Vue is written in TypeScript, so even if you don’t use TypeScript, you’ll get the auto-completion of types & functions in your text editor. Alpine.js is written in JavaScript, and has no type definitions (yet!)
These are the reasons why adopting Petite-Vue may make sense for you.
We’re going to test exactly how easy these theoretical points are in practice in this article, so read on!
Link Using Petite-Vue + GraphQL to make practical magic
This article isn’t going to teach you Petite-Vue; if you’re looking for that, check out the Petite-Vue documentation or Dave Rupert’s My petite-vue review article.
Rather we’re going to revisit an older article I wrote entitled Using VueJS + GraphQL to make Practical Magic, which shows how to build a simple Vue.js autocomplete field with GraphQL.
The article was written with Craft CMS as a backend in mind, but that’s not particularly relevant for our purposes. Anything that has a GraphQL API should work by just tweaking a few things.
We’re going to take this Vue.js autocomplete component, and convert it over to Petite-Vue!
Here’s what the end-result looks like:
I’ve resisted the temptation to improve upon the code from the older article, preferring to keep it as to make the comparison as direct as possible.
Also to keep things simple, I’m just using Bootstrap & Axios from a CDN for the styling and XHR’s:
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
Link GraphQL JavaScript preamble
The autocomplete component has some setup code that I’m calling the “GraphQL JavaScript preamble”:
// Information needed for connecting to our CraftQL endpoint
const apiToken = 'vX45NkKh9jPQ2dBGbYnhcq3YR1mTRhzf';
const apiUrl = '/api';
// What to search for
const searchSections = ['blog'];
const searchPrefix = 'title:';
// The query to search for entries in Craft
const searchQuery =
`
query searchQuery($sections: [String], $needle: String!, $limit: Int)
{
entries(section: $sections, search: $needle, limit: $limit) {
title
url
}
}
`;
// Configure the api endpoint
const configureApi = (url, token) => {
return {
baseURL: url,
headers: {
'Authorization': `Bearer ${token}`,
'X-Requested-With': 'XMLHttpRequest'
}
};
};
// Execute a GraphQL query by sending an XHR to our api endpoint
const executeQuery = (api, query, variables, callback) => {
api.post('', {
query: query,
variables: variables
}).then((result) => {
if (callback) {
callback(result.data);
}
console.log(result.data);
}).catch((error) => {
console.log(error);
})
};
It just has a few constants for defining the API token, GraphQL API URL, etc., and the GraphQL query that we’ll be sending along to the backend to return the results. Feel free to adjust this query as you see fit.
This code needed zero changes from the original article to adapt it to Petite-Vue.
Link HTML for the autocomplete search component
Next up we have the HTML for the autocomplete search component (often referred to as a “template” in Vue parlance):
<form id="demo" autocomplete="off">
<div class="form-group">
<label for="searchQuery">Search:</label>
<input v-model="searchQuery" v-on:keyup="performSearch()" id="searchQuery" class="form-control" type="text" />
</div>
<div class="form-group">
<ul class="list-group">
<li v-for="(searchResult, index) in searchResults" class="list-group-item">
<a v-bind:href="searchResult.url">{{ searchResult.title }}</a>
</li>
</ul>
</div>
<div class="form-group">
<pre>data: {{ searchResults }}</pre>
</div>
</form>
Check out the original article if you want a more detailed explanation of what the various directives here are, but it’s a basic search field with a display of autocomplete results from the GraphQL API (if any) below it.
This code needed zero changes from the original article to adapt it to Petite-Vue.
Link The autocomplete search component
Here’s the original Vue 2.x autocomplete search component from the original article:
// Instantiate our Vue instance
new Vue({
el: '#demo',
data: {
searchApi: axios.create(configureApi(apiUrl, apiToken)),
searchQuery: '',
searchResults: {}
},
methods: {
// Perform a search
performSearch() {
// If they haven't entered anything to search for, return nothing
if (this.searchQuery === '') {
this.searchResults = {};
return;
}
// Set the variables we will pass in to our query
const variables = {
sections: searchSections,
needle: searchPrefix + this.searchQuery,
limit: 5
};
// Execute the query
executeQuery(this.searchApi, searchQuery, variables, (data) => {
this.searchResults = data.data.entries;
});
}
}
})
To adapt this to Petite-Vue, what we needed to do is essentially “flatten” the object that we’re using, combining all of the data, methods, etc. into a single object. Here’s what it looks like in Petite-Vue:
// The actual petite-vue component
import { createApp } from 'https://unpkg.com/petite-vue?module'
createApp({
// data
searchApi: axios.create(configureApi(apiUrl, apiToken)),
searchQuery: '',
searchResults: {},
// methods
performSearch() {
// If they haven't entered anything to search for, return nothing
if (this.searchQuery === '') {
this.searchResults = {};
return;
}
// Set the variables we will pass in to our query
const variables = {
sections: searchSections,
needle: searchPrefix + this.searchQuery,
limit: 5
};
// Execute the query
executeQuery(this.searchApi, searchQuery, variables, (data) => {
this.searchResults = data.data.entries;
});
}
}).mount('#demo');
The changes boil down to removing the data: and methods: keys in the object we’re returning, and then using the Vue.js 3.x createApp() and .mount() syntax for creating & mounting our component to exiting DOM elements.
That’s it! It was quite straightforward, which I found very satisfyingly surprising.
It really was just moving the furniture around a little bit, the core code stayed the same.
Link What about going to full Vue.js?
So okay, that shows pretty clearly how existing domain knowledge can transfer both ways between Petite-Vue and full Vue.js.
But what about the claim that if we were working on a project using Petite-Vue, and the scope changed, we could easily adapt it to full Vue.js instead? How easy of a transition would that be?
Let’s have a look at the Vue.js 3.x version of the same component:
// The actual vue component
import { createApp } from 'https://unpkg.com/vue@3.2.4/dist/vue.esm-browser.js'
createApp({
// data
data: () => ({
searchApi: axios.create(configureApi(apiUrl, apiToken)),
searchQuery: '',
searchResults: {},
}),
// methods
methods: {
performSearch() {
// If they haven't entered anything to search for, return nothing
if (this.searchQuery === '') {
this.searchResults = {};
return;
}
// Set the variables we will pass in to our query
const variables = {
sections: searchSections,
needle: searchPrefix + this.searchQuery,
limit: 5
};
// Execute the query
executeQuery(this.searchApi, searchQuery, variables, (data) => {
this.searchResults = data.data.entries;
});
}
}
}).mount('#demo');
The only differences here are we change the script that we’re importing from Petite-Vue to Vue 3.x, and we’re moved our “flattened” config object back into data: and methods: keys in the object we return.
That’s it. I find that to be very compelling.
Link Stepping Stone
Similar to Alpine.js, for many projects, Petite-Vue solves the “Goldilocks” problem in spades, being the fit that is just right.
However, Petite-Vue has the added superpower of an API that is compatible with its bigger brother Vue.js, which I think has many benefits in the long term.
In that way, I consider it to be the perfect amuse-bouche for many of my projects.
We also talk about Petite-Vue on a CraftQuest.io live stream, if you want to check that out!