Last active
January 15, 2020 21:11
-
-
Save lancegliser/9a4d22dbab2113a45d5ddb04f5825071 to your computer and use it in GitHub Desktop.
Basic error boundary component for Vue JS using the V2 composition api. Adapated from https://github.com/dillonchanis/vue-error-boundary
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script lang="ts"> | |
import { | |
createComponent, | |
createElement, | |
onErrorCaptured, | |
reactive, | |
SetupContext | |
} from "@vue/composition-api"; | |
import DefaultFallbackUI from "./ErrorBoundaryFallbackUI.vue"; | |
import { IErrorBoundaryState } from "@/components/errorBoundary/IErrorBoundary"; | |
import { Vue as VueType } from "vue/types/vue"; | |
import { VNode } from "vue"; | |
const isObjectEmpty = (obj: Object) => | |
Object.entries(obj).length === 0 && obj.constructor === Object; | |
// https://github.com/posva/vue-promised/blob/master/src/index.js | |
const convertVNodeArray = (h: Function, wrapperTag: string, nodes: VNode[]) => { | |
// for arrays and single text nodes | |
if (nodes.length > 1 || !nodes[0].tag) return h(wrapperTag, {}, nodes); | |
return nodes[0]; | |
}; | |
interface IProps { | |
stopPropagation: boolean; | |
fallBack: Object; | |
onError: Function; | |
tag: string; | |
} | |
const defaultOnErrorFallback = () => {}; | |
const ErrorBoundary = createComponent<IProps>({ | |
name: "ErrorBoundary", | |
props: { | |
stopPropagation: { | |
type: Boolean, | |
default: false | |
}, | |
fallBack: { | |
type: Object, | |
default: () => DefaultFallbackUI | |
}, | |
onError: { | |
type: Function, | |
default: defaultOnErrorFallback | |
}, | |
tag: { | |
type: String, | |
default: "div" | |
} | |
}, | |
setup(props: IProps, context: SetupContext): () => VNode | null { | |
const { state } = useState(props); | |
return (): VNode | null => { | |
const fallback = createElement(props.fallBack, { | |
props: { state } | |
}); | |
if (state.error) { | |
return Array.isArray(fallback) | |
? convertVNodeArray(createElement, props.tag, fallback) | |
: fallback; | |
} | |
if (isObjectEmpty(context.slots)) { | |
console.warn("ErrorBoundary component must have child components."); | |
return null; | |
} | |
const contents = context.slots.default(); | |
return Array.isArray(contents) | |
? convertVNodeArray(createElement, props.tag, contents) | |
: contents; | |
}; | |
} | |
}); | |
export default ErrorBoundary; | |
function useState(props: IProps) { | |
const state = reactive({ | |
error: undefined | |
} as IErrorBoundaryState); | |
onErrorCaptured((error: Error, vm: VueType, info: string = "") => { | |
state.error = error; | |
props.onError(error, vm, info); | |
if (props.stopPropagation) { | |
return false; | |
} | |
}); | |
return { state }; | |
} | |
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<p>An error occurred</p> | |
<p v-if="isProduction">{{ state.error.message }}</p> | |
<pre v-else> | |
{{ state.error.stack }} | |
</pre> | |
</template> | |
<script lang="ts"> | |
import { computed, createComponent } from "@vue/composition-api"; | |
import { IErrorBoundaryState } from "@/components/errorBoundary/IErrorBoundary"; | |
interface IProps { | |
state: IErrorBoundaryState; | |
} | |
const ErrorBoundaryFallbackUI = createComponent<IProps>({ | |
props: { | |
state: Object | |
}, | |
setup() { | |
const isProduction = computed(() => process.env.NODE_ENV === "production"); | |
return { isProduction }; | |
} | |
}); | |
export default ErrorBoundaryFallbackUI; | |
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export interface IErrorBoundaryState { | |
error: Error | undefined; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment