1

What I want:

Parent.vue

<template>
    <div>
        <span>{{foo}}</span>
        <Child/>
    </div>
</template>

<script setup>
import { ref, defineComponent } from 'vue';

let foo = ref('foo');

let Child = defineComponent({
    name: 'Child',
    template: `<span>{{bar}}</span>`,
    setup() {
        let bar = ref('bar');

        return { bar };
    }
});
</script>

I wanted to make very small dedicated component for one page.

It looks pretty good. But it doesn't work.

I don't want to make a new file and use export default.

and also don't want register it globally.

Is there no way to create component like this?

=====

answer:

main.js

import { createApp } from 'vue'; (X)

import { createApp } from 'vue/dist/vue.esm-bundler.js'; (O)

it works. Why...

3
  • 1
    @JBallin Vue's single-file components are not evaluated like that. It's pretty normal to define the <template> first Commented Jul 6, 2022 at 6:06
  • You have a typo... missing ) to close definedComponent( Commented Jul 6, 2022 at 6:08
  • @Phil No... It's just a typo from writing.... Commented Jul 6, 2022 at 6:16

1 Answer 1

2

Your code does not work because the template of the Child component is provided as a string.

Note on In-Browser Template Compilation

When using Vue without a build step, component templates are written either directly in the page's HTML or as inlined JavaScript strings. In such cases, Vue needs to ship the template compiler to the browser in order to perform on-the-fly template compilation. On the other hand, the compiler would be unnecessary if we pre-compile the templates with a build step.

Our default tooling setups use the runtime-only build since all templates in SFCs are pre-compiled. If, for some reason, you need in-browser template compilation even with a build step, you can do so by configuring the build tool to alias vue to vue/dist/vue.esm-bundler.js instead

You are using Vue SFC - which means you are using Vite or Vue CLI. Both are preconfigured to use runtime only build and precompile all Vue templates inside the <template> tags of all SFC files. BUT your Child component has a template as a string and thus requires build with the compiler included. And this is the reason why importing from vue/dist/vue.esm-bundler.js fixes the issue (although I recommend to use a solution described in the docs instead of importing like that because you can easily end up with two versions of Vue used which leads to very strange and hard to debug errors)

Other solution is to avoid string templates and write your simple component using render function

<script setup>
import { ref, defineComponent, h } from 'vue'

const Child = defineComponent({
    name: 'Child',
    setup() {
        const bar = ref('bar');
        return () => h('span', bar.value)
    }
});
</script>
    
<template>
  <Child></Child>
</template>

Demo

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you so much. Now I understand why modules need to be exported an imported in general way.
This is not about export/import in general. It is about tooling - the SFC compiler that "understands" the anatomy of Vue SFC files and knows that content of the <template> section needs to be compiled to JS render function

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.