Storybook: μ• λ“œμ˜¨ λ¬Έμ„œ: μ†ŒμŠ€ λ¬Έμ„œ 블둝 Typescript 지원

에 λ§Œλ“  2019λ…„ 08μ›” 20일  Β·  69μ½”λ©˜νŠΈ  Β·  좜처: storybookjs/storybook

버그 μ„€λͺ…
Technical Preview κ°€μ΄λ“œμ— μ„€λͺ…λœ λŒ€λ‘œ sourceLoaderOptions: null λ₯Ό λ¬Έμ„œ 사전 섀정에 μ „λ‹¬ν•˜μ§€ μ•Šκ³  typescriptλ₯Ό μ‚¬μš©ν•˜λ©΄ λ‹€μŒ 였λ₯˜κ°€ λ°œμƒν•©λ‹ˆλ‹€.

Variable '__MODULE_DEPENDENCIES__' implicitly has an 'any[]' type

이것은 λΆˆν–‰νžˆλ„ tsconfig.json λ₯Ό μ‚¬μš©ν•˜λ„λ‘ "noImplicitAny": false tsconfig.json μŠ€ν† λ¦¬λΆμ„ μ—…λ°μ΄νŠΈν•˜μ—¬ μˆ˜μ •λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€.

μž¬ν˜„ν•˜κΈ° μœ„ν•΄
λ™μž‘μ„ μž¬ν˜„ν•˜λŠ” 단계:

  1. Typescript와 λ¬Έμ„œ 사전 섀정을 μ‚¬μš©ν•˜μ—¬ addon-docs λŒ€ν•œ μŠ€ν† λ¦¬ μž‘μ„±
  2. μŠ€ν† λ¦¬λΆ μ‹€ν–‰

μ˜ˆμƒλ˜λŠ” 행동
λ¬Έμ„œ νŽ˜μ΄μ§€κ°€ ν‰μ†Œμ™€ 같이 λ‘œλ“œλ˜κ³  μŠ€ν† λ¦¬μ— λŒ€ν•œ μ½”λ“œ μŠ€λ‹ˆνŽ«μ„ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μŠ€ν¬λ¦°μƒ·
ν•΄λ‹Ήν•˜λŠ” 경우 문제λ₯Ό μ„€λͺ…ν•˜λŠ” 데 도움이 λ˜λŠ” μŠ€ν¬λ¦°μƒ·μ„ μΆ”κ°€ν•˜μ„Έμš”.

μ½”λ“œ 쑰각
presets.js :

{
  name: '@storybook/addon-docs/react/preset',
  options: {
    sourceLoaderOptions: null,
  },
}

체계:
ν™˜κ²½ 정보:

체계:
운영 체제: macOS 10.14.5
CPU: (16) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
λ°”μ΄λ„ˆλ¦¬:
λ…Έλ“œ: 10.16.0 - /usr/local/opt/node@10/bin/node
원사: 1.17.3 - ~/workspace/component-library/node_modules/.bin/yarn
npm: 6.9.0 - /usr/local/opt/node@10/bin/npm
λΈŒλΌμš°μ €:
크둬: 76.0.3809.100
μ‚¬νŒŒλ¦¬: 12.1.1
npmνŒ¨ν‚€μ§€:
@storybook/addon-a11y: ^5.2.0-beta.36 => 5.2.0-beta.38
@storybook/addon-actions: ^5.2.0-beta.36 => 5.2.0-beta.38
@storybook/addon-docs: ^5.2.0-beta.36 => 5.2.0-beta.38
@storybook/addon-knobs: ^5.2.0-beta.36 => 5.2.0-beta.38
@storybook/addon-links: ^5.2.0-beta.36 => 5.2.0-beta.38
@storybook/addon-viewport: ^5.2.0-beta.36 => 5.2.0-beta.38
@storybook/addons: ^5.2.0-beta.36 => 5.2.0-beta.38
@storybook/preset-scss: 1.0.2 => 1.0.2
@storybook/preset-typescript: 1.1.0 => 1.1.0
@storybook/react: ^5.2.0-beta.36 => 5.2.0-beta.38
@storybook/theming: ^5.2.0-beta.36 => 5.2.0-beta.38

docs storysource source compatibility with other tools has workaround inactive typescript

κ°€μž₯ μœ μš©ν•œ λŒ“κΈ€

Awesome-typescript-loaderλ₯Ό μ‚¬μš©ν•˜λŠ” 경우 μž„μ‹œ μ†”λ£¨μ…˜:

/* tsconfig.json */
{
  "compilerOptions": { },
  "awesomeTypescriptLoaderOptions": {
    "ignoreDiagnostics": [7005]
  }
}

μ΄μƒμ μ΄μ§€λŠ” μ•Šμ§€λ§Œ μž‘λ™ν•©λ‹ˆλ‹€.

λͺ¨λ“  69 λŒ“κΈ€

@enagy27 κ°μ‚¬ν•©λ‹ˆλ‹€! μ—¬κΈ°μ—λŠ” μ΅œμ†Œν•œ λͺ‡ 가지 μ˜΅μ…˜μ΄ μžˆμŠ΅λ‹ˆλ‹€.

1) source-loader λŠ” νƒ€μ΄ν”„μŠ€ν¬λ¦½νŠΈμ— 더 μΉœμˆ™ν•œ μ½”λ“œλ₯Ό 좜λ ₯ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
2) μ‚¬μš©μžλŠ” typescriptλ₯Ό λ‹€λ₯΄κ²Œ ꡬ성할 수 μžˆμŠ΅λ‹ˆλ‹€(λͺ¨λ…Έλ ˆν¬μ—μ„œ λ³Έ 적이 μ—†μŒ)
3) source-loader λŠ” ν•΄κ²° λ°©λ²•μœΌλ‘œ @ts-ignore λ₯Ό 좜λ ₯ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

제 μƒκ°μ—λŠ” μ„Έ 번째 μ˜΅μ…˜μ΄ μ‹œμž‘ν•˜κΈ° κ°€μž₯ κ°„λ‹¨ν•˜κ³  첫 번째 μ˜΅μ…˜μ΄ μž₯기적으둜 κ°€μž₯ 쒋을 κ²ƒμž…λ‹ˆλ‹€.

μœ„λŒ€ν•œ 카이사λ₯΄μ˜ 유령!! 이 문제λ₯Ό μ°Έμ‘°ν•˜λŠ” PR #7831이 ν¬ν•¨λœ https://github.com/storybookjs/storybook/releases/tag/v5.2.0-beta.39 λ₯Ό 방금 μΆœμ‹œν–ˆμŠ΅λ‹ˆλ‹€. μ§€κΈˆ μ—…κ·Έλ ˆμ΄λ“œν•˜μ—¬ μ‚¬μš©ν•΄ λ³΄μ„Έμš”!

이 μ‹œν—˜νŒμ€ @next NPM νƒœκ·Έμ—μ„œ 찾을 수 μžˆμŠ΅λ‹ˆλ‹€.

이 문제λ₯Ό λ‹«μŠ΅λ‹ˆλ‹€. 아직 ν•  일이 더 μžˆλ‹€κ³  μƒκ°λ˜λ©΄ λ‹€μ‹œ μ—΄μ–΄μ£Όμ„Έμš”.

@enagy27 μ—λŠ” μž¬ν˜„μ΄ μ—†μœΌλ―€λ‘œ μ‹œλ„ν•΄ λ³΄μ‹œκ³  μž‘λ™ν•˜λŠ”μ§€ μ•Œλ €μ£Όλ©΄ 쒋을 κ²ƒμž…λ‹ˆλ‹€.

@shilman μ ˆλŒ€! μ§€κΈˆ 도전해 λ³΄μ„Έμš”. κ°μ‚¬ν•©λ‹ˆλ‹€!

@shilman은 μ—¬μ „νžˆ beta.39 μ—μ„œ 이 였λ₯˜λ₯Ό 보고 μžˆμŠ΅λ‹ˆλ‹€ 😞

ERROR in /Users/eric.nagy/workspace/component-library/src/elements/tag/tag.stories.tsx
./src/elements/tag/tag.stories.tsx
[tsl] ERROR in /Users/eric.nagy/workspace/component-library/src/elements/tag/tag.stories.tsx(69,52)
      TS7005: Variable '__MODULE_DEPENDENCIES__' implicitly has an 'any[]' type.

ERROR in /Users/eric.nagy/workspace/component-library/src/elements/tag/tag.stories.tsx
./src/elements/tag/tag.stories.tsx
[tsl] ERROR in /Users/eric.nagy/workspace/component-library/src/elements/tag/tag.stories.tsx(74,3)
      TS2300: Duplicate identifier 'parameters'.

npx -p @storybook/cli<strong i="10">@next</strong> sb info

