We try to save time for everyone in our team, not only developers: some people spend a lot of time configuring our app for clients or demos, so we make sure it's as smooth as possible. For instance, we try to make every change real time, so there's no need to reload the app for changes to appear.
Recently, we figured out those people usually work with multiple tabs open, making sure the configuration works as expected in multiple pages of the app. So we thought about syncing the configuration across tabs.
We didn't want to store it, neither in session, local storage or anything else, as we will then have to make sure it's always up to date.
That's when we came across the BroadcastChannel API, I didn't even know it existed. It's not fairly new, but Safari was the last to implement it according to CanIUse. Anyway it's largely supported now. You can think of it like the good old window.postMessage()
from iframe
, but across multiple tabs of the same origin.
Luckily for us, VueUse already made a little composable to ease its usage: https://vueuse.org/core/useBroadcastChannel/#usebroadcastchannel
const {
isSupported,
channel,
post,
close,
error,
isClosed,
} = useBroadcastChannel({ name: 'unique-name' })
So we created a little in house composable based on it to make sure a ref
is always synchronized among all tabs:
import { useBroadcastChannel, watchPausable } from '@vueuse/core';
import { nextTick, watch } from 'vue';
import type { Ref } from 'vue';
export const useSync = <T>(value: Ref<T>, name: string, options?: { immediate?: boolean; deep?: boolean }) => {
// Name must be unique
const { post, data } = useBroadcastChannel<T, T>({ name });
// When value changes locally, update other tabs
const { pause, resume } = watchPausable(
() => value.value,
(newValue) => {
post(structuredClone(newValue));
},
options,
);
// When value changes in another tab, update it locally
watch(
() => data.value,
async (newValue) => {
// Prevent watch loop when updating config
pause();
value.value = newValue;
await nextTick();
resume();
},
options,
);
};
So now we can sync a ref with a single line:
const config = ref({})
useSync(config, 'config', { deep: true });
And voilà! That's some hours saved each month across teams 🥳
Top comments (0)