Incorrect 'computed' import can cause reactivity to break after transpiling
Version
3.2.8
Reproduction link
Steps to reproduce
- See in the example how the css classes on a simple button component are updated with a computed property when its props change. This can be viewed with
npm run serve
. (Sometimes the sandbox throws errors about module import locations, but a refresh fixes that) - Run the included
build:lib
command to build that component as a library. Will probably have to be done outside of CodeSandbox - Import that built component into some other Vue application
- The CSS classes should no longer update, because the computed property is no longer being recalculated when its dependencies change.
What is expected?
After days of debugging this behavior I noticed that VS Code had automatically imported computed
for me as:
import { computed } from "@vue/reactivity";
rather than:
import { computed } from "vue";
This import works in development mode, and everything behaves how it should. However, my computed properties were not updating when the props they depended on were updated when I used the vue cli command to build them as a library.
I realize that I was not importing things as documented, but I would rather one of two things happen:
- See a console warning that I'm importing
compute
incorrectly - VS Code not suggest the incorrect import from
vue
What is actually happening?
Computed properties are transpiled differently based on which way you import computed
when you're build target is a library. When using the components build as a library the computed properties are only ever calculated once and basically cause components to fail silently.
Ran into this bug while I was developing components for a UI library. VS Code tried to be helpful and import computed
for me, but it used the wrong import statement and sent me down a rabbit hole for days. It would be really great if there were some guard rails in place so no one else gets stuck the same way I did!
I can supply more verbose examples of the transpiling differences I'm talking about if that would be helpful.
This isn't really a bug. Here's what's happening:
- Vue 3 reactivity relies on a few singletons in that reactivity package.
- You built your library and excluded 'vue', as you should, but since you imported from '@vue/reactivity', that package got bundled with your library.
- So now the consuming app has two copies of
@vue/reactivity
: one, included in and only used by your lib, and the second one installed in the app'snode_modules
- And these two have their own singletons responsible for managing dependencies and effects.
there's two things that can prevent this from happening:
- Use a package manager that prevents you from importing from transitive dependencies, like pnpm.
- Use eslint's
no-restricted-imports
rule to disallow imports from@vue/*
dependencies.
We can't really do much in core as we can't prevent consumers from doing this import.
You could maybe open an issue in our eslint-plugin's repo and propose a rule to prevent these imports in our presets?