Environment Info:

  System:
    OS: macOS 10.14.5
    CPU: (16) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
  Binaries:
    Node: 10.16.0 - /usr/local/opt/node@10/bin/node
    Yarn: 1.17.3 - ~/workspace/component-library/node_modules/.bin/yarn
    npm: 6.9.0 - /usr/local/opt/node@10/bin/npm
  Browsers:
    Chrome: 76.0.3809.100
    Safari: 12.1.1
  npmPackages:
    @storybook/addon-a11y: ^5.2.0-beta.39 => 5.2.0-beta.39 
    @storybook/addon-actions: ^5.2.0-beta.39 => 5.2.0-beta.39 
    @storybook/addon-docs: ^5.2.0-beta.39 => 5.2.0-beta.39 
    @storybook/addon-knobs: ^5.2.0-beta.39 => 5.2.0-beta.39 
    @storybook/addon-links: ^5.2.0-beta.39 => 5.2.0-beta.39 
    @storybook/addon-viewport: ^5.2.0-beta.39 => 5.2.0-beta.39 
    @storybook/addons: ^5.2.0-beta.39 => 5.2.0-beta.39 
    @storybook/preset-scss: 1.0.2 => 1.0.2 
    @storybook/preset-typescript: 1.1.0 => 1.1.0 
    @storybook/react: ^5.2.0-beta.39 => 5.2.0-beta.39 
    @storybook/theming: ^5.2.0-beta.39 => 5.2.0-beta.39

이것이 μ†ŒμŠ€ λ‘œλ”μ— μžˆλ‹€λŠ” 점을 κ°μ•ˆν•  λ•Œ λ³„λ„λ‘œ μ„€μΉ˜ν•΄μ•Ό ν•˜κ³  사전 섀정에 μ˜ν•΄ μ±„νƒλ˜μ–΄μ•Ό ν•©λ‹ˆκΉŒ, μ•„λ‹ˆλ©΄ 사전 μ„€μ •μ˜ μƒˆ λ¦΄λ¦¬μŠ€κ°€ ν•„μš”ν•œκ°€μš”?

@enagy27 μ—¬κΈ° 지침을 μ‚¬μš©ν•˜μ—¬ λ‘œλ“œλœ μ†ŒμŠ€λ₯Ό μ‚΄νŽ΄λ³΄κ³  λ‘œλ“œλœ μ†ŒμŠ€μ— #7831의 λ³€κ²½ 사항이 ν¬ν•¨λ˜μ–΄ μžˆλŠ”μ§€ 확인할 수 μžˆμŠ΅λ‹ˆκΉŒ? ( .mdx λ₯Ό .tsx λ°”κΎΈκ³  λ‚˜λ¨Έμ§€λŠ” μ μš©ν•΄μ•Ό 함)

https://github.com/storybookjs/storybook/blob/next/addons/docs/docs/faq.md#how -do-i-debug-my-mdx-story

@shilman μ €λŠ” sourceLoaderOptions: null κ°€ 적용될 λ•Œλ§Œ μ„œλ²„λ₯Ό μ‹œμž‘ν•  수 μžˆμŠ΅λ‹ˆλ‹€ 😞 그렇지 μ•ŠμœΌλ©΄ μ‹€νŒ¨ν•œ λΉŒλ“œκ°€ μ„œλ²„ μ‹œμž‘μ„ μ€‘λ‹¨ν•˜κ³  λΈŒλΌμš°μ € λ‚΄ μ†ŒμŠ€λ₯Ό 검사할 수 μ—†μŠ΅λ‹ˆλ‹€. 첫 번째 λΉŒλ“œ μ‹€νŒ¨ μ‹œ μ„œλ²„λ₯Ό μš°νšŒν•˜κ³  μ‹œμž‘ν•˜λŠ” λͺ…령쀄 μ˜΅μ…˜μ΄ μžˆμŠ΅λ‹ˆκΉŒ?

야단법석!! 이 문제λ₯Ό μ°Έμ‘°ν•˜λŠ” PR #7845κ°€ ν¬ν•¨λœ https://github.com/storybookjs/storybook/releases/tag/v5.2.0-beta.40 을 방금 μΆœμ‹œν–ˆμŠ΅λ‹ˆλ‹€. μ§€κΈˆ μ—…κ·Έλ ˆμ΄λ“œν•˜μ—¬ μ‚¬μš©ν•΄ λ³΄μ„Έμš”!

이 μ‹œν—˜νŒμ€ @next NPM νƒœκ·Έμ—μ„œ 찾을 수 μžˆμŠ΅λ‹ˆλ‹€.

@enagy27 λ³€κ²½ 사항을 병합 및 λ¦΄λ¦¬μŠ€ν–ˆμŠ΅λ‹ˆλ‹€. μ‹œλ„ 해봐?

@shilman 그런 ν–‰μš΄μ€ μ—†μŠ΅λ‹ˆλ‹€ 😞 μ €λŠ” ν˜„μ§€μ—μ„œ μ‹€ν—˜ν•˜κ³  μžˆλŠ”λ° 잘 λͺ» ν•˜λŠ” 것 κ°™μŠ΅λ‹ˆλ‹€. λ‚˜λŠ” μ†μž„μˆ˜λ₯Ό μ“°κ³  λͺ¨λ‘ as any ν–ˆμ§€λ§Œ 쀑볡 λ³€μˆ˜ parameters 에 λŒ€ν•΄ λΆˆν‰ν•˜λŠ” κ²ƒμ²˜λŸΌ λ³΄μ΄λ―€λ‘œ __STORY__ 이 μ œλŒ€λ‘œ μ΄μŠ€μΌ€μ΄ν”„λ˜μ§€ μ•ŠλŠ”μ§€ κΆκΈˆν•©λ‹ˆλ‹€. ν•˜μ§€λ§Œ TSκ°€ μ•„λ‹Œ JSμ—μ„œ μ–΄λ–»κ²Œ μž‘λ™ν•˜λŠ”μ§€ μ•Œ 수 μ—†μŠ΅λ‹ˆλ‹€...

저도 이 문제λ₯Ό κ²ͺκ³  μžˆμ§€λ§Œ λΆˆν–‰νžˆλ„ μΆ”κ°€ μ»¨ν…μŠ€νŠΈκ°€ λ§Žμ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

μ—¬κΈ°μ„œ 또 λ‹€λ₯Έ 해결책은 μŠ€ν† λ¦¬λΆμ΄ λ‘œλ“œν•˜λŠ” tsconfig.js 파일의 λͺ¨λ“  "μ—„κ²©ν•œ" μœ ν˜• 검사 κ·œμΉ™μ„ μž¬μ •μ˜ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€(ν”„λ‘œμ νŠΈμ˜ tsconfig λ˜λŠ” .storybook/tsconfig.js (λ‚΄ μƒκ°μ—λŠ”)).

λ‹€μŒμ΄ ν™œμ„±ν™”λ˜μ–΄ μžˆμ§€ μ•Šμ€μ§€ ν™•μΈν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.
image

@libetl λ°”μ˜μ‹ κ±΄ μ•Œκ² λŠ”λ° 이것 μ’€ λ΄μ£Όμ‹œλ©΄ κ°μ‚¬ν•˜κ² μŠ΅λ‹ˆλ‹€.

@JonKrone 이 μž‘μ—…μ„ μˆ˜ν–‰ν•˜λ©΄ λ¬Έμ„œ 탭에 μ†ŒμŠ€ μ½”λ“œκ°€ ν‘œμ‹œλ©λ‹ˆκΉŒ? μ΄λ ‡κ²Œ μˆ˜μ •ν–ˆλŠ”λ°λ„ μ†ŒμŠ€κ°€ μ•ˆλ³΄μ΄λ„€μš” 😞

Awesome-typescript-loaderλ₯Ό μ‚¬μš©ν•˜λŠ” 경우 μž„μ‹œ μ†”λ£¨μ…˜:

/* tsconfig.json */
{
  "compilerOptions": { },
  "awesomeTypescriptLoaderOptions": {
    "ignoreDiagnostics": [7005]
  }
}

μ΄μƒμ μ΄μ§€λŠ” μ•Šμ§€λ§Œ μž‘λ™ν•©λ‹ˆλ‹€.

