The simplicity of using Vue’s reactivity system outside of Vue

tldr; Vue’s reactivity can be imported and used in JS outside of a Vue app, like in Node directly.

Simon Le Marchant
6 min read ·

Creative programming.

Vue is described as “incrementally adoptable”, which is what drew me to it years ago. In now-ancient projects (let’s say 5 or 6 years ago), I incorporated Vue 2 by just dropping a CDN script tag in my HTML, and then copy/pasting a boilerplate block of code to mount to #app. In a few lines of code, I had reactivity. To be able to do this is what made Vue a library in my head canon. It wasn’t opinionated, outside of using the Options API structure.

Nowadays, things are a little different, but the mindset of keeping Vue incrementally adopted has remained. Vue 3 and the Composition API not only makes massive strides forward for Vue apps, but actually allows us to cherry-pick out the reactivity features of Vue and use them in other places. The Vue core library actually has a package explicitly for this, @vue/reactivity. Or if you want even more, you can just bring in the full vue@latest.

A simple example: using Vue reactivity in Node

Let's jump in with a simple yet effective example, using reactivity in a plain Node script.

// node entry.js

const { ref, computed, watchEffect } = require('vue'); // CommonJS require

const number = ref(0);

watchEffect(() => {
    console.log(number.value);
});

setInterval(() => {
    number.value += 1;
}, 1000);

// Prints
// 1
// 2
// 3
// etc...

This isn’t novel, in fact it’s absurdly obvious if you spend even a moment thinking about it - but up until now, I never had a reason to; and I’d argue most haven’t either.

Hell at first glance you’d think you were looking at a <script setup> tag, but nope, this is just a top-level JavaScript file, being ran by Node (or Bun/Deno if you’re inclined to use those).

Thinking outside of the box

With this example in mind, we can quickly get creative. Take, for example, a Raspberry Pi. This little device is capable of running JavaScript through a Node.js environment, and thus can benefit from Vue's reactivity.

Picture a home automation system where reactive data handles sensor input changes, turning lights on or off, or even managing a garden's watering schedule — all with reactivity powered by Vue.

const { ref, watch } = require('vue');

// Reactive state
const temperature = ref(75); // in degrees (F)
const soilMoisture = ref(30); // in percentage
const lightsOn = ref(false);
const isWatering = ref(false);

// Simulate sensor data change
setTimeout(() => {
    temperature.value = 22; // Temperature rises
    soilMoisture.value = 15; // Soil moisture drops
}, 3000);

// Turn the lights on if the temperature is too high
watch(temperature, (newTemp) => {
    lightsOn.value = newTemp > 78;
});

// Water the plant if the soil is too dry
watch(soilMoisture, (newMoisture) => {
    isWatering.value = newMoisture < 20;
});

This straightforward example keeps things local to Node, but you can easily see how you might use a serial port or another communication method to interact with IOT devices based on actions triggered by Vue’s reactivity. Some other examples that pop to mind include data synchronization and workflow automation - anywhere where you can run JS and may not need a full UI framework.