`defineExpose` attributes are not available from options API methods called from first template render in production build, despite it working in Vite dev mode
Vue version
3.2.39
Link to minimal reproduction
https://github.com/segevfiner/vue-define-expose-bug
Steps to reproduce
- Run
pnpm dev
, open the page, TheBar: {{ bar() }}
in the components used inHomeView
renders correctly. - Run
pnpm build
&pnpm preview
,Bar: {{ bar() }}
throws an exception.
What is expected?
It should work. It works in dev
, so it should work in build
as well.
What is actually happening?
It throws:
index.9acc7ff5.js:1 TypeError: this.foo is not a function
at Proxy.bar (index.9acc7ff5.js:9:22894)
at Proxy.<anonymous> (index.9acc7ff5.js:9:23095)
at Mn (index.9acc7ff5.js:1:15620)
at rs.w [as fn] (index.9acc7ff5.js:1:34772)
at rs.run (index.9acc7ff5.js:1:4548)
at u.update (index.9acc7ff5.js:1:35042)
at ee (index.9acc7ff5.js:1:35068)
at pt (index.9acc7ff5.js:1:33922)
at ht (index.9acc7ff5.js:1:33716)
at z (index.9acc7ff5.js:1:30557)
System Info
System:
OS: macOS 12.6
CPU: (10) arm64 Apple M1 Pro
Memory: 79.61 MB / 16.00 GB
Shell: 5.8.1 - /bin/zsh
Binaries:
Node: 16.17.0 - ~/.nvm/versions/node/v16.17.0/bin/node
Yarn: 1.22.19 - ~/.nvm/versions/node/v16.17.0/bin/yarn
npm: 8.19.2 - ~/.nvm/versions/node/v16.17.0/bin/npm
Browsers:
Chrome: 105.0.5195.125
Safari: 16.0
npmPackages:
vue: ^3.2.38 => 3.2.39
Any additional comments?
This seems to happen due to the exposed attributes not being exposed/defined on this
before running the render function/template for the first time in the production build, although they are available properly in dev
mode, and they have proper type definitions, which makes it seem like this should work.
There is no warning at all about this not working in a production build, and the type checking and linting passes.
Mixing script setup and options API like this is invalid. We will make this fail in dev in a future release.
See a similar discussion in #6677
A lint can also help, but might be a bit complex? Oh well, this will make migration difficult for us due to widespread use of mixins that are difficult to convert. Any suggestions on how to ease migration if such dual usage should not be done?
That will help. Although script setup
is obviously nicer... Sadly I doubt mixins can be used or will be made available to use with it, as they are "technically deprecated"/"not recommended", so guess that's our only option for the time being.
You'll need to convert the mixins sometime, as you can't use mixins in Composition API, yes. I'd likely try and convert one mixin into a composable, then inject that via setup
:
// use it just for composables from mixins
setup() {
return {
...useMyComposableFromAMixin()
}
},
// rest of existing Options API ...
and once all mixins are transformed, then migrate components themselves to composition API - if that make sense for you at all.
Yeah. And using them via splatting saves from needing to make a mixin shim for the old code that uses them. Thanks!