@defstudio/vite-livewire-plugin
Version:
Livewire plugin for Vite
241 lines (216 loc) • 9.45 kB
JavaScript
import { minimatch } from "minimatch";
const defaultWatches = [
"**/resources/views/**/*.blade.php",
"**/app/**/Livewire/**/*.php",
"**/app/**/Filament/**/*.php",
"app/View/Components/**"
];
const defaultConfig = {
watch: defaultWatches,
refresh: [],
bottomPosition: 10
};
function triggerUpdates(ctx, refreshList) {
const updates = [];
for (const path of refreshList) {
let type;
if (path.endsWith("css")) {
type = "css-update";
} else if (path.endsWith("js")) {
type = "js-update";
} else {
continue;
}
updates.push({
type,
path,
acceptedPath: path,
timestamp: (/* @__PURE__ */ new Date()).getTime()
});
}
if (updates.length > 0) {
ctx.server.ws.send({
type: "update",
updates
});
}
}
function refresh(ctx, config) {
ctx.server.ws.send({
type: "custom",
event: "livewire-update",
data: {
blade_updated: ctx.file.endsWith(".blade.php")
}
});
}
function resolvePluginConfig(config) {
if (typeof config === "undefined") {
config = defaultConfig;
}
if (typeof config === "string") {
config = [config];
}
if (Array.isArray(config)) {
const watch = config;
config = { ...defaultConfig };
config.watch = watch;
}
if (typeof config.refresh === "undefined") {
config.refresh = defaultConfig.refresh;
}
if (typeof config.refresh === "string") {
config.refresh = [config.refresh];
}
if (typeof config.watch === "undefined") {
config.watch = defaultConfig.watch;
}
if (typeof config.watch === "string") {
config.watch = [config.watch];
}
if (typeof config.bottomPosition === "undefined") {
config.bottomPosition = defaultConfig.bottomPosition;
}
return config;
}
function livewire(config) {
const typoVirtualModuleId = "virtual:tailwind-hot-reload";
const virtualModuleId = "virtual:livewire-hot-reload";
const resolvedVirtualModuleId = "\0" + virtualModuleId;
const pluginConfig = resolvePluginConfig(config);
return {
name: "Tailwind Plugin",
pluginConfig,
resolveId(id) {
if (id === virtualModuleId || id === typoVirtualModuleId) {
return resolvedVirtualModuleId;
}
},
load(id) {
if (id === resolvedVirtualModuleId) {
return `
let lastLivewireUpdate = 0;
function initConflictingReloadCheck() {
window.onload = function () {
if (sessionStorage.getItem("livewire_hot_reload_conflict") === '1') {
console.error("" +
"[vite] Another Vite plugin reloaded the page whilst " +
"defstudio/vite-livewire-plugin was refreshing a Livewire component. " +
"For optimal results, disable full page reloads when " +
"defstudio/vite-livewire-plugin is enabled. " +
"For more info, visit out docs: https://github.com/def-studio/vite-livewire-plugin");
}
sessionStorage.setItem("livewire_hot_reload_conflict", '0');
window.addEventListener("beforeunload", () => {
const now = (new Date()).getTime();
if (now - lastLivewireUpdate > 200) {
return;
}
sessionStorage.setItem("livewire_hot_reload_conflict", '1');
});
};
}
function makeOptInCheckbox() {
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.style.cssText = "width: 12px; height: 12px; cursor: pointer";
checkbox.id = "livewire_hot_reload";
checkbox.checked = (sessionStorage.getItem("livewire_hot_reload") ?? "1") === "1";
sessionStorage.setItem("livewire_hot_reload", checkbox.checked ? "1" : "0");
console.log("[vite] livewire hot reload " + (checkbox.checked ? "enabled." : "disabled."));
checkbox.addEventListener('change', event => {
const eventTarget = event.currentTarget;
if (eventTarget === null) {
return;
}
if (eventTarget instanceof HTMLInputElement) {
sessionStorage.setItem("livewire_hot_reload", eventTarget.checked ? "1" : "0");
console.log("[vite] livewire hot reload " + (eventTarget.checked ? "enabled." : "disabled."));
}
});
return checkbox;
}
function makeOptInLabel() {
const debugbarHeight = document.querySelector('.phpdebugbar, .clockwork-toolbar, .sf-toolbar')?.offsetHeight ?? 0;
const defaultBottomPosition = ${pluginConfig.bottomPosition};
const calculatedBottomPosition = debugbarHeight + defaultBottomPosition
const label = document.createElement('label');
label.style.cssText = "position: fixed; bottom: "+calculatedBottomPosition+"px; right: 10px; font-size: 12px; cursor: pointer";
label.innerHTML += "Livewire Hot Reload ";
return label;
}
function injectOptInCheckbox() {
const label = makeOptInLabel();
// noinspection JSCheckFunctionSignatures
label.append(makeOptInCheckbox());
window.document.body.insertBefore(label, window.document.body.lastChild);
}
export function livewire_hot_reload() {
if (import.meta.hot) {
initConflictingReloadCheck();
if (import.meta.env.VITE_LIVEWIRE_OPT_IN) {
injectOptInCheckbox();
} else {
console.log("[vite] livewire hot reload enabled.");
}
import.meta.hot.on('livewire-update', data => {
// noinspection JSUnresolvedVariable
if (typeof Livewire === "undefined" || (Livewire.components !== undefined && Object.keys(Livewire.components).length === 0) || (Livewire.components === undefined && Object.keys(Livewire.all()).length === 0)) {
console.log("[vite] full reload...");
location.reload();
return;
}
const checkbox = window.document.getElementById("livewire_hot_reload");
if (checkbox && !checkbox.checked) {
if (!data.blade_updated) {
return;
}
console.log('[vite] full reload...');
location.reload();
return;
}
if(Livewire.components === undefined){
Livewire.all().forEach(component => component.$wire.call('$refresh'));
}else{
for (const componentId in Livewire.components.componentsById) {
const component = Livewire.components.componentsById[componentId];
component.call('$refresh');
}
}
lastLivewireUpdate = (new Date()).getTime();
console.log('[vite] livewire hot updated.');
});
}
}
`;
}
},
handleHotUpdate(ctx) {
if (minimatch(ctx.file, "**/storage/framework/views/**/*.php")) {
return [];
}
for (const pattern of pluginConfig.watch) {
if (minimatch(ctx.file, pattern)) {
const refreshList = [...pluginConfig.refresh.filter((path) => {
if (ctx.modules.length === 0 || !ctx.modules[0]) {
return true;
}
let includeInRefresh = true;
ctx.modules[0].importers.forEach((importer) => {
includeInRefresh = !importer.file?.endsWith(path);
});
return includeInRefresh;
})];
triggerUpdates(ctx, refreshList);
refresh(ctx, pluginConfig);
return [...ctx.modules[0]?.importers ?? [], ...ctx.modules.slice(1)];
}
}
}
};
}
export {
livewire as default,
defaultConfig,
defaultWatches
};