@shilman 이것이 당신이 μ°Ύκ³  μžˆλŠ” κ²ƒμž…λ‹ˆκΉŒ? 참고둜 이것은 TS7005(μ•”μ‹œμ  μ—†μŒ)λ₯Ό λ¬΄μ‹œν•˜μ§€ μ•Šκ³ λŠ” λΉŒλ“œλ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

  // @ts-ignore
  var withSourceLoader = require('@storybook/source-loader/preview').withSource;
  // @ts-ignore
  var __SOURCE_PREFIX__ = "/home/user/projects/real/ts/my-blog-react/src/graphql";
  // @ts-ignore
  var __STORY__ = "import React from \"react\";\n\nimport { ApolloProvider } from \"@apollo/react-hooks\";\nimport { storiesOf } from \"@storybook/react\";\n\nimport { Posts } from \"../views/Posts/index\"; // ! Fix coupling\nimport { PostContent } from \"../views/PostContent\"; // ! Fix coupling\nimport { withPostContentQuery } from \"./components/withPostContentQuery\";\nimport { withPostsQuery } from \"./components/withPostsQuery\";\nimport * as fakeQl from \"./fakeql/fakeql-endpoints\";\nimport apolloClientFactory from \"./apollo\";\n\n// FIXME: #coupling - find a way to not depend on Post and Container, probably fakes - but not good enough.\n\nconst apolloClient = apolloClientFactory(fakeQl.normalApiEndpoint);\nconst PostContentQuery = withPostContentQuery(PostContent);\nconst PostsQuery = withPostsQuery(Posts);\n\n// ~~~ Posts ~~~\nstoriesOf(\"GraphQL\", module).add(\"PostsQuery\", () => (\n  <ApolloProvider client={apolloClient}>\n    <PostsQuery routeHandler={() => null} />\n  </ApolloProvider>\n));\n\n// ~~~ PostContent ~~~\nstoriesOf(\"GraphQL\", module).add(\"PostContentQuery\", () => (\n  <ApolloProvider client={apolloClient}>\n    <PostContentQuery postId=\"1\" />\n  </ApolloProvider>\n));\n";
  // @ts-ignore
  var __ADDS_MAP__ = {"graphql--postsquery":{"startLoc":{"col":33,"line":20},"endLoc":{"col":1,"line":24},"startBody":{"col":47,"line":20},"endBody":{"col":1,"line":24}},"graphql--postcontentquery":{"startLoc":{"col":33,"line":27},"endLoc":{"col":1,"line":31},"startBody":{"col":53,"line":27},"endBody":{"col":1,"line":31}}};
  // @ts-ignore
  var __MAIN_FILE_LOCATION__ = "/root.stories.tsx";
  // @ts-ignore
  var __MODULE_DEPENDENCIES__ = [];
  // @ts-ignore
  var __LOCAL_DEPENDENCIES__ = {};
  // @ts-ignore
  var __IDS_TO_FRAMEWORKS__ = {};

  import React from "react";

import { ApolloProvider } from "@apollo/react-hooks";
import { storiesOf } from "@storybook/react";

import { Posts } from "../views/Posts/index"; // ! Fix coupling
import { PostContent } from "../views/PostContent"; // ! Fix coupling
import { withPostContentQuery } from "./components/withPostContentQuery";
import { withPostsQuery } from "./components/withPostsQuery";
import * as fakeQl from "./fakeql/fakeql-endpoints";
import apolloClientFactory from "./apollo";

// FIXME: #coupling - find a way to not depend on Post and Container, probably fakes - but not good enough.

const apolloClient = apolloClientFactory(fakeQl.normalApiEndpoint);
const PostContentQuery = withPostContentQuery(PostContent);
const PostsQuery = withPostsQuery(Posts);

// ~~~ Posts ~~~
storiesOf("GraphQL", module).addParameters({ storySource: { source: __STORY__, locationsMap: __ADDS_MAP__ } }).addDecorator(withSourceLoader(__STORY__, __ADDS_MAP__,__MAIN_FILE_LOCATION__,__MODULE_DEPENDENCIES__,__LOCAL_DEPENDENCIES__,__SOURCE_PREFIX__,__IDS_TO_FRAMEWORKS__)).add("PostsQuery", () => (
  <ApolloProvider client={apolloClient}>
    <PostsQuery routeHandler={() => null} />
  </ApolloProvider>
));

// ~~~ PostContent ~~~
storiesOf("GraphQL", module).addParameters({ storySource: { source: __STORY__, locationsMap: __ADDS_MAP__ } }).addDecorator(withSourceLoader(__STORY__, __ADDS_MAP__,__MAIN_FILE_LOCATION__,__MODULE_DEPENDENCIES__,__LOCAL_DEPENDENCIES__,__SOURCE_PREFIX__,__IDS_TO_FRAMEWORKS__)).add("PostContentQuery", () => (
  <ApolloProvider client={apolloClient}>
    <PostContentQuery postId="1" />
  </ApolloProvider>
));


@0b10 ν•œλ²ˆ ν•΄λ³Όκ»˜μš” κ°μ‚¬ν•©λ‹ˆλ‹€! μš°λ¦¬λŠ” ν˜„μž¬ λͺ¨λ“  쀄을 λ¬΄μ‹œν•˜κ³  μžˆμ§€λ§Œ λ‚΄ tsconfig.json 도 λ³€κ²½ν•  생각은 ν•˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€ πŸ€”

Storybook-react-routerλ₯Ό 1.0.6으둜 μ—…λ°μ΄νŠΈν•œ ν›„ μ—¬κΈ°μ—μ„œ 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€. λ¬Έμ œκ°€ μ—΄λ € μžˆμŠ΅λ‹ˆλ‹€. gvaldambrini/storybook-router#42 여기에 였λ₯˜κ°€ ν‘œμ‹œλ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€(storybook-router 였λ₯˜λŠ” 관련이 없을 수 μžˆμŠ΅λ‹ˆλ‹€. μ•„λž˜ 주석 μ°Έμ‘° )

λ‚΄ TSX μŠ€ν† λ¦¬μ—μ„œ "μ‚¬μš© κ°€λŠ₯ν•œ μ½”λ“œ μ—†μŒ", MDXλŠ” μ œλŒ€λ‘œ μž‘λ™ν•˜κ³  κ²°κ³ΌλŠ” @0b10 의 μŠ€ν† λ¦¬μ™€ μœ μ‚¬/μ •ν™•ν•˜κ²Œ λ³΄μž…λ‹ˆλ‹€.

  // @ts-ignore
  var withSourceLoader = require('@storybook/source-loader/preview').withSource;
  // @ts-ignore
  var __SOURCE_PREFIX__ = "C:\\Workspace\\application-ui\\src\\components\\atoms\\container";
  // @ts-ignore
  var __STORY__ = "import { storiesOf } from \"@storybook/react\";\nimport React, { ReactElement } from \"react\";\n\nimport { Container } from \"components\";\n\nconst stories = storiesOf(\"Atoms/Container\", module).addParameters({ component: Container });\n\nstories.add(\"Default\", (): ReactElement => <Container>Hello</Container>);\n";
  // @ts-ignore
  var __ADDS_MAP__ = {};
  // @ts-ignore
  var __MAIN_FILE_LOCATION__ = "/Container.stories.tsx";
  // @ts-ignore
  var __MODULE_DEPENDENCIES__ = [];
  // @ts-ignore
  var __LOCAL_DEPENDENCIES__ = {};
  // @ts-ignore
  var __IDS_TO_FRAMEWORKS__ = {};

  import { storiesOf } from "@storybook/react";
import React, { ReactElement } from "react";

import { Container } from "components";

const stories = storiesOf("Atoms/Container", module).addParameters({ storySource: { source: __STORY__, locationsMap: __ADDS_MAP__ } }).addDecorator(withSourceLoader(__STORY__, __ADDS_MAP__,__MAIN_FILE_LOCATION__,__MODULE_DEPENDENCIES__,__LOCAL_DEPENDENCIES__,__SOURCE_PREFIX__,__IDS_TO_FRAMEWORKS__)).addParameters({ component: Container });

stories.add("Default", (): ReactElement => <Container>Hello</Container>);

docs: DocsPage μ˜€μœΌλ―€λ‘œ config.jsλ₯Ό μ—…λ°μ΄νŠΈν–ˆμŠ΅λ‹ˆλ‹€.

    docs: {
        container: DocsContainer,
        page: DocsPage,
    },

사전 μ„€μ •:

module.exports = [
    {
        name: "@storybook/addon-docs/react/preset",
        options: {
            configureJSX: true,
        },
    },
];

Webpack ꡬ성, μ•„λ§ˆλ„ ν•„μš”ν•˜μ§€ μ•ŠμŠ΅λ‹ˆκΉŒ?

    config.module.rules.push({
        exclude: /node_modules/,
        test: /\.(ts|tsx)$/,
        use: [
            {
                loader: require.resolve("babel-loader"),
                options: {
                    presets: [["react-app", { flow: false, typescript: true }]],
                },
            },
            {
                loader: require.resolve("react-docgen-typescript-loader"),
            },
        ],
    });

    config.module.rules.push({
        enforce: "pre",
        include: [path.resolve(__dirname, "../src")],
        loader: require.resolve("@storybook/source-loader"),
        test: /\.(stories|story)\.[tj]sx?$/,
    });

tsconfig.json은 "noImplicitAny": true ν•˜κ³  ignoreDiagnostics λŠ” ν¬ν•¨ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€ πŸ˜•

rc.4 더 이상 λ¬Έμ œκ°€ ν‘œμ‹œλ˜μ§€ μ•Šμ§€λ§Œ μ†ŒμŠ€κ°€ μ—†μŠ΅λ‹ˆλ‹€ 😞 #6641에도 ν‘œμ‹œλœ κ²ƒμ²˜λŸΌ λ³΄μ΄μ§€λ§Œ 였λ₯˜κ°€ 더 이상 μ‘΄μž¬ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ 이 λ¬Έμ œλŠ” 쀑볡될 수 μžˆμŠ΅λ‹ˆλ‹€.

