תרגיל vue.js - מה שבור בקומפוננטה
את הבאג הזה מצאתי במקרה בקוד אמיתי שהשתמש בגרסה ישנה של הספריה ומאחר והוא לקח לי איזה שעתיים מהחיים חשבתי שהוא מצדיק גם פוסט. צריך להגיד ביושר שהאתגר היה להבין שיש בעיה בקומפוננטה חיצונית שבעצמה נטענה מתוך קומפוננטה חיצונית ואתם מקבלים פה רק את הצעד האחרון של האתגר.
מוכנים? הנה קוד קומפוננטת vue.js שאמורה להציג קוד צבוע אבל מתעלמת מפרמטר השפה שאני מעביר לה ותמיד מריצה זיהוי אוטומטי:
import { ref, h, computed, defineComponent, Plugin, watch } from 'vue'
import hljs from 'highlight.js/lib/core'
import { escapeHtml } from './lib/utils'
const component = defineComponent({
props: {
code: {
type: String,
required: true,
},
language: {
type: String,
default: '',
},
autodetect: {
type: Boolean,
default: true,
},
ignoreIllegals: {
type: Boolean,
default: true,
},
},
setup(props) {
const language = ref(props.language)
watch(() => props.language, (newLanguage) => {
language.value = newLanguage
})
const autodetect = computed(() => props.autodetect || !language.value)
const cannotDetectLanguage = computed(() => !autodetect.value && !hljs.getLanguage(language.value))
const className = computed((): string => {
if (cannotDetectLanguage.value) {
return ''
} else {
return `hljs ${language.value}`
}
})
const highlightedCode = computed((): string => {
// No idea what language to use, return raw code
if (cannotDetectLanguage.value) {
console.warn(`The language "${language.value}" you specified could not be found.`)
return escapeHtml(props.code)
}
if (autodetect.value) {
const result = hljs.highlightAuto(props.code)
language.value = result.language ?? ''
return result.value
} else {
const result = hljs.highlight(props.code, {
language: language.value,
ignoreIllegals: props.ignoreIllegals,
})
return result.value
}
})
return {
className,
highlightedCode,
}
},
render() {
return h('pre', {}, [
h('code', {
class: this.className,
innerHTML: this.highlightedCode,
}),
])
},
})
const plugin: Plugin & { component: typeof component } = {
install(app) {
app.component('highlightjs', component)
},
component,
}
export default plugin
רואים את הבעיה? התשובה בשורה 30:
const autodetect = computed(() => props.autodetect || !language.value)
הקוד מוגדר לבצע זיהוי אוטומטי ולהתעלם ממאפיין השפה אם לא העברנו שפה (הגיוני) או אם המאפיין autodetect בעל ערך אמת. החלק השני היה יכול להיות סביר אלמלא אמת היתה ברירת המחדל למאפיין זה:
autodetect: {
type: Boolean,
default: true,
},
כלומר אם אני לא מעביר ערך false בצורה מפורשת לאותו autodetect ברירת המחדל שלו היא לזהות לבד את השפה ולהתעלם מערך ה language שהעברתי.
הסיבה שאני נתקעתי על הסיפור הזה יותר מדי זמן היא דף התיעוד של הספריה שמציג את הדוגמה הבאה:
<div id="app">
<!-- bind to a data property named `code` -->
<highlightjs autodetect :code="code" />
<!-- or literal code works as well -->
<highlightjs language='javascript' code="var x = 5;" />
</div>
שכמובן עובדת רק בגלל ש highlightjs מצליח לזהות אוטומטית בדיוק את אותה שפת javascript שמוגדרת ב language.
עכשיו תשאלו - אין לך איזה קלוד חכם בצוות שידע להסביר בדיוק את הבאג הזה? נו, יש קלוד חכם והוא הצליח להציע המון רעיונות מקוריים ולא נכונים. מסתבר שגם הוא לא חשב שתיעוד יכול להטעות ובאגים יכולים לקרות בספריות חיצוניות.