Multiple SFC components with common (extended) <script> sections

I’m currently writing several SFC components in Vue3 (composition API) which all share a ‘base’ <script> section. However they all have different templates, using different 3rd-party components in the template, and so need the <script> ‘extended’ with some imports.

Effectively I want to define something like a base.vue

<script>
import { computed } from 'vue'
import { changeName } from '../utils'

export default {
  props: {
    name: {
      type: String,
      default: '',
    }
  },
  setup(props) {
  let { name } = toRef(props)
  let newName = computed(() => {
    return changeName(name)
  })

return { newName }
</script>

Then a number of different components which somehow ‘inherit’ base.vue - each with a different component, and some minor differences in variables etc. I know the following isn’t correct, but hopefully it lays out the kind of thing I’m looking for:

<template>
<CustomComponent :name="newName" :foo="local" />
</template>

<script>
import CustomComponent from 'custom_component'
export default {
  components: [CustomComponent],
  setup(props) { // 'props' from `base.vue`
    let local = "bar"
    return { local } // what about 'newName' ?
  }
}
</script>

Is there a way to achieve something like this? How do I import/include/extend base.vue here?

I think in Vue 3 would be the best approach to use composables. You would have all your shared computed, methods in an extra file which you then import in your setup function.

Here is a nice introduction to this topic: https://www.thisdot.co/blog/custom-composable-methods-with-vue-3

1 Like

Thanks for the suggestion! I’ve had a look and this does seem like the right way to go about it - however I’m having some issues with getting props and computed properties to interact nicely.

I’ve mocked up an example here: vue 3 vuex 4 test (forked) - CodeSandbox

The props seem to get passed down as expected, and can be seen to be reactive when the input is edited, and computed properties work ‘generally’ as can be seen with multiply - however I’m not sure how to get greet to see baseProps.name as the reactive property value, rather than the underlying object?

I’ve forked and corrected some of your code. Now it should work as aspected.

Thanks - yes this works, but unfortunately the props are actually one of the main things I need to have in base since they are duplicated across multiple components, along with the methods.

However this got me thinking that I can keep exporting baseProps as a plain object, but export the computed/methods inside a function that takes props as an argument. That way the component can ‘convert’ baseProps to ‘real’ propsand make them available to all the methods that need them.

I’ve forked and saved it here:

There may be an even nicer way to do this, but I think this is a good enough mix of DRY but also not complicated to follow.

Thanks for all the suggestions, if you hadn’t mentioned composables I’d never have got there!

Hello, i share scripts using mixins.

Mixins | Vue.js (vuejs.org)