ν•΄κ²° 방법을 μ°Ύμ•˜μŠ΅λ‹ˆλ‹€!

  • sourceLoaderOptions: null λ₯Ό μ‚¬μš©ν•˜λŠ” λŒ€μ‹  transpileOnly: true μ—μ„œ tsLoaderOptions
  • μ΅œμƒμœ„ parameters λ³€μˆ˜κ°€ μžˆμ„ 수 μ—†λŠ” #8055의 ν•΄κ²° 방법을 λ”°λ₯΄μ‹­μ‹œμ˜€.
  • μ–΄λ–€ 이유둜 as 'optionA' | 'optionB' 와 같은 였λ₯Έμͺ½ λ¬Έ μ‚¬μš©μ€ μ—¬κΈ°μ—μ„œ μ‹€νŒ¨ν–ˆμœΌλ©° μ™Όμͺ½ ν˜•μ‹ μ„ μ–ΈμœΌλ‘œ λ³€ν™˜ν•΄μ•Ό ν–ˆμŠ΅λ‹ˆλ‹€.

이것은 μ‹€νŒ¨ν•©λ‹ˆλ‹€:

const colors = {
  primary: 'primary',
  secondary: 'secondary',
};

const color = radios('color', colors, colors.primary) as ButtonColor;

이것은 μž‘λ™ν•©λ‹ˆλ‹€:

const colors: Record<string, ButtonColor> = {
  primary: 'primary',
  secondary: 'secondary',
};

const color = radios('color', colors, colors.primary);

돌이켜보면 이것은 μœ ν˜• μΆ”λ‘  πŸ€”κ³Ό κ΄€λ ¨λœ 이해할 수 μžˆλŠ” source-loader 문제인 것 κ°™μŠ΅λ‹ˆλ‹€. μ–΄μ¨Œλ“  이것이 도움이 되기λ₯Ό λ°”λžλ‹ˆλ‹€!

@enagy27 당신은 이것을 μ•Œμ•„λ‚΄λŠ” 것에 λŒ€ν•΄ λ°”μœ„μž…λ‹ˆλ‹€. @libetl 이 5.3의 μ–΄λŠ μ‹œμ μ—μ„œ λ‹€μ‹œ 온라인 μƒνƒœκ°€ 되기λ₯Ό 바라며 μ΄λŸ¬ν•œ ν•΄κ²° 방법이 ν•„μš”ν•˜μ§€ μ•Šλ„λ‘ source-loader μ—…κ·Έλ ˆμ΄λ“œν•˜λ©΄ λ©λ‹ˆλ‹€. 손가락이 ꡐ차! 🀞

μ•ˆλ…•ν•˜μ„Έμš”. λˆ„κ΅°κ°€ λ°˜μ‘ν˜• μŠ€ν¬λ¦½νŠΈμ™€ λ¬Έμ„œκ°€ μžˆλŠ” μŠ€ν† λ¦¬λΆμ΄ μž‘λ™ν•˜λŠ” 예제 리포지토리λ₯Ό μ œκ³΅ν•  수 μžˆμŠ΅λ‹ˆκΉŒ?

@simonhoss 이것은 쒋은 μ•„μ΄λ””μ–΄μž…λ‹ˆλ‹€. 이 μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ” 데 정말 어렀움을 κ²ͺκ³  μžˆμŠ΅λ‹ˆλ‹€.

λ‚˜λ„ πŸ˜„

TS 지침은 addon-info λ₯Ό μ„€μΉ˜ν•˜λΌλŠ” react-docgen-typescript-loader λ₯Ό κ°€λ¦¬ν‚€μ§€λ§Œ μ„€λͺ…μ„œμ˜ μ•žλΆ€λΆ„μ—λŠ” addon-docs κ°€ addon-info 의 λŒ€μ²΄ν’ˆμ΄λΌκ³  λ‚˜μ™€ μžˆμ§€ μ•ŠμŠ΅λ‹ˆκΉŒ? TSμ—μ„œ μž‘λ™ν•˜λŠ” μ„€μ •μ΄λ‚˜ TS둜 addon-docs λ₯Ό μ„€μ •ν•˜κΈ° μœ„ν•œ λͺ…ν™•ν•œ 지침을 ν•œ κ³³μ—μ„œ ν™•μΈν•˜λŠ” 데 큰 도움이 될 κ²ƒμž…λ‹ˆλ‹€.

기꺼이 κΈ°μ—¬ν•˜κ³  도움을 μ£Όμ§€λ§Œ 이 쑰각듀이 μ–΄λ–»κ²Œ μ„œλ‘œ 잘 λ§žλŠ”μ§€ λ¨Όμ € 이해해야 ν•©λ‹ˆλ‹€! πŸ‘

이제 λ¬Έμ„œκ°€ λ¦΄λ¦¬μŠ€λ˜μ—ˆμœΌλ―€λ‘œ cra-ts-kitchen-sink λ₯Ό μ—…λ°μ΄νŠΈν•˜μ—¬ ꡬ성에 λŒ€ν•΄ λͺ¨λ‘ 같은 νŽ˜μ΄μ§€μ— μžˆλŠ”μ§€ ν™•μΈν•˜λŠ” 데 μ‹œκ°„μ΄ 걸릴 수 μžˆμŠ΅λ‹ˆλ‹€. πŸ™‚ 일주일 정도 걸릴 수 μžˆμ§€λ§Œ... μ§€κΈˆμ€ λ‚΄ ꡬ성을 μ œκ³΅ν•˜κ² μŠ΅λ‹ˆλ‹€.

.storybook/addons.js

import '@storybook/addon-knobs/register';
import '@storybook/addon-a11y/register';
import '@storybook/addon-actions/register';

.μŠ€ν† λ¦¬λΆ/config.js

import { configure, addDecorator, addParameters } from '@storybook/react';
import { withA11y } from '@storybook/addon-a11y';
import { withKnobs } from '@storybook/addon-knobs';

import theme from './theme';
import '../stylesheets/gusto.scss';

// This file overrides styles from the global Gusto
// styles which interfere with Storybook styles
import './storybook.scss';

// Is your addon not showing up? Try looking for a `register` function
// and add it to .storybook/addons.js
addDecorator(withA11y);
addDecorator(withKnobs);

addParameters({
  // storybook built-in
  // more info available here:
  // https://storybook.js.org/docs/configurations/options-parameter/
  options: {
    showPanel: true,
    panelPosition: 'right',
    // https://storybook.js.org/docs/configurations/theming/
    theme,
  },
  knobs: {
    escapeHTML: false,
  },
  // viewport structure here:
  // https://github.com/storybookjs/storybook/tree/master/addons/viewport#use-custom-set-of-devices
  // viewport: {
  //   defaultViewport: 'iphone6',
  //   type: 'mobile',
  // },
});

configure(require.context('../src', true, /\.stories\.(js|jsx|ts|tsx|mdx)$/), module);

.storybook/presets.js

const path = require('path');

module.exports = [
  '@storybook/preset-scss',
  {
    name: '@storybook/preset-typescript',
    options: {
      // Point the loader here to override the root "noEmit" compilerOption
      tsLoaderOptions: {
        // Transpile only means no type-checking from storybook, which greatly speeds up
        // builds. Types will be checked as part of the normal build process. This may also
        // be necessary for loading story source
        transpileOnly: true,
        configFile: path.resolve(__dirname, 'tsconfig.json'),
      },
      // We must use our config to ensure props and their comments are loaded
      tsDocgenLoaderOptions: {
        tsconfigPath: path.resolve(__dirname, 'tsconfig.json'),
        // https://github.com/styleguidist/react-docgen-typescript#parseroptions
        propFilter: prop => {
          if (prop.parent) {
            return !prop.parent.fileName.includes('node_modules/@types/react/');
          }

          return true;
        },
      },
    },
  },
  '@storybook/addon-docs/react/preset',
];

.storybook/theme.js

이것은 우리 νšŒμ‚¬ 내뢀이기 λ•Œλ¬Έμ— κ³΅μœ ν•  수 μ—†μ§€λ§Œ config.js μ—μ„œ μ°Έμ‘°λ©λ‹ˆλ‹€.

.μŠ€ν† λ¦¬λΆ/tsconfig.json

이 νŒŒμΌμ€ 루트 tsconfig.json ꡬ성을 μ œκ±°ν•˜λŠ” μ—­ν• λ§Œ ν•˜λ©° μ΄λŠ” μ—¬κΈ° μŠ€ν† λ¦¬λΆμ—μ„œ μ˜λ―Έκ°€ μ—†μŠ΅λ‹ˆλ‹€.

{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "noEmit": false
  }
}

μ•ˆλ…•ν•˜μ„Έμš” @enagy27 - κ°μ‚¬ν•©λ‹ˆλ‹€. λ‚˜λŠ” 이것을 μ‚¬μš©μž μ •μ˜ webpack κ΅¬μ„±μœΌλ‘œ μž‘μ—…ν–ˆμŠ΅λ‹ˆλ‹€. μ΄μƒν•œ 이유둜 typescript 사전 섀정을 μ‚¬μš©ν•˜λ©΄ μŠ€ν† λ¦¬λΆμ˜ 에셋(예: CSS 파일)을 κ°€μ Έμ˜¬ 수 μ—†μŠ΅λ‹ˆλ‹€.

