Reputation: 5791
The export default statement does not seem to work inside <script setup>
.
If I try to export it in test.vue
:
<template>
<div id="test" class="test">
</div>
</template>
<script setup>
const x = 5
export default {
x
}
</script>
<style scoped lang="scss">
</style>
and then importing it into another blog.vue
:
<script setup>
import x from './test'
</script>
I am getting this bulk of error:
app.js?id=3b6365f542826af47b926162803b3ef6:37396 Uncaught Error: Module build failed (from ./node_modules/vue-loader/dist/index.js):
TypeError: Cannot read properties of null (reading 'content')
at selectBlock (:3000/Users/artur/PhpstormProjects/safa-ameedee.com/node_modules/vue-loader/dist/select.js:23:45)
at Object.loader (:3000/Users/artur/PhpstormProjects/safa-ameedee.com/node_modules/vue-loader/dist/index.js:67:41)
at Object../node_modules/babel-loader/lib/index.js??clonedRuleSet-5.use[0]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./resources/vue/backend/components/test.vue?vue&type=script&setup=true&lang=js (app.js?id=3b6365f542826af47b926162803b3ef6:37396:7)
at __webpack_require__ (app.js?id=3b6365f542826af47b926162803b3ef6:64806:42)
at Module../resources/vue/backend/components/test.vue?vue&type=script&setup=true&lang=js (app.js?id=3b6365f542826af47b926162803b3ef6:60116:217)
at __webpack_require__ (app.js?id=3b6365f542826af47b926162803b3ef6:64806:42)
at Module../resources/vue/backend/components/test.vue (app.js?id=3b6365f542826af47b926162803b3ef6:59477:102)
at __webpack_require__ (app.js?id=3b6365f542826af47b926162803b3ef6:64806:42)
at Module../node_modules/babel-loader/lib/index.js??clonedRuleSet-5.use[0]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./resources/vue/backend/components/blog.vue?vue&type=script&setup=true&lang=js (app.js?id=3b6365f542826af47b926162803b3ef6:37336:63)
at __webpack_require__ (app.js?id=3b6365f542826af47b926162803b3ef6:64806:42)
at Module../resources/vue/backend/components/blog.vue?vue&type=script&setup=true&lang=js (app.js?id=3b6365f542826af47b926162803b3ef6:60084:217)
at __webpack_require__ (app.js?id=3b6365f542826af47b926162803b3ef6:64806:42)
./node_modules/babel-loader/lib/index.js??clonedRuleSet-5.use[0]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./resources/vue/backend/components/test.vue?vue&type=script&setup=true&lang=js @ app.js?id=3b6365f542826af47b926162803b3ef6:37396
__webpack_require__ @ app.js?id=3b6365f542826af47b926162803b3ef6:64806
./resources/vue/backend/components/test.vue?vue&type=script&setup=true&lang=js @ app.js?id=3b6365f542826af47b926162803b3ef6:60116
__webpack_require__ @ app.js?id=3b6365f542826af47b926162803b3ef6:64806
./resources/vue/backend/components/test.vue @ app.js?id=3b6365f542826af47b926162803b3ef6:59477
__webpack_require__ @ app.js?id=3b6365f542826af47b926162803b3ef6:64806
./node_modules/babel-loader/lib/index.js??clonedRuleSet-5.use[0]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./resources/vue/backend/components/blog.vue?vue&type=script&setup=true&lang=js @ app.js?id=3b6365f542826af47b926162803b3ef6:37336
__webpack_require__ @ app.js?id=3b6365f542826af47b926162803b3ef6:64806
./resources/vue/backend/components/blog.vue?vue&type=script&setup=true&lang=js @ app.js?id=3b6365f542826af47b926162803b3ef6:60084
__webpack_require__ @ app.js?id=3b6365f542826af47b926162803b3ef6:64806
./resources/vue/backend/components/blog.vue @ app.js?id=3b6365f542826af47b926162803b3ef6:59328
__webpack_require__ @ app.js?id=3b6365f542826af47b926162803b3ef6:64806
./resources/js/router.js @ app.js?id=3b6365f542826af47b926162803b3ef6:39847
__webpack_require__ @ app.js?id=3b6365f542826af47b926162803b3ef6:64806
./resources/js/app.js @ app.js?id=3b6365f542826af47b926162803b3ef6:39770
__webpack_require__ @ app.js?id=3b6365f542826af47b926162803b3ef6:64806
(anonymous) @ app.js?id=3b6365f542826af47b926162803b3ef6:64971
__webpack_require__.O @ app.js?id=3b6365f542826af47b926162803b3ef6:64843
(anonymous) @ app.js?id=3b6365f542826af47b926162803b3ef6:64973
(anonymous) @ app.js?id=3b6365f542826af47b926162803b3ef6:64975
Upvotes: 16
Views: 50923
Reputation: 39
Rename your component to TestComponent.vue. Locate into a folder /src/components/. You can try the code below in your parent vue file.
<template>
<TestComponent/>
</template>
<script>
import { defineComponent } from 'vue'
import TestComponent from '/src/components/TestComponent.vue'
export default defineComponent({
components: {
TestComponent
}
})
</script>
<script setup>
// store
// locals
// methods
// lifecycle hooks
</script>
Upvotes: 3
Reputation: 90103
TL/DR
By design, a <script setup>
cannot have any ES module exports (explanation below). To export from a Vue component you have at least two options:
.js
or .ts
file and import it in the Vue file as well as anywhere else you might need it<script>
alongside the <script setup>
and export from the normal one. Each block is treated as a separate module by the the vue SFC (single file component) compiler (@vue/compiler-sfc
), so you can use both default or named exports in a normal <script>
, even when that component also has a <script setup>
block.Why doesn't <script setup>
allow exports?
<script setup>
is an alternative way of writing the script part of Vue SFC. The contents of a <script setup>
are parsed by the script setup macro and exported as default.
That is why you can't declare the default export inside a <script setup>
: the default export is reserved for the macro's output from parsing its contents.
Also note that, because having both a default and named exports from the same module is not recommended, <script setup>
does not allow any exports inside of it, although technically it could allow named exports.
In a nutshell, the macro takes the contents of <script setup>
, separates the imports from everything else and outputs:
/** imports go here **/
const componentDefinition = defineComponent({
setup() {
/** the rest of contents goes here **/
}
})
export default componentDefinition
The above is an over-simplification, outlining the principle 1.
In reality, the macro does more: it extracts emits, watch, props, expose and more from the setup contents, and places each in the appropriate section of the component definition, which is then exported as default.
And it also constructs the return
value of the setup()
function, making all declared constants and imports available for use in <template>
.
1 - In reality, the script setup macro does not export a defineComponent()
code block, because defineComponent
is sugar syntax for lower level options, such as the render function of the component. I'm only claiming it does to outline the way the script setup macro works.
To see it in action, go to Vue SFC Playground, open up the JS tab and watch the output changing as you change <script setup>
contents.
Upvotes: 0
Reputation: 5418
The solution is to use defineOPtions
I had the a similar problem where without the setup script I would done the following
<script>
import AnotherLayout from "../layouts/Another.vue"
export default {
layout: AnotherLayout
}
</script>
With the setup script, you have to use the following syntax.
<script setup>
import AnotherLayout from "../layouts/Another.vue"
defineOptions({
layout: Another
})
</script>
See the VueJS Docs for more info https://vuejs.org/api/sfc-script-setup.html#defineoptions
Upvotes: 2
Reputation: 435
'Components using script setup
are closed by default' - said from their own docs.
You need to expose using defineExpose()
<script setup>
const x = 5;
defineExpose({
x
})
</script>
https://vuejs.org/api/sfc-script-setup.html#defineexpose
Upvotes: 1
Reputation: 27
Hello i just see from others and it went well for me. Just add name properties next to script setup and it will export your component.
<script setup name="Greet">
</script>
it is the same as
export const MyComponent = {
name: "MyComponent" // I'm not 100% set on this part}
So you can just add your code in the parent component like this.
<script setup>
import Greet from './components/Greet.vue';
</script>
<template>
<Greet/>
</template>
Upvotes: -3
Reputation: 39
I didn't see this marked as answered so here's what I found dealing with same issue:
You can just use regular block alongside the block and place your export in that.
Here is the relevant documentation: https://vuejs.org/api/sfc-script-setup.html#usage-alongside-normal-script
Upvotes: 2
Reputation: 387
Create new file *.d.ts
like vue.d.ts
or paste script below this vite-env.d.ts
file (generate by vite)
declare module '*.vue' {
import type { DefineComponent } from 'vue';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const component: DefineComponent<Record<string, unknown>, Record<string, unknown>, any>;
export default component;
}
and then you can use script setup>
without defining two script tags
Upvotes: 3