Optional Components
Sometimes we want to load a Vue component if the relevant package is installed, but not cause errors if it is not. For example, we want to use the Media Library file picker if it is available, but a regular text input if it is not.
Unfortunately, Webpack doesn't make this easy - normally it won't compile unless all dependencies are found - but we can make it work...
<script>
// Example from vendor/alberon/nexus-menus/assets/vue/Menus/MenuItemEdit.vue
// 1. Import this helper
import optionalComponent from '@alberon/nexus/js/lib/optionalComponent';
export default {
components: [
// 2. Use this syntax to load the optional component (see below for an explanation)
FieldMediaLibraryImage: optionalComponent(require.context('../../../../', true, /^\.\/nexus-media-library\/assets\/vue\/FieldMediaLibraryImage\.vue$/)),
// ...
],
// ...
}
</script>
<template>
...
<!-- 3. Check whether the component was loaded using v-if/v-else -->
<FieldMediaLibraryImage
v-if="$options.components.FieldMediaLibraryImage"
id="image"
v-model="menuItem.image_path"
/>
<input
v-else
class="form-control"
id="image"
type="text"
v-model="menuItem.image_path"
/>
...
</template>
The syntax of require.context() is somewhat unwieldy, but it breaks down to:
- The path from the current component (
Example.vue) to thevendor/alberon/directory. Adjust the number of../'s as required. trueto enable recursively searching subdirectories.- A regex that matches the target file, relative to the
vendor/alberon/directory.
Note: The path specified in the first parameter must always exist, so we can't use ../../../../nexus-media-library/, for example.
The optionalComponent() function takes the context returned by webpack and returns (1) a closure that loads the component, or (2) undefined if it wasn't found. (FYI, this technique is a simplified version of loading dynamic Vue components.)
To test it without actually uninstalling the package, just change the regex to a file that doesn't exist. (Remember to change it back again though!)