λ‚΄κ°€ μ§λ©΄ν•œ ν•œ 가지 μž‘μ€ λ¬Έμ œλŠ” λ‚΄ props ν…Œμ΄λΈ”μ΄ λ‹€μŒκ³Ό 같은 μœ ν˜•μ„ μœ μΆ”ν•  수 μ—†λ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€.

SomeType['property'] μ§€κΈˆ λ‚΄ ν…Œμ΄λΈ”μ— Union λŒ€μ‹  any κ°€ ν‘œμ‹œλ©λ‹ˆλ‹€. 이 문제λ₯Ό ν•΄κ²°ν•  수 μžˆλŠ” 방법이 μžˆλŠ”μ§€ κΆκΈˆν•©λ‹ˆλ‹€.

μ•ˆλ…•ν•˜μ„Έμš” @enagy27μž…λ‹ˆλ‹€. κ°μ‚¬ν•©λ‹ˆλ‹€. κ³΅μœ ν•œ κ΅¬μ„±μœΌλ‘œ 이 μž‘μ—…μ„ μˆ˜ν–‰ν–ˆμŠ΅λ‹ˆλ‹€.ν•˜μ§€λ§Œ μ—¬μ „νžˆ λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆλ‹€. tsx둜 componentλ₯Ό μž‘μ„±ν•  λ•Œ component descriptionκ³Ό props description을 생성할 수 μ—†μŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ 그것은 jsx와 ν•¨κ»˜ μž‘λ™ν•©λ‹ˆλ‹€γ€‚
image
image
image

μ•ˆλ…•ν•˜μ„Έμš” @zerofrontμž…λ‹ˆλ‹€. λ‚˜λŠ” 이 μ •ν™•ν•œ λŒ“κΈ€ νŒ¨ν„΄μ„ 따라야 ν–ˆλ‹€

ꡬ성 μš”μ†Œ μ„€λͺ…:

/**
 * This is a component description and should sit directly above your component
 */

μ†Œν’ˆ μ„€λͺ…:

/** I am a prop description and should sit directly above the interface property i am describing */

@enagy27 사싀 첫 사진에 보여

@zerofront ꡬ성 μš”μ†Œμ— λŒ€ν•œ Typescript μœ ν˜•μ΄ ν•„μš”ν•©λ‹ˆλ‹€. λŒ€μ‹  export const Button: React.FC<BaseButtonProps> = props => {...} λ₯Ό μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

πŸ‘† TS 및 docgen을 μ‚¬μš©ν•œ 섀정이 μ–΄λ–€ 이유둜 μ œλ„€λ¦­μ—μ„œ μž‘λ™ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. μ—¬κΈ° #8143μ—μ„œ μ„€λͺ…ν•˜λŠ” λ¬Έμ œκ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€.

@zerofront μ •ν™•νžˆ κ·€ν•˜μ˜ λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆλ‹€. Button λ¬Έμ„œμ˜ μ†Œν’ˆ μ„Ήμ…˜μ—μ„œ Storybook은 BaseButtonProps μΈν„°νŽ˜μ΄μŠ€ λŒ€μ‹  defaultProps λ₯Ό μΈμ‡„ν•©λ‹ˆλ‹€. 그리고 μ„€λͺ…도 μƒλž΅ν•©λ‹ˆλ‹€. μžλ§‰μ— λŒ€ν•΄ λ‹€μŒκ³Ό 같이 μŠ€ν† λ¦¬ νŒŒμΌμ— μΆ”κ°€ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

export default {
  title: 'Button',
  component: Button,
  parameters: {
    componentSubtitle: 'Handy status label',
  },
}

@zerofront @enagy27이 λ§ν•œ 것 외에도.
*.stories.tsx 둜 μž‘μ—…ν•˜λ €λ©΄ λ‹€μŒ ꡬ성과 같은 것을 μΆ”κ°€ν•΄μ•Ό ν•©λ‹ˆλ‹€.

.storybook/webpack.config.js

const path = require('path');
const include = path.resolve(__dirname, '../src');

module.exports = ({ config }) => {
  config.module.rules.push({
    test: /\.ts(x?)$/,
    exclude: /node_modules/,
    use: [
      {
        loader: require.resolve('babel-loader'),
        options: {
          presets: [['react-app', { flow: false, typescript: true }]],
        },
      },
    ],
    include,
  });
  return config;
};

@zerofront ꡬ성 μš”μ†Œμ— λŒ€ν•œ Typescript μœ ν˜•μ΄ ν•„μš”ν•©λ‹ˆλ‹€. λŒ€μ‹  export const Button: React.FC<BaseButtonProps> = props => {...} λ₯Ό μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

@zerofront @enagy27 μ–΄μ œ λ‚΄ 문제(@zerofront와 λΆ„λͺ…νžˆ 동일함)κ°€ ν•¨μˆ˜μ˜ λ°˜ν™˜ μœ ν˜•μœΌλ‘œ 인해 λ°œμƒν–ˆλ‹€λŠ” 것을 λ°œκ²¬ν–ˆμŠ΅λ‹ˆλ‹€.

이것은 λ‚˜λ₯Ό μœ„ν•΄ μˆ˜μ •λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

- import React from 'react'
+ import React, { FC } from 'react'

- export const Button: React.FC<Props>
+ export const Button: FC<Props>

μ›μ²œ:
https://github.com/strothj/react-docgen-typescript-loader/issues/42#issuecomment -535090697
λΆ€λΆ„μ μœΌλ‘œ 이 λ©”λͺ¨λŠ” λ‹€μŒκ³Ό 관련될 수 μžˆμŠ΅λ‹ˆλ‹€.
https://github.com/strothj/react-docgen-typescript-loader#react -component-class-import

도움이 될 수 있기λ₯Ό λ°”λžλ‹ˆλ‹€.

@sergiop @enagy27 κ°μ‚¬ν•©λ‹ˆλ‹€! κ²°κ΅­ props ν…Œμ΄λΈ”μ΄ μž‘λ™ν•©λ‹ˆλ‹€.
κ·ΈλŸ¬λ‚˜ μ—¬μ „νžˆ λͺ‡ 가지 λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆλ‹€.

defaultPropsκ°€ stringν˜•μ΄ μ•„λ‹ˆλ©΄ 생성할 수 μ—†μŠ΅λ‹ˆλ‹€.
image

image

@zerofront λ™μΌν•œ λ¬Έμ œκ°€ μžˆμŒμ„ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€. ν•΄κ²°ν•΄μ•Ό ν•  문제 λͺ©λ‘μ— μžˆμŠ΅λ‹ˆλ‹€. ;-)
원인을 μ°Ύκ³  μ‹Άλ‹€λ©΄ μŠ€ν† λ¦¬λΆ μžμ²΄μ™€ 관련이 μžˆλŠ”μ§€ μ•„λ‹ˆλ©΄ react-docgen-typescript-loader 와 관련이 μžˆλŠ”μ§€ μ΄ν•΄ν•˜κΈ° μ‹œμž‘ν•΄μ•Ό ν•©λ‹ˆλ‹€.

@zerofront μ•„λ§ˆλ„ μ „μš© 문제λ₯Ό μ—¬λŠ” 것이 더

μ†Œν’ˆμ„ κ΅¬μ‘°ν™”ν•˜λŠ” λ™μ•ˆ κΈ°λ³Έ μ†Œν’ˆμ„ μ„€μ •ν•˜λŠ” 데 운이 μ’‹μ•˜μŠ΅λ‹ˆλ‹€. λ¬Έμžμ—΄μ΄ μ•„λ‹Œ κ°’μœΌλ‘œλ„ μž‘λ™ν•œλ‹€κ³  ν™•μ‹ ν•©λ‹ˆλ‹€.

즉:

const Text = ({
text: 'Hello world'
}: Props) => <p>{text}</p>

μ†Œν’ˆμ„ κ΅¬μ‘°ν™”ν•˜λŠ” λ™μ•ˆ κΈ°λ³Έ μ†Œν’ˆμ„ μ„€μ •ν•˜λŠ” 데 운이 μ’‹μ•˜μŠ΅λ‹ˆλ‹€. λ¬Έμžμ—΄μ΄ μ•„λ‹Œ κ°’μœΌλ‘œλ„ μž‘λ™ν•œλ‹€κ³  ν™•μ‹ ν•©λ‹ˆλ‹€.

즉:

const Text = ({
text: 'Hello world'
}: Props) => <p>{text}</p>

@sami616 저도 λ‹˜κ³Ό 같은 κΈ°λ³Έ μ†Œν’ˆμ„ μ‚¬μš©ν•˜μ§€λ§Œ @zerofrontκ°€ 이미 λ³΄κ³ ν•œ κ²ƒμ²˜λŸΌ λ¬Έμžμ—΄μ΄ μ•„λ‹Œ 것에 λŒ€ν•œ 기본값은 보이지 μ•ŠμŠ΅λ‹ˆλ‹€.

λ‚΄ μ˜κ²¬μ„ λ¬΄μ‹œν•˜μ‹­μ‹œμ˜€. 예, 같은 λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆλ‹€.

@sami616 , 이미 λ§ν–ˆλ“―μ΄ 이에 λŒ€ν•œ 버그 λ³΄κ³ μ„œλ₯Ό μ—΄κ³  μ‹Άμ§€λ§Œ 이λ₯Ό μˆ˜ν–‰ν•˜κΈ° 전에 문제의 원인이 storybook 인지 λ˜λŠ” react-docgen-typescript-loader 인지 μ΄ν•΄ν•˜κΈ° μœ„ν•΄ μ½”λ“œλ² μ΄μŠ€μ—μ„œ μ•½κ°„μ˜ 쑰사가 ν•„μš”ν•©λ‹ˆλ‹€

@sami616 @sergiop
react-docgen-typescript-loader 버전 3.2.1을 μ„€μΉ˜ν•©λ‹ˆλ‹€.
node_modules/react-docgen-typescript-loader/dist/generateDocgenCodeBlockμ—μ„œ 일뢀 μ½”λ“œλ₯Ό μ°Ύμ•˜μŠ΅λ‹ˆλ‹€.

var setDefaultValue = function(defaultValue) {
    return typescript_1.default.createPropertyAssignment(
      typescript_1.default.createLiteral('defaultValue'),
      // Use a more extensive check on defaultValue. Sometimes the parser
      // returns an empty object.
      defaultValue != null && typeof defaultValue === 'object' && 'value' in defaultValue && typeof defaultValue.value === 'string'
        ? typescript_1.default.createObjectLiteral([
            typescript_1.default.createPropertyAssignment(
              typescript_1.default.createIdentifier('value'),
              typescript_1.default.createLiteral(defaultValue.value),
            ),
          ])
        : typescript_1.default.createNull(),
    );
  };

&& typeof defaultValue.value === 'string'

이 쑰건은 defaultProps의 μœ ν˜•μ„ μ œν•œν•©λ‹ˆλ‹€.

그리고 μ΅œμ‹  버전 3.3.0 react-docgen-typescript-loaderμ—μ„œλŠ” string、number、boolean을 μ§€μ›ν•©λ‹ˆλ‹€.

https://github.com/strothj/react-docgen-typescript-loader/blob/master/src/generateDocgenCodeBlock.ts

const setDefaultValue = (
    defaultValue: { value: string | number | boolean } | null,
  ) =>
    ts.createPropertyAssignment(
      ts.createLiteral("defaultValue"),
      // Use a more extensive check on defaultValue. Sometimes the parser
      // returns an empty object.
      defaultValue != null &&
        typeof defaultValue === "object" &&
        "value" in defaultValue &&
        (typeof defaultValue.value === "string" ||
          typeof defaultValue.value === "number" ||
          typeof defaultValue.value === "boolean")
        ? ts.createObjectLiteral([
            ts.createPropertyAssignment(
              ts.createIdentifier("value"),
              ts.createLiteral(defaultValue!.value),
            ),
          ])
        : ts.createNull(),
    );

@zerofront , λ°˜κ°‘μŠ΅λ‹ˆλ‹€. 저도 3.2.1 가지고 μžˆμŠ΅λ‹ˆλ‹€. 였늘 μ•„μΉ¨ 늦게 3.3.0으둜 μ—…λ°μ΄νŠΈν•˜μ—¬ λ¬Έμ œκ°€ ν•΄κ²°λ˜λŠ”μ§€ ν™•μΈν•˜κ² μŠ΅λ‹ˆλ‹€. 감사 ν•΄μš”.

@zerofront react-docgen-typescript-loader λ₯Ό 3.3.0으둜 μ—…λ°μ΄νŠΈν•˜λ©΄ λ¬Έμ œκ°€ ν•΄κ²°λ©λ‹ˆλ‹€. 감사 ν•΄μš”.
Screenshot 2019-10-10 at 12 00 16

Awesome-typescript-loaderλ₯Ό μ‚¬μš©ν•˜λŠ” 경우 μž„μ‹œ μ†”λ£¨μ…˜:

/* tsconfig.json */
{
  "compilerOptions": { },
  "awesomeTypescriptLoaderOptions": {
    "ignoreDiagnostics": [7005]
  }
}

μ΄μƒμ μ΄μ§€λŠ” μ•Šμ§€λ§Œ μž‘λ™ν•©λ‹ˆλ‹€.

였늘 5.1μ—μ„œ 5.2.5둜 μ—…λ°μ΄νŠΈν–ˆλŠ”λ° 아직 addon-docsλ₯Ό μ„€μΉ˜ν•˜μ§€ μ•Šκ³  이 였λ₯˜κ°€ λ°œμƒν•˜κΈ° μ‹œμž‘ν–ˆμŠ΅λ‹ˆλ‹€. 이 μ†”λ£¨μ…˜μ€ μ €μ—κ²Œ νš¨κ³Όκ°€ μžˆμ—ˆμ§€λ§Œ κ·Έ μ΄μœ λŠ” λͺ…ν™•ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

μ•ˆλ…•ν•˜μ„Έμš” μ—¬λŸ¬λΆ„! μ΅œκ·Όμ— 이 λ¬Έμ œμ— λŒ€ν•΄ 많이 μ§„ν–‰λ˜μ§€ μ•Šμ€ 것 κ°™μŠ΅λ‹ˆλ‹€. μ—¬μ „νžˆ 질문, 의견 λ˜λŠ” 버그가 있으면 자유둭게 토둠을 κ³„μ†ν•˜μ‹­μ‹œμ˜€. λΆˆν–‰νžˆλ„ λͺ¨λ“  문제λ₯Ό λ‹€λ£° μ‹œκ°„μ΄ μ—†μŠ΅λ‹ˆλ‹€. μš°λ¦¬λŠ” 항상 기여에 μ—΄λ € μžˆμœΌλ―€λ‘œ 도움이 ν•„μš”ν•˜λ©΄ ν’€ λ¦¬ν€˜μŠ€νŠΈλ₯Ό λ³΄λ‚΄μ£Όμ‹­μ‹œμ˜€. λΉ„ν™œμ„± λ¬Έμ œλŠ” 30일 후에 λ‹«νž™λ‹ˆλ‹€. 감사 ν•΄μš”!

"@storybook/react": "5.2.6" 및 "react-docgen-typescript-loader": "3.6.0" 버전에 λŒ€ν•΄ 이 λ¬Έμ œμ— μ„€λͺ…λœ 였λ₯˜κ°€ 계속 λ°œμƒν•©λ‹ˆλ‹€. 관련성이 μžˆλŠ”μ§€ ν™•μ‹€ν•˜μ§€ μ•Šμ§€λ§Œ μ—¬κΈ°μ—μ„œ 참쑰된 PRμ—μ„œ // @ts-ignore 에 __MODULE_DEPENDENCIES__ 에 μΆ”κ°€λœ μœ μΌν•œ νŒŒμΌμ€ src/server/build.js뿐이지 만 src μ—μ„œλŠ” μ—¬μ „νžˆ λ¬΄μ‹œλ©λ‹ˆλ‹€.

@jalooc 5.3 베타λ₯Ό ν™•μΈν•˜μ‹­μ‹œμ˜€. μ†Œν’ˆ ν…Œμ΄λΈ”μ— λŒ€ν•œ μˆ˜λ§Žμ€ κ°œμ„  사항.

@shilman λ‚˜λŠ” 이것을 beta.6μ—μ„œ λ§ˆμ§€λ§‰μœΌλ‘œ μ‹œλ„ν–ˆμœΌλ©° ν•΄κ²° 방법 μ—†μ΄λŠ” μž‘λ™ν•˜μ§€ μ•Šμ•˜λ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€. πŸ˜„ μ΅œμ‹ μž‘μœΌλ‘œ λ‹€μ‹œ λ„μ „ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

μŠ€ν† λ¦¬λΆ 5.3μ—μ„œ μ—¬μ „νžˆ 이 λ¬Έμ œκ°€ λ°œμƒν•©λ‹ˆλ‹€. [email protected] 및 react-docgen-typescript-loader 3.6.0.

λ‚˜λ₯Ό μœ„ν•΄ 그것을 κ³ μΉ  수 μžˆλŠ” μœ μΌν•œ 방법은 λ‚΄κ°€ μ •λ§λ‘œ ν•˜κ³  싢지 μ•Šμ€ "noImplicitAny": false in tsconfig.json ν•˜λŠ” κ²ƒμ΄μ—ˆμŠ΅λ‹ˆλ‹€.

λ‚΄κ°€ μ–»λŠ” 였λ₯˜λŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.
TS7005: Variable '__MODULE_DEPENDENCIES__' implicitly has an 'any[]' type.

λ‚΄ 이야기에 μœ ν˜•μ„ 좔가해도 λ¬Έμ œκ°€ μ™„μ „νžˆ ν•΄κ²°λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

후속 쑰치둜 @enagy27이 μ–ΈκΈ‰ν•œ transpileOnly μ˜΅μ…˜μ„ μ‚¬μš©ν•˜μ—¬ μž‘λ™ν•˜λ„λ‘ ν–ˆμŠ΅λ‹ˆλ‹€. 전체 μ›ΉνŒ© ꡬ성 λŒ€μ‹  사전 섀정을 μ‚¬μš©ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. 이것은 ν˜„μž¬ presets.js μž…λ‹ˆλ‹€. tsconfig.json λ³€κ²½ μ—†μŒ:

