Incompatible with vue 3.0
adambullmer opened this issue · 10 comments
Describe the bug
When using this plugin on a vue 3.0 based repo, the storybook build/serve commands fail due to the absence of the vue/dist/vue.esm.js
file. I believe it has been renamed vue/dist/vue.esm-browser.js
. Possibly, but not likely, this is because of yarn 2 (berry).
Steps to reproduce the behavior
- Scaffold new vue app
vue create .
and follow prompts selecting vue 3.0 - Add this plugin
vue add storybook
and use^6.0.0
as the version yarn set version berry
- fix peer dependency outlined in #110 (Manually add peer dependency to
.yarnrc.yml
) yarn install
yarn storybook:build
- Observe error.
Expected behavior
I expect a default vue project, adding this plugin's generated code, and a build to succeed without failure.
Screenshots and/or logs
info
info => Loading presets
info => Loading presets
info => Loading config/preview file in "config/storybook".
info => Adding stories defined in "config/storybook/main.js".
ERR! Error: Qualified path resolution failed - none of the candidates can be found on the disk.
ERR!
ERR! Source path: /Users/adam/github/test-vue-3/.yarn/unplugged/vue-npm-3.0.0-6474504e0b/node_modules/vue/dist/vue.esm.js
ERR! Rejected candidate: /Users/adam/github/test-vue-3/.yarn/unplugged/vue-npm-3.0.0-6474504e0b/node_modules/vue/dist/vue.esm.js
ERR! Rejected candidate: /Users/adam/github/test-vue-3/.yarn/unplugged/vue-npm-3.0.0-6474504e0b/node_modules/vue/dist/vue.esm.js.js
ERR! Rejected candidate: /Users/adam/github/test-vue-3/.yarn/unplugged/vue-npm-3.0.0-6474504e0b/node_modules/vue/dist/vue.esm.js.json
ERR! Rejected candidate: /Users/adam/github/test-vue-3/.yarn/unplugged/vue-npm-3.0.0-6474504e0b/node_modules/vue/dist/vue.esm.js.node
ERR!
ERR! Require stack:
ERR! - /Users/adam/github/test-vue-3/.yarn/$$virtual/vue-cli-plugin-storybook-virtual-dab0511f8d/0/cache/vue-cli-plugin-storybook-npm-1.3.0-5111490768-ff5ea2b87a.zip/node_modules/vue-cli-plugin-storybook/lib/preset.js
ERR! - /Users/adam/github/test-vue-3/.yarn/$$virtual/@storybook-core-virtual-239ad0cf3f/0/cache/@storybook-core-npm-6.0.22-db69c12efe-7f862c3c5f.zip/node_modules/@storybook/core/dist/server/presets.js
ERR! - /Users/adam/github/test-vue-3/.yarn/$$virtual/@storybook-core-virtual-239ad0cf3f/0/cache/@storybook-core-npm-6.0.22-db69c12efe-7f862c3c5f.zip/node_modules/@storybook/core/dist/server/config.js
ERR! - /Users/adam/github/test-vue-3/.yarn/$$virtual/@storybook-core-virtual-239ad0cf3f/0/cache/@storybook-core-npm-6.0.22-db69c12efe-7f862c3c5f.zip/node_modules/@storybook/core/dist/server/build-static.js
ERR! - /Users/adam/github/test-vue-3/.yarn/$$virtual/@storybook-core-virtual-239ad0cf3f/0/cache/@storybook-core-npm-6.0.22-db69c12efe-7f862c3c5f.zip/node_modules/@storybook/core/server.js
ERR! - /Users/adam/github/test-vue-3/.yarn/$$virtual/vue-cli-plugin-storybook-virtual-dab0511f8d/0/cache/vue-cli-plugin-storybook-npm-1.3.0-5111490768-ff5ea2b87a.zip/node_modules/vue-cli-plugin-storybook/lib/index.js
ERR! - /Users/adam/github/test-vue-3/.yarn/$$virtual/@vue-cli-service-virtual-81f54a6811/0/cache/@vue-cli-service-npm-4.5.6-7e8eb1fcab-c621385ec3.zip/node_modules/@vue/cli-service/lib/Service.js
ERR! - /Users/adam/github/test-vue-3/.yarn/$$virtual/@vue-cli-service-virtual-81f54a6811/0/cache/@vue-cli-service-npm-4.5.6-7e8eb1fcab-c621385ec3.zip/node_modules/@vue/cli-service/bin/vue-cli-service.js
ERR! at internalTools_makeError (/Users/adam/github/test-vue-3/.pnp.js:26975:34)
ERR! at resolveUnqualified (/Users/adam/github/test-vue-3/.pnp.js:28007:13)
ERR! at resolveRequest (/Users/adam/github/test-vue-3/.pnp.js:28031:14)
ERR! at Object.resolveRequest (/Users/adam/github/test-vue-3/.pnp.js:28091:26)
ERR! at Function.external_module_.Module._resolveFilename (/Users/adam/github/test-vue-3/.pnp.js:27208:34)
ERR! at Function.resolve (internal/modules/cjs/helpers.js:94:19)
ERR! at Object.webpack (/Users/adam/github/test-vue-3/.yarn/$$virtual/vue-cli-plugin-storybook-virtual-dab0511f8d/0/cache/vue-cli-plugin-storybook-npm-1.3.0-5111490768-ff5ea2b87a.zip/node_modules/vue-cli-plugin-storybook/lib/preset.js:39:25)
ERR! at /Users/adam/github/test-vue-3/.yarn/$$virtual/@storybook-core-virtual-239ad0cf3f/0/cache/@storybook-core-npm-6.0.22-db69c12efe-7f862c3c5f.zip/node_modules/@storybook/core/dist/server/presets.js:258:36
ERR! at processTicksAndRejections (internal/process/task_queues.js:93:5)
ERR! at async Promise.all (index 1)
ERR! at async buildDevStandalone (/Users/adam/github/test-vue-3/.yarn/$$virtual/@storybook-core-virtual-239ad0cf3f/0/cache/@storybook-core-npm-6.0.22-db69c12efe-7f862c3c5f.zip/node_modules/@storybook/core/dist/server/build-dev.js:438:28)
ERR! at async Object.buildDev (/Users/adam/github/test-vue-3/.yarn/$$virtual/@storybook-core-virtual-239ad0cf3f/0/cache/@storybook-core-npm-6.0.22-db69c12efe-7f862c3c5f.zip/node_modules/@storybook/core/dist/server/build-dev.js:520:3)
Environment
- OS: OSX 10.15.7
- Node.js version: v14.12.0
- NPM version: yarn 2.2.2
- Browser (if applicable): n/a
- Browser version (if applicable): n/a
- Device (if applicable): n/a
Additional context
#110 must be fixed if using yarn2
Example .yarnrc.yml
yarnPath: .yarn/releases/yarn-berry.js
packageExtensions:
vue-cli-plugin-storybook@*:
peerDependencies:
"@storybook/core": "*"
In the interim, I've utilized yarn's patch capabilities to solve this for me:
First, Create file ./patches/vue-cli-plugin-storybook.patch
diff --git a/lib/preset.js b/lib/preset.js
index e5c85e120ce743d879044dfed9a77451eeabdaf1..ba340af5f10747ba4cf56bc4610942e9d69367f3 100644
--- a/lib/preset.js
+++ b/lib/preset.js
@@ -36,7 +36,7 @@ module.exports = {
...webpackConfig.resolve,
alias: {
...webpackConfig.resolve && webpackConfig.resolve.alias,
- vue$: require.resolve('vue/dist/vue.esm.js'),
+ vue$: require.resolve('vue/dist/vue.esm-browser.js'),
},
},
resolveLoader: webpackConfig.resolveLoader,
Then tell yarn to use the patched version in your package.json
"devDependencies": {
// ...
"vue-cli-plugin-storybook": "patch:vue-cli-plugin-storybook@~1.3.0#./patches/vue-cli-plugin-storybook.patch",
// ...
}
and lastly yarn install
to apply the patch
Is the patch working for you? I can't build storybook for my vue3 project even with npm
. And vue3 is not exactly supported in storybook.
Yeah, I think I called my patch a solution too soon. It builds successfully and I assumed the lack of output was because the boilerplate component was broken for TS projects. After fixing that, there appears to be console errors because @storybook/vue/dist/client/preview/render.js
tries to create vue components with new Vue()
which was removed in vue 3.
at Object../.yarn/$$virtual/@storybook-vue-virtual-af7ac388fa/0/cache/@storybook-vue-npm-6.0.22-10d30dd9e8-4f2987ec61.zip/node_modules/@storybook/vue/dist/client/preview/render.js (render.js:47)
at __webpack_require__ (bootstrap:848)
at fn (bootstrap:150)
at Object../.yarn/$$virtual/@storybook-vue-virtual-af7ac388fa/0/cache/@storybook-vue-npm-6.0.22-10d30dd9e8-4f2987ec61.zip/node_modules/@storybook/vue/dist/client/preview/index.js (index.js:30)
at __webpack_require__ (bootstrap:848)
at fn (bootstrap:150)
at Object.<anonymous> (index.js:55)
at Object../.yarn/$$virtual/@storybook-vue-virtual-af7ac388fa/0/cache/@storybook-vue-npm-6.0.22-10d30dd9e8-4f2987ec61.zip/node_modules/@storybook/vue/dist/client/index.js (index.js:59)
at __webpack_require__ (bootstrap:848)
at fn (bootstrap:150)
I think the provided patch is all that is needed here, but more work will be necessary in the storybook side to fix vue rendering.
@pksunkara I think I've got the yarn patchable (post transpile) changes figured out. There's some HMR issues with it for sure, and I'm seeing that click events (and probably other listeners) are firing twice. But this could at least serve as a starting place for using storybook with vue 3.
The changes below mostly follow the migration guides for render functions and creating components. But that alone didn't render the story, so it was necessary to begin using the composition api to make the reactive storybook properties added on the root app. While this is a bit of a hack, I suspect the storybook team will be able to leverage composition APIs to drastically simplify their vue integration.
./patches/@storybook/vue.patch
diff --git a/dist/client/preview/index.js b/dist/client/preview/index.js
index 38a6be377c58c2efab3fdd446a0272e30045ced9..3accfe7f72096cfce6d2bd63f37fd3005819a231 100644
--- a/dist/client/preview/index.js
+++ b/dist/client/preview/index.js
@@ -70,18 +70,19 @@ function prepare(rawStory, innerStory) {
});
}
- story = _vue["default"].extend(story); // @ts-ignore // https://github.com/storybookjs/storybook/pull/7578#discussion_r307984824
- } else if (story.options[WRAPS]) {
+ story = _vue["defineComponent"](story); // @ts-ignore // https://github.com/storybookjs/storybook/pull/7578#discussion_r307984824
+ } else if (story[WRAPS]) {
return story;
}
- return _vue["default"].extend((_Vue$extend = {}, _defineProperty(_Vue$extend, WRAPS, story), _defineProperty(_Vue$extend, _render.VALUES, Object.assign(Object.assign({}, innerStory ? innerStory.options[_render.VALUES] : {}), (0, _util.extractProps)(story))), _defineProperty(_Vue$extend, "functional", true), _defineProperty(_Vue$extend, "render", function render(h, _ref) {
- var data = _ref.data,
- parent = _ref.parent,
- children = _ref.children;
- return h(story, Object.assign(Object.assign({}, data), {}, {
+ return _vue["defineComponent"]((_Vue$extend = {}, _defineProperty(_Vue$extend, WRAPS, story), _defineProperty(_Vue$extend, _render.VALUES, Object.assign(Object.assign({}, innerStory ? innerStory[_render.VALUES] : {}), (0, _util.extractProps)(story))), _defineProperty(_Vue$extend, "functional", true), _defineProperty(_Vue$extend, "render", function render(_ref) {
+ var data = _ref.$data,
+ props = _ref.$props,
+ parent = _ref.$parent,
+ children = _ref.$children;
+ return _vue['h'](story, Object.assign(Object.assign({}, data), {}, {
// @ts-ignore // https://github.com/storybookjs/storybook/pull/7578#discussion_r307986196
- props: Object.assign(Object.assign({}, data.props || {}), parent.$root[_render.VALUES])
+ props: Object.assign(Object.assign({}, props || {}), parent.$root[_render.VALUES])
}), children);
}), _Vue$extend));
}
diff --git a/dist/client/preview/render.js b/dist/client/preview/render.js
index 510391bf8a72e0ae4246176901522654e425b4b0..6b914faad18f7f69af30456d30a08c77fd02eaea 100644
--- a/dist/client/preview/render.js
+++ b/dist/client/preview/render.js
@@ -44,20 +44,24 @@ var COMPONENT = 'STORYBOOK_COMPONENT';
exports.COMPONENT = COMPONENT;
var VALUES = 'STORYBOOK_VALUES';
exports.VALUES = VALUES;
-var root = new _vue["default"]({
- data: function data() {
- var _ref;
-
- return _ref = {}, _defineProperty(_ref, COMPONENT, undefined), _defineProperty(_ref, VALUES, {}), _ref;
+var _ref = _vue['markRaw']({
+ [COMPONENT]: undefined,
+ [VALUES]: {},
+});
+var root = _vue["createApp"]({
+ setup(props, { slots, attrs, emit }) {
+ var children = _ref[COMPONENT] ? [_vue['h'](_ref[COMPONENT])] : undefined;
+
+ return () => _vue['h'](
+ 'div',
+ {
+ id: 'root',
+ [COMPONENT]: _ref[COMPONENT],
+ [VALUES]: _ref[VALUES],
+ },
+ children
+ );
},
- render: function render(h) {
- var children = this[COMPONENT] ? [h(this[COMPONENT])] : undefined;
- return h('div', {
- attrs: {
- id: 'root'
- }
- }, children);
- }
});
function render(_ref2) {
@@ -69,7 +73,7 @@ function render(_ref2) {
showError = _ref2.showError,
showException = _ref2.showException,
forceRender = _ref2.forceRender;
- _vue["default"].config.errorHandler = showException; // FIXME: move this into root[COMPONENT] = element
+ root.config.errorHandler = showException; // FIXME: move this into root[COMPONENT] = element
// once we get rid of knobs so we don't have to re-create
// a new component each time
@@ -85,14 +89,14 @@ function render(_ref2) {
showMain(); // at component creation || refresh by HMR or switching stories
- if (!root[COMPONENT] || !forceRender) {
- root[COMPONENT] = element;
+ if (!_ref[COMPONENT] || !forceRender) {
+ _ref[COMPONENT] = element;
} // @ts-ignore https://github.com/storybookjs/storrybook/pull/7578#discussion_r307986139
- root[VALUES] = Object.assign(Object.assign({}, element.options[VALUES]), args);
+ _ref[VALUES] = Object.assign(Object.assign({}, element[VALUES]), args);
if (!root.$el) {
- root.$mount('#root');
+ root.mount('#root');
}
}
\ No newline at end of file
diff --git a/dist/client/preview/util.js b/dist/client/preview/util.js
index ab8c1d3cdb5424fc782e3fb3bee8951ee2d6c7e0..90bbd09f5a6276ea6592c7c0d0a9ba63df83e140 100644
--- a/dist/client/preview/util.js
+++ b/dist/client/preview/util.js
@@ -79,7 +79,7 @@ function resolveDefault(_ref) {
function extractProps(component) {
// @ts-ignore this options business seems not good according to the types
- return Object.entries(component.options.props || {}).map(function (_ref2) {
+ return Object.entries(component.props || {}).map(function (_ref2) {
var _ref3 = _slicedToArray(_ref2, 2),
name = _ref3[0],
prop = _ref3[1];
"devDependencies": {
// ...
"@storybook/vue": "patch:@storybook/vue@^6.0.0#./patches/@storybook/vue.patch",
"vue-cli-plugin-storybook": "patch:vue-cli-plugin-storybook@~1.3.0#./patches/vue-cli-plugin-storybook.patch",
// ...
}
You should probably help at storybookjs/storybook#10654 instead of here.
Given that vue3 support has landed in storybook 6.2, this should be doable now.
Here are some things, that I definitely had to change:
- install
@storybook/vue3
- require
@storybook/vue3/package.json
inlib/index.js
framework: 'vue3'
inlib/index.js
- require
vue/dist/vue.esm-browser.js
inlib/preset.js
- get the new app object in
config/storybook/preview.js
withimport { app } from "@storybook/vue3";
e.g. to register directives or global components
The only thing that doesn’t work for me is storybook-vue-router and the property tables in docs mode.
Cf. vue-styleguidist/vue-styleguidist#997
What do you think, would it be better to have one version of vue-cli-plugin-storybook to support both vue2 and vue3 or separate versions?
We can try. Would welcome a PR
From a user perspective I would prefer to have only one plugin no matter my vue version.
For vue 2 we peer-depend on @storybook/vue
and for vue 3 on @storybook/vue3
though.
How can we handle that?
Ok, I solved it with optional peerDependencies. They work with npm 7. In npm 6 peerDependencies are not pulled in automatically anyways.
Please have a look at the PR @pksunkara .