λ²κ·Έ μ€λͺ
Technical Preview κ°μ΄λμ μ€λͺ
λ λλ‘ sourceLoaderOptions: null
λ₯Ό λ¬Έμ μ¬μ μ€μ μ μ λ¬νμ§ μκ³ typescriptλ₯Ό μ¬μ©νλ©΄ λ€μ μ€λ₯κ° λ°μν©λλ€.
Variable '__MODULE_DEPENDENCIES__' implicitly has an 'any[]' type
μ΄κ²μ λΆννλ tsconfig.json
λ₯Ό μ¬μ©νλλ‘ "noImplicitAny": false
tsconfig.json
μ€ν 리λΆμ μ
λ°μ΄νΈνμ¬ μμ λμ§ μμμ΅λλ€.
μ¬ννκΈ° μν΄
λμμ μ¬ννλ λ¨κ³:
addon-docs
λν μ€ν 리 μμ±μμλλ νλ
λ¬Έμ νμ΄μ§κ° νμμ κ°μ΄ λ‘λλκ³ μ€ν 리μ λν μ½λ μ€λν«μ μ¬μ©ν μ μμ΅λλ€.
μ€ν¬λ¦°μ·
ν΄λΉνλ κ²½μ° λ¬Έμ λ₯Ό μ€λͺ
νλ λ° λμμ΄ λλ μ€ν¬λ¦°μ·μ μΆκ°νμΈμ.
μ½λ μ‘°κ°
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
@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
(λ΄ μκ°μλ)).
λ€μμ΄ νμ±νλμ΄ μμ§ μμμ§ νμΈνλ κ²μ
λλ€.
@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 λ₯Ό μ λ°μ΄νΈνμ¬ κ΅¬μ±μ λν΄ λͺ¨λ κ°μ νμ΄μ§μ μλμ§ νμΈνλ λ° μκ°μ΄ 걸릴 μ μμ΅λλ€. π μΌμ£ΌμΌ μ λ 걸릴 μ μμ§λ§... μ§κΈμ λ΄ κ΅¬μ±μ μ 곡νκ² μ΅λλ€.
import '@storybook/addon-knobs/register';
import '@storybook/addon-a11y/register';
import '@storybook/addon-actions/register';
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);
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',
];
μ΄κ²μ μ°λ¦¬ νμ¬ λ΄λΆμ΄κΈ° λλ¬Έμ 곡μ ν μ μμ§λ§ config.js
μμ μ°Έμ‘°λ©λλ€.
μ΄ νμΌμ λ£¨νΈ 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μ ν¨κ» μλν©λλ€γ
μλ νμΈμ @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νμ΄ μλλ©΄ μμ±ν μ μμ΅λλ€.
@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μΌλ‘ μ
λ°μ΄νΈνλ©΄ λ¬Έμ κ° ν΄κ²°λ©λλ€. κ°μ¬ ν΄μ.
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 μλμ΄ μλ£λμμ΅λλ€.
++ κ·Έ
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,
},
},
];
κ°μ¬ν©λλ€!
κ°μ₯ μ μ©ν λκΈ
Awesome-typescript-loaderλ₯Ό μ¬μ©νλ κ²½μ° μμ μ루μ :
μ΄μμ μ΄μ§λ μμ§λ§ μλν©λλ€.