// presets.js
const path = require("path");

module.exports = [
    {
        name: "@storybook/preset-typescript",
        options: {
            tsLoaderOptions: {
                configFile: path.resolve(__dirname, "../tsconfig.json"),
                transpileOnly: true,
            },
            tsDocgenLoaderOptions: {
                tsconfigPath: path.resolve(__dirname, "../tsconfig.json"),
            },
            include: [path.resolve(__dirname, "../src")],
        },
    },
    {
        name: "@storybook/addon-docs/react/preset",
        options: {
            configureJSX: true,
            //sourceLoaderOptions: null,
        },
    },
];

이에 λŒ€ν•œ μ—…λ°μ΄νŠΈκ°€ μžˆμŠ΅λ‹ˆκΉŒ? μš°λ¦¬λŠ” TS와 ν•¨κ»˜ μŠ€ν† λ¦¬λΆ μ• λ“œμ˜¨μ„ μ‚¬μš©ν•˜λ €κ³  ν•˜κ³  있으며 ν•΄κ²° λ°©λ²•μœΌλ‘œλ„ 이것을 μ§€λ‚˜μΉ  수 μ—†μŠ΅λ‹ˆλ‹€. 계속 λ°›κΈ°
"λ³€μˆ˜ '__MODULE_DEPENDENCIES__'에 μ•”μ‹œμ μœΌλ‘œ 'any[]' μœ ν˜•μ΄ μžˆμŠ΅λ‹ˆλ‹€."

ν˜„μž¬ μŠ€ν† λ¦¬λΆμ„ 5.3.0-beta.16으둜 μ—…λ°μ΄νŠΈν•˜κ³  여기에 μ–ΈκΈ‰λœ λ‹€λ₯Έ ν•΄κ²° 방법을 μ‹œλ„ν–ˆμŠ΅λ‹ˆλ‹€. 감사 ν•΄μš”

typescriptκ°€ μžˆλŠ” props ν…Œμ΄λΈ”μ„ ν‘œμ‹œν•˜κΈ° μœ„ν•΄ μŠ€ν† λ¦¬λΆ addon-docsλ₯Ό κ°€μ Έμ˜¬ 수 μ—†μŠ΅λ‹ˆλ‹€. "κ΅¬μ„±μš”μ†Œλ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€"라고만 ν‘œμ‹œλ©λ‹ˆλ‹€.

addons.js

import '@storybook/addon-knobs/register'
import '@storybook/addon-a11y/register'
import '@storybook/addon-docs/register'

프리셋.js

module.exports = [
  {
    name: "@storybook/addon-docs/react/preset",
    options: {
      configureJSX: true,
    }
  }
]

μ›ΉνŒ©.config.js

const path = require('path')
const SRC_PATH = path.join(__dirname, '../src')

module.exports = ({ config }) => {
    config.module.rules.push({
        test: /\.(ts|tsx|js|jsx)$/,
        include: [SRC_PATH],
        use: [
            {
                loader: require.resolve('babel-loader'),
                options: {
                    presets: [['react-app', { flow: false, typescript: true }]],
                    plugins: ['babel-plugin-styled-components']
                },
            },
            {
                loader: require.resolve('react-docgen-typescript-loader'),
                options: {
                    tsconfigPath: path.resolve(__dirname, '../tsconfig.json'),
                },
            },
            {
                loader: require.resolve('@storybook/source-loader'),
                options: { parser: 'typescript',  injectParameters: true, },
            },
        ],
        exclude: [/node_modules/],
        enforce: 'pre',

    })

    config.resolve.extensions.push('.ts', '.tsx', '.js', '.jsx')
    return config
}

μŠ€ν† λ¦¬λΆ 5.2.8
μ• λ“œμ˜¨ λ¬Έμ„œ 5.2.8
react-docgen-typescript-loader 3.6.0
바벨 λ‘œλ” 8.0.6
@storybook/source-loader 5.2.8

λ˜ν•œ Component Story Format을 μ‚¬μš©ν•˜λ©΄ μŠ€ν† λ¦¬λΆμ΄ ꡬ성 μš”μ†Œλ₯Ό μ „ν˜€ 찾지 μ•Šμ§€λ§Œ(μΊ”λ²„μŠ€μ™€ λ¬Έμ„œ 및 메뉴가 λΉ„μ–΄ 있음)storyOfλ₯Ό μ‚¬μš©ν•˜λ©΄ ꡬ성 μš”μ†Œλ₯Ό ν‘œμ‹œν•©λ‹ˆλ‹€.

ν•΄κ²° λ°©λ²•μœΌλ‘œ μ—„κ²©ν•œ κ·œμΉ™μ΄ ν•΄μ œλœ μƒνƒœμ—μ„œ λ¬Έμ„œ 생성을 tsconfig.json으둜 지정할 수 μžˆμŠ΅λ‹ˆλ‹€. 일단 μ΄λ ‡κ²Œ ν•΄κ²°ν•œ 것 κ°™μ•„μš”. κ΄€μ‹¬μžˆλŠ” μ‚¬λžŒμ΄ 있으면 λ‹€μŒ 주에 λ‹€μ‹œ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

이것은 λ‚΄ ꡬ성이며 도움이 될 수 μžˆμŠ΅λ‹ˆλ‹€.
git μž‘λ™μ΄ μ™„λ£Œλ˜μ—ˆμŠ΅λ‹ˆλ‹€.
Capture1
Capture2
Capture3
Capture4

++ κ·Έ
const AccordionItem 내보내기
webpack.config.jsκ°€ μ—†μŠ΅λ‹ˆλ‹€.

μ—¬μ „νžˆ κ³ κ΅°λΆ„νˆ¬ν•˜λŠ” λ‹€λ₯Έ λˆ„κ΅°κ°€λ₯Ό μœ„ν•΄ react-docgen-typescript-loader의 κ³ ν†΅μŠ€λŸ¬μš΄ 디버깅 후에 λ§ˆμΉ¨λ‚΄ μž‘λ™ν•˜λ„λ‘ κ΄€λ¦¬ν–ˆμŠ΅λ‹ˆλ‹€.

React-docgen-typescript-loaderλŠ” ꡬ성 μš”μ†Œ 이름이 μ•„λ‹Œ 폴더 이름을 μ‚¬μš©ν•˜μ—¬ __docgeninfo λ₯Ό ν• λ‹Ήν•˜λ―€λ‘œ ꡬ성 μš”μ†Œλ₯Ό 같은 μ΄λ¦„μ˜ 폴더에 λ„£μ–΄μ•Ό ν•©λ‹ˆλ‹€(λŒ€μ†Œλ¬Έμž ꡬ뢄).

|__
  CTALink
    |___index.tsx

CSF ν˜•μ‹μ„ μ‚¬μš©ν•  수 μ—†μ—ˆμ§€λ§Œ(항상 λΉ„μ–΄ 있음) storiesOf ꡬ문을 μ‚¬μš©ν•  λ•Œ props ν…Œμ΄λΈ”μ„ μ„ νƒν•˜λ €λ©΄ μŠ€ν† λ¦¬λΆμ—μ„œ addParameters ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ ꡬ성 μš”μ†Œλ₯Ό 포함해야 ν•©λ‹ˆλ‹€. .

storiesOf('CTALink', module)
  .addParameters({
    component: CTALink,
  })
  .add('default story', () => (
    <CTALink to="/">Click here</CTALink>
  ))

μ•ˆλ…•ν•˜μ„Έμš” μ—¬λŸ¬λΆ„! μ΅œκ·Όμ— 이 λ¬Έμ œμ— λŒ€ν•΄ 많이 μ§„ν–‰λ˜μ§€ μ•Šμ€ 것 κ°™μŠ΅λ‹ˆλ‹€. μ—¬μ „νžˆ 질문, 의견 λ˜λŠ” 버그가 있으면 자유둭게 토둠을 κ³„μ†ν•˜μ‹­μ‹œμ˜€. λΆˆν–‰νžˆλ„ λͺ¨λ“  문제λ₯Ό λ‹€λ£° μ‹œκ°„μ΄ μ—†μŠ΅λ‹ˆλ‹€. μš°λ¦¬λŠ” 항상 기여에 μ—΄λ € μžˆμœΌλ―€λ‘œ 도움이 ν•„μš”ν•˜λ©΄ ν’€ λ¦¬ν€˜μŠ€νŠΈλ₯Ό λ³΄λ‚΄μ£Όμ‹­μ‹œμ˜€. λΉ„ν™œμ„± λ¬Έμ œλŠ” 30일 후에 λ‹«νž™λ‹ˆλ‹€. 감사 ν•΄μš”!

TypescriptλŠ” 5.3의 μ†ŒμŠ€ λΈ”λ‘μ—μ„œ μž‘λ™ν•΄μ•Ό ν•©λ‹ˆλ‹€. 폐쇄.

