-
-
Notifications
You must be signed in to change notification settings - Fork 9.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Storybook and angular library: Cannot read property 'selector' of undefined #14828
Comments
any updates ? faced the same issue |
Facing the same issue in mdx. |
Hi @ThibaudAV! do you need more info? |
I started to look at it but several things seem to be misconfigured or suspect in the example repos Especially here : https://github.com/krbaio3/sb-lib-issue/blob/master/tsconfig.json#L15 the path should match and it should not point to the
and with this version of storybook it works on my side :) This configuration also seems suspicious to me
is not enough. but this does not change the way storybook works |
I ran into this same issue. Storybook is not able to find the component annotations in this function. storybook/app/angular/src/client/preview/angular-beta/utils/NgComponentAnalyzer.ts Line 128 in 7064642
|
@manbearwiz what Storybook and Angular version are you using? |
I can recreate that error with sb6.3.4 + ng11.2.14. I was able to resolve by using sb6.1.21 + ng11.2.14. Haven't yet bisected to determine which specific version between those introduced the bug. Edit: Confirmed upgrading from sb6.1 to sb6.2.0 recreates the error. |
I see a flag was added from sb6.2, |
Any idea on which upcoming version will have fix for this issue ? |
I would submit a patch from @KondakovArtem observations, but I didn't get past the Anyway, here is an ugly solution if anyone needs a workaround other than accessing the library components directly (not built), which I personally don't like. I want the devs to access components using the built library entry points.
{
"scripts": {
"build-storybook": "npm run docs:json && build-storybook",
"postinstall": "node postinstall" // <-- add this line
}
} Create the postinstall script, or add this piece of code if you already have one. var fs = require('fs')
// Workaround to fix function getComponentDecoratorMetadata from storybook 6.3.7.
// See https://github.com/storybookjs/storybook/issues/14828.
// TODO: Remove this as soon as issue is solved in a future release.
var file = './node_modules/@storybook/angular/dist/ts3.9/client/preview/angular-beta/utils/NgComponentAnalyzer.js'
fs.readFile(file, 'utf8', function (err,data) {
if (err) {
return console.log(err);
}
var result = data.replace(
' return (decorators || []).find(function (d) { return d instanceof core_1.Component; });',
'if (!decorators) return component.decorators[0].args[0]; return (decorators || []).find(function (d) { return d instanceof core_1.Component; });'
);
fs.writeFile(file, result, 'utf8', function (err) {
if (err) return console.log(err);
});
}); I do recommend you freeze your storybook at 6.3.7 or whatever version your using which doesn't have the fix yet. This might break or break your code in different versions. That replace is working nicely for me. |
Good afternoon, Here is my solution to this problem. The script runs before launching the storybook. The script replaces the contents of the NgComponentAnalyzer.js file in and creates a backup nearby. You can compare what has been changed Yes it works on 6.3.7. Again. this is an ugly solution but it works
import fs from 'fs-extra';
import { resolve } from 'path';
import { createHash } from 'crypto';
const FIX_CONTENT = `"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __spreadArrays = (this && this.__spreadArrays) || function () {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getComponentDecoratorMetadata = exports.getComponentPropsDecoratorMetadata = exports.isComponent = exports.isDeclarable = exports.getComponentInputsOutputs = void 0;
var core_1 = require("@angular/core");
/**
* Returns component Inputs / Outputs by browsing these properties and decorator
*/
exports.getComponentInputsOutputs = function (component) {
var _a, _b;
var componentMetadata = exports.getComponentDecoratorMetadata(component);
var componentPropsMetadata = exports.getComponentPropsDecoratorMetadata(component);
var initialValue = {
inputs: [],
outputs: [],
};
// Adds the I/O present in @Component metadata
if (componentMetadata && componentMetadata.inputs) {
(_a = initialValue.inputs).push.apply(_a, componentMetadata.inputs.map(function (i) { return ({ propName: i, templateName: i }); }));
}
if (componentMetadata && componentMetadata.outputs) {
(_b = initialValue.outputs).push.apply(_b, componentMetadata.outputs.map(function (i) { return ({ propName: i, templateName: i }); }));
}
if (!componentPropsMetadata) {
return initialValue;
}
// Browses component properties to extract I/O
// Filters properties that have the same name as the one present in the @Component property
return Object.entries(componentPropsMetadata).reduce(function (previousValue, _a) {
var _b, _c;
var propertyName = _a[0], value = _a[1][0];
var valProto = value.prototype || value.__proto__ || {};
if (value instanceof core_1.Input || valProto.ngMetadataName === 'Input') {
var inputToAdd = {
propName: propertyName,
templateName: (_b = value.bindingPropertyName) !== null && _b !== void 0 ? _b : propertyName,
};
var previousInputsFiltered = previousValue.inputs.filter(function (i) { return i.templateName !== propertyName; });
return __assign(__assign({}, previousValue), { inputs: __spreadArrays(previousInputsFiltered, [inputToAdd]) });
}
if (value instanceof core_1.Output || valProto.ngMetadataName === 'Output') {
var outputToAdd = {
propName: propertyName,
templateName: (_c = value.bindingPropertyName) !== null && _c !== void 0 ? _c : propertyName,
};
var previousOutputsFiltered = previousValue.outputs.filter(function (i) { return i.templateName !== propertyName; });
return __assign(__assign({}, previousValue), { outputs: __spreadArrays(previousOutputsFiltered, [outputToAdd]) });
}
return previousValue;
}, initialValue);
};
exports.isDeclarable = function (component) {
if (!component) {
return false;
}
var decoratorKey = '__annotations__';
var decorators = Reflect.getOwnPropertyDescriptor(component, decoratorKey)
? Reflect.getOwnPropertyDescriptor(component, decoratorKey).value
: component[decoratorKey];
return !!(decorators || []).find(function (d) { return d instanceof core_1.Directive || d instanceof core_1.Pipe || d instanceof core_1.Component; });
};
exports.isComponent = function (component) {
if (!component) {
return false;
}
var decoratorKey = '__annotations__';
var decorators = Reflect.getOwnPropertyDescriptor(component, decoratorKey)
? Reflect.getOwnPropertyDescriptor(component, decoratorKey).value
: component[decoratorKey];
return (decorators || []).some(function (d) { return d instanceof core_1.Component; });
};
/**
* Returns all component decorator properties
* is used to get all \`@Input\` and \`@Output\` Decorator
*/
exports.getComponentPropsDecoratorMetadata = function (component) {
var decoratorKey = '__prop__metadata__';
var propsDecorators = Reflect &&
Reflect.getOwnPropertyDescriptor &&
Reflect.getOwnPropertyDescriptor(component, decoratorKey)
? Reflect.getOwnPropertyDescriptor(component, decoratorKey).value
: component[decoratorKey];
if (!propsDecorators) {
var propsDecorators = {};
for (var key in component.propDecorators) {
if (component.propDecorators.hasOwnProperty(key)){
propsDecorators[key] = [component.propDecorators[key][0].type]
}
}
}
return propsDecorators;
};
/**
* Returns component decorator \`@Component\`
*/
exports.getComponentDecoratorMetadata = function (component) {
var decoratorKey = '__annotations__';
var decorators = Reflect &&
Reflect.getOwnPropertyDescriptor &&
Reflect.getOwnPropertyDescriptor(component, decoratorKey)
? Reflect.getOwnPropertyDescriptor(component, decoratorKey).value
: component[decoratorKey];
if (!decorators) {
return component.decorators[0].args[0];
}
return (decorators || []).find(function (d) { return d instanceof core_1.Component; });
};`;
const FIX_FILE = 'NgComponentAnalyzer.js';
const PATH = `node_modules/@storybook/angular/dist/ts3.9/client/preview/angular-beta/utils`;
const CHECK_HASH = ['0be5cd4bed1d63d21a865a14707131ff', 'e0c243b9118ecf34576a8ed5d2f5e238'];
(async () => {
console.log('Start fixing storybook...');
let path = resolve(PATH, FIX_FILE);
if (!fs.existsSync(path)) {
path = resolve('../../', PATH, FIX_FILE);
if (!fs.existsSync(path)) {
throw new Error('Missing fixing file');
}
}
const code = await fs.readFile(path, 'utf-8');
const hash = createHash('md5').update(code).digest('hex');
const fixHash = createHash('md5').update(FIX_CONTENT).digest('hex');
console.log(hash);
if (hash === fixHash) {
console.log('Storybook is already fixed');
return;
}
if (!CHECK_HASH.includes(hash)) {
throw new Error(
`File ${path} was modified by developers. New hash is ${hash}, prev hash ${CHECK_HASH}`,
);
}
console.log('Fixing is done');
await fs.writeFile(`${path}_backup`, code);
await fs.writeFile(path, FIX_CONTENT);
})(); |
Olé!! I just released https://github.com/storybookjs/storybook/releases/tag/v6.4.0-alpha.32 containing PR #15874 that references this issue. Upgrade today to the
Closing this issue. Please re-open if you think there's still more to do. |
Unfortunately I still run into this issue with Storybook 6.4.0-alpha.32, Angular 12 and webpack 5:
These are the packages that are installed.
I noticed that internally Storybook or angular seems to be using Typescript 3.9 (See first line of stack trace: ...storybook/angular/dist/ts3.9/) while at project level Typescript 4.3.5 seems to be installed. Could this mismatch be a cause of the issue? |
Well, the issue was solved for me on Angular 11 LTS. However after suffering a lot with this issue and other issues I realized trying to consume from a compiled library creates LOTS of issues on storybook, so I'd highly recommend against that. This will only make your workflow unnecessarily more complex. So I edited out some private info from the develpment workflow my team will follow and made it generic for you guys. Notice how we are not consuming from a library when it comes to developing the components on storybook. We are consuming directly from the library source code and webpack does a good job at compliling it for the storybook purposes. Unfortunately I can't share the code, but find me on the Storybook Discord server if you need any help. |
Thnx for your reply. We are also running this directly against the source, but no luck with Angular 12.2.2. Previously when we were on Angular 9 with Webpack4 storybook worked correctly. |
Also still experiencing issues with our angular library project, Any chance this can be opened again? |
@saulodias @ThibaudAV any ideas why the fix didn't work? |
thanks @computergnome99 @tlaukkanen !!! |
I generally never comment on GitHub but thought to help get this issue raised. Using: I got the error listed in the main post during running the storybook website trying to render a component. After deleting all package lock and node modules folder, and doing npm install —legacy-peer-reps it fixed all my issues after running storybook. |
@jesse-schein Thanks for the confirmation! |
@jesse-schein solution works with npm. But in our monorepo we are using pnpm and I cannot find a way to make it work. We are using the last versions of Angular and Storybook with Nx. |
Hello, I'm facing the same issue with Nx, I tried to use storybook in the libs folder. Angular: 16.1.0 |
I can confirm the problem using storybook inside an In my case I don't need to add flags to My environment is:
I did some debugging and in my case the problem is in the function computesTemplateFromComponent: the const ngComponentMetadata = getComponentDecoratorMetadata(component); //undefined for me Debugging a little more inside the export const getComponentDecoratorMetadata = (component: any): Component | undefined => {
const decorators = reflectionCapabilities.annotations(component); //correctly populated
return decorators.reverse().find((d) => d instanceof Component); //failing on the test function
}; I see the I hope this could help identify the problem. |
I can confirm this error, but I have a bit more information. We started having this error after moving from Angular 12 to Angular 15, but, well, we ALSO decided to migrate to Storybook v7 at the same time. So I'm in the unique position to confirm that this happens in both 6.5.16, AND 7.3.2, in the same project, after migrating to Angular 15. Angular CLI: 15.2.8 Storybook: Both 6.5.16 AND 7.3.2, (But 7.3.2 only has this issue in a builded PROD, not dev. While 6.5.16 has this issue in DEV too.) Running npm install --legacy-peer-deps didn't work for me. Any chance someone could post their package.json? |
Did anyone successfully solve this issue? I am facing the same problem as @EliezerB123. Storybook Version: 7.4.5 Starting storybook in dev mode works perfectly fine. Running a production build and deploying the result files leads to the error. However, I encountered the following: When I use a story with the
Stories where I used a template instead of the component reference work as expected.
|
From what I can tell, this seems to be the likely source of the bug. As per https://stackoverflow.com/a/63937850/5243309 and https://stackoverflow.com/q/41587865/5243309, it seems that instanceof Component will fail when using two Which explains why npm install --legacy-peer-deps appears to solve the issue for some people. The solution seems to be to replace all the code using |
Hi, i'm facing the same problem. It occurs only when running a production build :'( Storybook Version: 7.4.6 |
HI, found solution. I hope this could help. |
Initially, I thought the same, and I already prepared a PR to not use I talked to the Angular core team, and they warned me to support this case since having multiple instances of Angular in the application is a quite broken state, and many things are likely to malfunction. The only valid solution, therefore, is to guarantee that the application loads one instance of Angular. So I thought about the reproduction, which was provided by @John-Zimmer. When creating an Angular workspace with some applications and libraries, each library might have its dependencies, which we must install. Since npm's default behavior is to install peer dependencies, a {
...
"workspaces": [
"projects/*"
],
...
} Then, a NX, on the other side, has its Single Version Policy, where all dependencies are installed in the root folder. Hence, the mentioned issues with having multiple instances of Angular should never occur. But there seem to be issues, and I am curious whether @yayassa-tootelo or @DanielAlcaraz could provide a reproduction with nx. But also, in this case, I suggest using the workspace feature of the used package manager to resolve this issue. |
Since the 7.5.0 storybook release, it is now possible to use the In our case, this has been used as a workaround for the error Here is an example of how to use it : import { argsToTemplate } from '@storybook/angular';
export const ExampleRange: Story = {
name: 'Default',
args: {
stringProp: "Foo",
objectProp : {foo: "bar"},
arrayProp: ["Foo", "Bar"]
},
render: (args) => ({
props: args,
template: `<app-my-input ${argsToTemplate(args)}></app-my-input>`
})
}; Using this on all of our stories seems to work, and we haven't found any problems at the moment. Hope this helps. Versions : |
Is there a repo or a stackblitz/codesandbox with working code? |
The only thing that fixed it for me was switching |
Maybe it helps anyone: I had the same issue. I have a Angular mono repo for libraries and storybook installed at the root. I accidentally run |
Is a solution in the works ? Versions : |
@ranceroxas Have you read my comment here: #14828 (comment). Please make sure that only one instance of Angular is used in the monorepo. Otherwise, disabling prod mode like mentioned in other comments might help as well. |
@vasa-ae, Can you tell me how your repository structure looks? If you use a mono repo, does this comment help? The main issue is that you likely have multiple Angular instances in your repository in different node_module folders. Ensure that just one instance of |
Thank you for providing all this information. First, I want to clarify that loading stories from "node_modules" isn't officially supported. We often explicitly exclude running builder plugins/loaders for Second, could you run Could you also initialize Storybook in your library |
Hi everyone, I'm facing the same issue using Angular@16, pnpm workspace and StoryBook@8. I have made a reproductible repo here. To try it out:
Hope it will help for debugging. @valentinpalkovic I have make sure that, in the Angular UI lib, angular is a peerDependency and with a I have no error in dev it's only with the builded storybook. (You can try |
@valentinpalkovic, are this exemple good for debugging what is the error ? |
Having the same issue here, any workarounds on this? |
Describe the bug
When I generate a component in an angular library (ng11), and I am going to use it in a storybook, it shows me the error of:
Cannot read property 'selector' of undefined.
To Reproduce
https://github.com/krbaio3/sb-lib-issue
System
System:
OS: macOS 11.3.1
CPU: (16) x64 Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz
Binaries:
Node: 15.14.0 - ~/.nvm/versions/node/v15.14.0/bin/node
Yarn: 1.22.10 - /usr/local/bin/yarn
npm: 7.11.2 - ~/.nvm/versions/node/v15.14.0/bin/npm
Browsers:
Chrome: 90.0.4430.93
Firefox: 88.0
Safari: 14.1
npmPackages:
@storybook/addon-actions: ^6.2.9 => 6.2.9
@storybook/addon-essentials: ^6.2.9 => 6.2.9
@storybook/addon-links: ^6.2.9 => 6.2.9
@storybook/angular: ^6.2.9 => 6.2.9
Additional context
Create an angular project:
ng new design-system --create-application=false --prefix=ds --style=scss
Create a angular-lib:
ng generate library pattern-lib --prefix=pl
Change the
name
ofdesign-system/projects/pattern-lib/package.json
to@css/pattern-lib
Change the
path
property ofdesign-system/tsconfig.json
frompattern-lib
to@css/pattern-lib
Generate the component
ng generate component button --project=pattern-lib
My button component is:
Change tsconfig properties of
design-system/projects/pattern-lib/tsconfig.lib.json
. Add this property:Generate the lib dist:
ng build
Init the storybook with
npx -p @storybook/cli sb init --type angular
Generate my custom story:
MyButton.stories.ts
I run:
npm run storybook
If I run with this code, (import { ButtonComponent } from 'projects/pattern-lib/src/public-api';) the storybook works.
But, if I change the import (commented) import { ButtonComponent } from '@css/pattern-lib'; the storybook fails, with the error Cannot read property 'selector' of undefined
The text was updated successfully, but these errors were encountered: