statamic / cms

The core Laravel CMS Composer package
https://statamic.com
Other
3.98k stars 523 forks source link

Live Preview breaking only in Production control panel when trying to render a Vue component #10960

Open fixr-austin opened 1 day ago

fixr-austin commented 1 day ago

Bug description

When adding a Set that contains a Vue component to my Bard, the Live Preview screen breaks and goes blank. This issue only happens in the Production control panel Live Preview screen. When working locally, the Live Preview displays the Set just fine, and I see all the expected data and functionality. When visiting the actual Live URL on the Production server (while the Set is active), everything looks fine and works as expected. The only error log I get is from the console: Console log: site.js TypeError: Cannot read properties of null (reading 'nextSibling') No errors produced in the laravel log.

Screenshot 2024-10-15 at 1 22 16 PM

As a work-around, I am currently wrapping the Vue component with an {{ if live_preview }}, but this is not ideal, as I would like my control panel users to see the actual data in the live preview screen.

company_cards.antlers.html

{{ if live_preview }}
    <div class="rounded-lg bg-slate-100 border border-slate-300 p-5 text-center capitalize animate-pulse">
        Company Cards for {{ (state === 'slug') ? (last_segment) : (state) }}
    </div>
{{else}}
    <company-cards
        slug="{{ state === 'slug' ? last_segment : state }}"
        advanced-options="{{advanced_options | to_json | entities}}"
    ></company-cards>
{{ /if}}

site.js

import { createApp } from 'vue/dist/vue.esm-bundler';
import {defineAsyncComponent} from "vue";

const app = createApp({});

const CompanyCards = defineAsyncComponent(() => import("./vue/components/CompanyCards.vue"));
app.component('company-cards', CompanyCards);

app.mount('#app');

CompanyCards.vue

<template>
    <div>
        <div v-if="loading">
            <loading-animation text="Loading Companies"></loading-animation>
        </div>
        <div v-else>
            <div class="grid md:grid-cols-2 gap-8 not-prose my-8">
                <div v-for="company in companies" class="rounded-lg bg-slate-100 border border-slate-300 p-5">
                    <h4 class="font-bold mt-0 mb-1 text-lg text-slate-900">{{ company.name }}</h4>
                    <p class="inline-flex items-center gap-2">
                        <svg width="15" height="18" viewBox="0 0 15 18" fill="none" xmlns="http://www.w3.org/2000/svg">
                            <path fill-rule="evenodd" clip-rule="evenodd" d="M2.82541 2.61078C4.13823 1.29796 5.9188 0.560425 7.77541 0.560425C9.63202 0.560425 11.4126 1.29796 12.7254 2.61078C14.0382 3.9236 14.7758 5.70417 14.7758 7.56078C14.7758 9.41739 14.0382 11.198 12.7254 12.5108L7.77541 17.4608L2.82541 12.5108C2.17532 11.8608 1.65964 11.0891 1.30781 10.2397C0.955986 9.39041 0.774902 8.4801 0.774902 7.56078C0.774902 6.64147 0.955986 5.73116 1.30781 4.88183C1.65964 4.03251 2.17532 3.2608 2.82541 2.61078ZM7.77541 9.56078C8.30584 9.56078 8.81455 9.35007 9.18962 8.97499C9.56469 8.59992 9.77541 8.09121 9.77541 7.56078C9.77541 7.03035 9.56469 6.52164 9.18962 6.14657C8.81455 5.7715 8.30584 5.56078 7.77541 5.56078C7.24497 5.56078 6.73627 5.7715 6.36119 6.14657C5.98612 6.52164 5.77541 7.03035 5.77541 7.56078C5.77541 8.09121 5.98612 8.59992 6.36119 8.97499C6.73627 9.35007 7.24497 9.56078 7.77541 9.56078Z" fill="#6DC300"/>
                        </svg>
                        {{company.office_locations?.[0]?.city ?? 'N/A'}}
                    </p>
                    <div class="flex justify-between items-center mt-3">
                        <div>
                            <rating-meter :rating="company.overall_expert_rating"></rating-meter>
                        </div>
                        <a class="btn-primary-sm block">Get Quote</a>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script setup>
import {onMounted, ref} from "vue";
import LoadingAnimation from "./LoadingAnimation.vue";
import RatingMeter from "./RatingMeter.vue";
import {ApiService} from "../../services/api.js";

const props = defineProps({
    slug: {
        type: String,
        default: ''
    },
    advancedOptions: {
        type: String,
        default: ''
    }
})

const apiService = new ApiService()
const loading = ref(true)
const companies = ref({})

onMounted(() =>{
    getCompanies()
})
function getCompanies() {
    apiService.getCompanies(props.slug, props.advancedOptions)
        .then((res) => {
            companies.value = res.data.data
        })
        .catch(error => {
            console.error('Error fetching data:', error)
            this.error = error
        })
        .finally(() => {
            loading.value = false
        })
}
</script>

<style scoped>

</style>

How to reproduce

Logs

No response

Environment

Environment
Application Name: SQ
Laravel Version: 11.25.0
PHP Version: 8.3.9
Composer Version: 2.7.7
Environment: local
Debug Mode: ENABLED
URL: localhost
Maintenance Mode: OFF
Timezone: UTC
Locale: en

Cache
Config: NOT CACHED
Events: NOT CACHED
Routes: NOT CACHED
Views: CACHED

Drivers
Broadcasting: log
Cache: file
Database: sqlite
Logs: stack / single
Mail: log
Queue: sync
Session: file

Statamic
Addons: 3
Sites: 1
Stache Watcher: Disabled
Static Caching: Disabled
Version: 5.27.0 PRO

Statamic Addons
alt-design/alt-redirect: 1.3.2
jacksleight/statamic-bard-texstyle: 3.3.0
ndx/statamic-bard-color-picker: 2.0.0

Installation

Existing Laravel app

duncanmcclean commented 1 day ago

site.js TypeError: Cannot read properties of null (reading 'nextSibling')

This looks like an error coming from your JS, rather than JS included in Statamic. What does the Vue component look like?