@storybook/react 및 @storybook/addon-docs λ₯Ό λͺ¨λ‘ 5.3.0-rc.4둜 μ—…λ°μ΄νŠΈν–ˆμ§€λ§Œ TS7005: Variable '__MODULE_DEPENDENCIES__' implicitly has an 'any[]' type. 였λ₯˜ λ©”μ‹œμ§€κ°€ 계속 ν‘œμ‹œλ©λ‹ˆλ‹€.

λ‚˜λŠ” 사전 섀정을 μ‚¬μš©ν•˜μ§€ μ•Šκ³  λ˜ν•œ webpack을 처음 μ‚¬μš©ν•˜λ―€λ‘œ μ•„λ§ˆλ„ λͺ‡ 가지 μ‹€μˆ˜λ₯Ό μ €μ§ˆλ €μ„ κ²ƒμž…λ‹ˆλ‹€.
λ‚΄ webpack.config.jsλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.
```const 경둜 = require('경둜');

module.exports = {
λ…Έλ“œ: {
fs: 'λΉ„μ–΄ 있음',
child_process: 'λΉ„μ–΄ 있음'
},
ν•΄κ²°ν•˜λ‹€: {
λͺ¨λ“ˆ: [
'λ…Έλ“œ_λͺ¨λ“ˆ',
],
ν™•μž₯자: [".ts", ".tsx"],
심볼릭 링크: μ°Έ
},
λͺ¨λ“ˆ: {
κ·œμΉ™: [
{
ν…ŒμŠ€νŠΈ: /.(ts|tsx)$/,
μ‚¬μš©ν•˜λ‹€: [
{
λ‘œλ”: require.resolve('awesome-typescript-loader')
},
{
λ‘œλ”: require.resolve('react-docgen-typescript-loader')
},
]
},
{
ν…ŒμŠ€νŠΈ: /.(이야기|이야기).[tj]sx?$/,
λ‘œλ”: require.resolve('@storybook/source-loader')
}
]
},
μ™ΈλΆ€: {
'클래슀 λ³€μ••κΈ°': '클래슀 λ³€μ••κΈ°'
}
};
```

μš”ν˜Έν˜Έ!! 이 문제λ₯Ό μ°Έμ‘°ν•˜λŠ” PR #9272κ°€ ν¬ν•¨λœ https://github.com/storybookjs/storybook/releases/tag/v5.3.0-rc.5 λ₯Ό 방금 μΆœμ‹œν–ˆμŠ΅λ‹ˆλ‹€. μ§€κΈˆ μ—…κ·Έλ ˆμ΄λ“œν•˜μ—¬ μ‚¬μš©ν•΄ λ³΄μ„Έμš”!

이 μ‹œν—˜νŒμ€ @next NPM νƒœκ·Έμ—μ„œ 찾을 수 μžˆμŠ΅λ‹ˆλ‹€.

@JacopoBonta κ°€μž₯ 졜근 릴리슀 5.3.0-rc.5 λ₯Ό μ‚¬μš©ν•΄ λ³Ό 수 μžˆμŠ΅λ‹ˆκΉŒ?

μ•ˆλ…•ν•˜μ„Έμš” @shilman μŠ€ν† λ¦¬λΆκ³Ό κ²°ν•©λœ λ¬Έμ„œμ— λŒ€ν•œ λ†€λΌμš΄ 지원에 κ°μ‚¬λ“œλ¦½λ‹ˆλ‹€.
5.3.0-rc.5 μ—…λ°μ΄νŠΈν–ˆλŠ”λ° μ—¬μ „νžˆ TS7005: Variable '__MODULE_DEPENDENCIES__' implicitly has an 'any[]' type. 였λ₯˜κ°€ λ°œμƒν•©λ‹ˆλ‹€.

μ•„λž˜μ™€ 같이 ts-loader ꡬ성에 ignoreDiagnostics: [7005] λ₯Ό μΆ”κ°€ν•œ κ²½μš°μ—λ§Œ μž‘λ™ν•©λ‹ˆλ‹€.

파일 main.js :

const { addons } = require('@storybook/addons');
const path = require('path');
const tsImportPluginFactory = require('ts-import-plugin')

module.exports = {
  stories: ['../packages/**/*.stories.(tsx|mdx)'],
  presets: [
    {
      name: '@storybook/preset-typescript',
      options: {
        tsLoaderOptions: {
          configFile: path.resolve(__dirname, 'tsconfig.json'),
          ignoreDiagnostics: [7005],
          getCustomTransformers: () => ({
            before: [ tsImportPluginFactory(
              {
                libraryName: 'antd',
                style: 'css',
                libraryDirectory: 'es'
              }
            ) ]
          }),
        },
        tsDocgenLoaderOptions: {
          tsconfigPath: path.resolve(__dirname, 'tsconfig.json'),
        },
        forkTsCheckerWebpackPluginOptions: {
          colors: false, // disables built-in colors in logger messages
        },
        include: [path.resolve(__dirname, "../packages")]
      },
    },
    {
      name: '@storybook/addon-docs/preset',
      options: {
      }
    }],
  addons: [
    '@storybook/addon-docs/register',
    '@storybook/addon-knobs/register',
    '@storybook/addon-actions/register',
    '@storybook/addon-links/register'
  ],
};

@JacopoBonta κ°€μž₯ 졜근 릴리슀 5.3.0-rc.5 λ₯Ό μ‚¬μš©ν•΄ λ³Ό 수 μžˆμŠ΅λ‹ˆκΉŒ?

μ£„μ†‘ν•˜μ§€λ§Œ 5.3.0-rc.5 μ—…κ·Έλ ˆμ΄λ“œν•  수 μ—†μŠ΅λ‹ˆλ‹€.
@storybook/react 및 @storybook/addon-docs λͺ¨λ‘ μ—…λ°μ΄νŠΈν–ˆμ§€λ§Œ λ™μΌν•œ 였λ₯˜κ°€ 계속 λ°œμƒν•©λ‹ˆλ‹€.

AcJacopoBonta @ esakal 의 ν•΄κ²° 방법을 확인할 수 μžˆμŠ΅λ‹ˆκΉŒ?

@JacopoBonta awesome-typescript-loader μ‚¬μš©ν•˜κ³  μžˆλŠ” κ²ƒμœΌλ‘œ λ‚˜νƒ€λ‚¬μŠ΅λ‹ˆλ‹€. ν˜„μž¬ λ‹€λ₯Έ λ‘œλ”λ₯Ό μ‚¬μš©ν•˜κ³  μžˆμ§€λ§Œ ν•œ 달 전에 μ‚¬μš©ν–ˆμ„ λ•Œ λΉ„μŠ·ν•œ ν•΄κ²° 방법을 μˆ˜ν–‰ν–ˆμŠ΅λ‹ˆλ‹€. awesome-typescript-loader 경우 λ‹€μŒμ„ μˆ˜ν–‰ν•΄μ•Ό ν•©λ‹ˆλ‹€.

/* tsconfig.json */
{
  "compilerOptions": { },
  "awesomeTypescriptLoaderOptions": {
    "ignoreDiagnostics": [7005]
  }
}

μ—¬κΈ° μ—μ„œ κ°€μ Έμ˜¨

예, μž‘λ™ν•©λ‹ˆλ‹€. 이전에 이미 이 ν•΄κ²° 방법을 μ‚¬μš©ν•˜κ³  μžˆμ—ˆμ§€λ§Œ μ—†λŠ” 방법을 μ°Ύκ³  μžˆμ—ˆμŠ΅λ‹ˆλ‹€.

μ•„λ¬΄νŠΌ λ§Žμ€ 도움 μ£Όμ…”μ„œ κ°μ‚¬ν•˜κ³  μƒˆν•΄ 볡 많이 λ°›μœΌμ„Έμš” πŸŽ‰

@esakal κ°μ‚¬ν•©λ‹ˆλ‹€. μ†”λ£¨μ…˜μ€ μ§€κΈˆκΉŒμ§€ (μ €μ—κ²Œ) μ΅œκ³ μž…λ‹ˆλ‹€. TypeScript 문제λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄ transpileOnly: true λ₯Ό μ„€μ •ν–ˆμ§€λ§Œ κ·Έ κ²°κ³Ό 더 λ§Žμ€ TypeScript 였λ₯˜κ°€ λˆˆμ— 띄지 μ•Šκ²Œ ν†΅κ³Όν•˜λŠ” νš¨κ³Όκ°€ μžˆμ—ˆμŠ΅λ‹ˆλ‹€.

ν˜„μž¬μ˜ μ•„μ£Ό μ΅œμ†Œν•œμ˜ ꡬ성( presets.js )은 λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

const path = require("path");

module.exports = [
    {
        name: "@storybook/preset-typescript",
        options: {
            tsLoaderOptions: {
                configFile: path.resolve(__dirname, "../tsconfig.json"),
                ignoreDiagnostics: [7005],
            },
        },
    },
    {
        name: "@storybook/addon-docs/preset",
        options: {
            configureJSX: true,
        },
    },
];

κ°μ‚¬ν•©λ‹ˆλ‹€!

이 νŽ˜μ΄μ§€κ°€ 도움이 λ˜μ—ˆλ‚˜μš”?
0 / 5 - 0 λ“±κΈ‰