λ€μ κ΅¬μ± μμλ₯Ό λ§λ€ λ μ€ν 리 λΆμ μ€λ₯κ° νμλ©λλ€.
# src/components/organisms/ParentComponent/index.tsx
import * as React from 'react';
import ChildrenComponent from 'src/components/molecules/ChildrenComponent/index';
const ParentComponent: React.SFC<{}> = ({ ...props }) => (
<ChildrenComponent />
);
μ€λ₯
Module not found: Error: Can't resolve 'src/components/molecules/ChildrenComponent/index' in '/AppRoot/src/components/organisms/ParentComponent'
μ΄κ²μ μ λ κ²½λ‘λ‘λ‘λ ν κ²μΌλ‘ 보μ΄λ―λ‘ λ€μμ μννλ©΄ μ μμ μΌλ‘ μλν©λλ€.
import ChildrenComponent from '../../molecules/ChildrenComponent/index';
κ·Έλ¬λ κ°λ₯ν νμ΄ λ°©λ²μ νΌνκ³ μΆμ΅λλ€. μλ κ²½λ‘λ‘ μ§μ νλ κ² μΈμ μ€λ₯μμ΄ μ€ν 리 λΆμ μμν μμλ λ°©λ²μ΄ μμ΅λκΉ?
μ λ κ²½λ‘μ μ μ©μ tsconfig.json
μ λν λ€μ μ€λͺ
μ κΈ°λ°μΌλ‘ν©λλ€.
"compilerOptions": {
"outDir": "build/dist",
"rootDir": "src",
"baseUrl": "."
}
λν μ΄λ²μλ μ€ν 리 λΆμ μ»΄νμΌ λ build/dist
λλ ν λ¦¬κ° μλ μ»΄νμΌ λ src
λλ ν 리μ tsx νμ₯μλ‘ μμ±λ stories
νμΌμ κ°μ Έμ΅λλ€.
./storybook/config
μ μ€μ λμ΄ μμ§λ§ build/dist
νλ©΄ λΉμ·ν κ²°κ³Όκ° μμ±λ©λλ€.
μ΄ νλ‘μ νΈλ μμ λμμΈμ μ¬μ©νκΈ° λλ¬Έμ λλ΅ λ€μκ³Ό κ°μ λλ ν 리 ꡬ쑰λ₯Ό κ°μ§κ³ μμ΅λλ€.
βββ components
β βββ molecules
β β βββ ChildrenComponent
β β β βββ index.tsx
β β β βββ index.stories.tsx
β βββ organisms
β β βββ ParentComponent
β β β βββ index.tsx
β β β βββ index.stories.tsx
κ΄λ ¨ λ¬Έμ μ κ°μ κ²μ΄μλ κ² κ°μ΅λλ€.
κ·Έλ¬λ κ·Έκ²μ ν΄κ²°μ±
μ λλ¬νμ§ λͺ»νμ΅λλ€.
μ΄ λ¬Έμ λ₯Ό ν΄κ²°νλ λ°λ λ κ°μ§ λ°©λ²μ΄ μλ€κ³ μκ°ν©λλ€.
μ¬κΈ°μ κ°μ₯ λ¨Όμ μμ²νκ³ μΆμ κ²μ "μ€ν 리 λΆμΌλ‘ μ λ κ²½λ‘ κ΅¬μ± μμ κ°μ Έ μ€κΈ°"μ΄κ³ , λ λ²μ§Έλ κ°μ Έμ¨ tsx
νμΌμ μ λ κ²½λ‘λ‘ κ°μ Έ μ€λ js
νμΌλ‘ μ»΄νμΌνλ κ²μ
λλ€. μλ κ²½λ‘λ‘. κ·Έλ° λ€μ κ°μ Έμ¨ js
νμΌμ μ€ν 리 λΆμ μλ κ²½λ‘μ ν¨κ» μ μ©ν©λλ€.
νμμ κ΄ν΄μλ μ¬κΈ°μμ΄ λ¬Έμ λ₯Ό λ£λ κ²μ΄ μ μ νμ§ μλ€κ³ μκ°νμ§λ§, μκ³ κ³μλ€λ©΄ κ·Έ λ°©λ²μ λν΄μλ λ¬Όμ΄λ³΄κ³ μΆμ΅λλ€.
μκ° λ΄ μ€μ κ³ λ§μ.
μΌλ° μ±μμ μ΄λ»κ² μλνλμ§ λͺ¨λ₯΄κ² μ§λ§ (μ€μ μ 무μμ
λκΉ?), cwd (-> cwd/src/components/....
λΌκ³ κ°μ )λ₯Ό resolve.modules
λ£μΌλ©΄ νμ₯ webpack.config
μμ μλ§λ λ¬Έμ λ₯Ό ν΄κ²°ν κ²μ
λλ€ (λλ Angular μ±μΌλ‘ νμΈνμ§λ§ μ€μ λ‘λ μ€μνμ§ μμ΅λλ€)
λ΄ .storybook/webpack.config.js
νμΌμ λ€μκ³Ό κ°μ΄ μ€λͺ
λ©λλ€.
μ¬κΈ°μ λ¬Έμ κ° μμ΅λκΉ?
const genDefaultConfig = require('@storybook/react/dist/server/config/defaults/webpack.config.js');
module.exports = (baseConfig, env) => {
const config = genDefaultConfig(baseConfig, env);
config.module.rules.push({
test: /\.(ts|tsx)?$/,
exclude: /node_modules/,
include: [/stories/, /src/],
loader: 'ts-loader'
});
config.resolve.extensions.push('.ts', '.tsx');
return config;
};
λ€μκ³Ό κ°μ΄ μΆκ°ν΄λ³΄μμμ€.
const path = require('path');
// blah blah code
module.exports = (baseConfig, env) => {
// blah blah code
config.resolve.modules = [
...(config.resolve.modules || []),
path.resolve('./'),
];
}
μ λλ‘ μλνμ΅λλ€ !!
λλ λΉμ μκ² μΆ©λΆν κ°μ¬ ν μ μλ€ !!!!!!!
@ igor-dv λΉμ·ν λ¬Έμ κ° μμΌλ©° κ·νμ μ μ (μ)κ³Ό resource.request κ²½λ‘λ₯Ό μμ νλ NormalModuleReplacementPluginμ μλνμ΅λλ€. λ λ€ μΌνμ§ μμλ€
λ€λ₯Έ μ μμ΄ μμ΅λκΉ?
μ½λ μμ / webpack.config.jsλ₯Ό 곡μ ν΄ μ£Όμκ² μ΅λκΉ?
.storybook / webpack.config.js
const path =
require ( 'path');`
// const webpack = require ( 'webpack');
const genDefaultConfig = require ( '@ storybook / react / dist / server / config / defaults / webpack.config.js');
module.exports = (baseConfig, env) => {
const config = genDefaultConfig (baseConfig, env);
config.module = {
κ·μΉ : [
{
ν
μ€νΈ : /.tsx$/,
λ‘λ : [ "ts-loader"],
ν¬ν¨ : path.resolve (__ dirname, '../app/xv/')
},
{
ν
μ€νΈ : /.scss$/,
λ‘λ : [
'μ€νμΌ λ‘λ',
'css-loader',
'sass-loader? includePaths [] ='+ encodeURIComponent (path.resolve (__ dirname, '../app/'))
]
},
{
ν
μ€νΈ : /.css$/,
λ‘λ : 'style-loader! css-loader'
},
{
ν
μ€νΈ : /.less$/,
λ‘λ : 'style-loader! css-loader! less-loader'
},
{
ν
μ€νΈ : /.js|.ts$/,
μ μΈ : [path.join (__ dirname, 'app / components'), / node_modules /],
λ‘λ : 'ng-annotate-loader'
},
{
ν
μ€νΈ : /.js$/,
μ μΈ : [path.join (__ dirname, 'app / components'), / node_modules /],
λ‘λ : 'babel-loader? presets [] = es2015 & presets [] = stage-1 & presets [] = react & cacheDirectory'
}
]
};
config.resolve.modules = [
...(config.resolve.modules || []),
path.resolve('./'),
];
return config;
// ,
// plugins: [
// new webpack.NormalModuleReplacementPlugin(/xv/, function(resource) {
// resource.request = resource.request.includes('xv/') ? '../../app/' + resource.request : resource.request;
// })
// ]
}`
// μ½λ
`import * as React from 'react';
'xv / util / decorators'μμ {autobind} κ°μ Έ μ€κΈ°;
import '../ styles / ActionIcon.scss';`
// μ€λ₯
`./app/xv/ui/components/ActionIcon.tsxμ μ€λ₯
λͺ¨λμ μ°Ύμ μ μμ : μ€λ₯ : '/ Users / lukasanderson / workspace / NeXgen-UI / app / xv / ui / components'μμ 'xv / util / decorators'λ₯Ό ν΄κ²°ν μ μμ΅λλ€.
@ ./app/xv/ui/components/ActionIcon.tsx 31 : 0-46
@ ./.storybook/stories/actionIcons.js
@ ./.storybook/config.js
@ multi ./node_modules/@storybook/react/dist/server/config/polyfills.js ./node_modules/@storybook/react/dist/server/config/globals.js (webpack) -hot-middleware / client.js? reload = true ./. storybook / config.js`
/ xv /λ μΌλ°μ μΈ μΉν© κ°λ° (μ€ν 리 λΆμ΄ μλ) λΉλμμ νλ‘μ νΈμ κΈ°λ³Έ (λ£¨νΈ / μ± / xv / *)μ 맀νλ©λλ€.
νμν μ£μ‘ν©λλ€
NormalModuleReplacementPluginμΌλ‘ μ κ·μ λ체μ λ€μν λ³νμ μλνμ΅λλ€. μΌλΆλ μ λ κ²½λ‘λ₯Ό μ²λ¦¬νμ§ μλ μ€ν 리 λΆμ λν μ μ¬ν μ€λ λ / λ¬Έμ μμ λ°κ²¬λμμ΅λλ€.
μ:
plugins: [
new webpack.NormalModuleReplacementPlugin(/xv/, function(resource) {
resource.request = resource.request.replace(/xv/, '../../app/');
})
]
μ΄ μ€λ₯κ° λ°μν©λλ€.
`./.storybook/stories/actionIcons.jsμ μ€λ₯
λͺ¨λμ μ°Ύμ μ μμ : μ€λ₯ : '/Users/lukasanderson/workspace/NeXgen-UI/.storybook/stories'μμ '../../app//ui/components/Tooltip'μ ν΄κ²°ν μ μμ΅λλ€.
@ ./.storybook/stories/actionIcons.js 5 : 0-47
@ ./.storybook/config.js
@ multi ./node_modules/@storybook/react/dist/server/config/polyfills.js ./node_modules/@storybook/react/dist/server/config/globals.js (webpack) -hot-middleware / client.js? reload = true ./.storybook/config.js
`
μ΄ λ³κ²½ μ¬ν (λ체 λ¬Έμμ΄μ / xv / μΆκ°)
plugins: [
new webpack.NormalModuleReplacementPlugin(/xv/, function(resource) {
resource.request = resource.request.replace(/xv/, '../../app/xv/');
})
]
μ€λ€
`./.storybook/stories/actionIcons.jsμ μ€λ₯
λͺ¨λμ μ°Ύμ μ μμ : μ€λ₯ : '/Users/lukasanderson/workspace/NeXgen-UI/.storybook/stories'μμ '../../app/xv//ui/components/Tooltip'μ ν΄κ²°ν μ μμ΅λλ€.
@ ./.storybook/stories/actionIcons.js 5 : 0-47
`
μ λ κ²½λ‘μ λν μ¬λ°λ₯Έ κ²½λ‘ λ체κ°μμ λ μλ κ²½λ‘κ° μλ§ μΌλΏλ§ μλλΌ κ²½λ‘κ° 'μ¬λ°λ₯Έ'κ²μ΄κ³ μ€λ₯κ° μ§μλ©λλ€.
ERROR in ./.storybook/stories/actionIcons.js
Module not found: Error: Can't resolve '../../app/xv/ui/components/Tooltip' in '/Users/lukasanderson/workspace/NeXgen-UI/.storybook/stories'
μμ λλ ν 리 (cwd)λ 무μμ λκΉ?
λΏλ¦¬/
NeXgen-UI (μΌλͺ νλ‘μ νΈ λ£¨νΈ)μμ μ€ν 리 λΆμ μμν©λλ€.
λ°λΌμ import { autobind } from 'xv/util/decorators';
μμΌλ©΄ resolve.modules
μ path.resolve('./app')
μ μΆκ°ν΄μΌν©λλ€.
μ’μ, μ΄μ μ΄κ²
`
config.resolve = {
modules: [
...(config.resolve.modules || []),
path.resolve('./app'),
path.resolve('./')
]
};
return config;
`
κ·Έλ¦¬κ³ κ°μ κ²μ μ»κ³ μμ΅λλ€.
`./app/xv/ui/components/ActionIcon.tsxμ μ€λ₯
λͺ¨λμ μ°Ύμ μ μμ : μ€λ₯ : '/ Users / lukasanderson / workspace / NeXgen-UI / app / xv / ui / components'μμ 'xv / util / decorators'λ₯Ό ν΄κ²°ν μ μμ΅λλ€.
`
config.resolve.extensions.push('.ts', '.tsx');
λ μΆκ°ν΄μΌνλ κ² κ°μ΅λλ€.
@ igor-dv λλ κ·Έμκ²λ κ°μ μ€λ₯λ₯Ό μ£Όμλ€. μ΄κ²μ λν λμμ μ£Όμ μ κ°μ¬ν©λλ€
π€ κ·ΈλΌ λ³΅μ νμ λ΄μΌ ν κ² κ°μμ. κ³΅μ© μ μ₯μκ° μμ΅λκΉ?
μ μκ²λ λ€μκ³Ό κ°μ΄ λ΄ μΉν© ꡬμ±μμ __dirname
λ₯Ό path.resolve
μ μΆκ°νμ¬ μλνμ΅λλ€. (μ λ create-react-app + TypeScript μ€μ μ μμ
μ€μ
λλ€) :
config.resolve.modules = [
...(config.resolve.modules || []),
path.resolve(__dirname, "../"),
path.resolve(__dirname, "../src")
];
λ΄ νμΌ κ΅¬μ‘°, κ·Έμ λ°λΌ μ‘°μ :
```
/λΏλ¦¬
/.storybook
webpack.config.js
/ src
λ΄κ° κΉ¨λ«μ§ λͺ»ν μ΄λ¦¬μμ μ μ resolve.modules
ꡬμ±μ μ ν ../
λ₯Ό μΆκ°νλ κ²μ μμλ€λ κ²μ
λλ€.
μ μκ² μ ν©ν κ²μ λ€μκ³Ό κ°μ΅λλ€.
// .storybook/webpack.config.js
module.exports = {
...,
resolve: {
modules: [path.resolve(__dirname, "../src"), "node_modules"],
}
}
μ΄κ²μ λ΄ μ€ν 리 λΆ μΉν© ꡬμ±μ΄ κΈ°λ³Έ .storybook
λλ ν 리μμ ν λλ ν 리 κΉμ΄μ μκΈ° λλ¬Έμ
λλ€.
λκ΅°κ° μ΄κ±Έ 5 λ² λνμ± μΌλ‘λ³΄κ³ κ³μλ€λ©΄
const path = require('path');
module.exports = ({ config }) => {
config.resolve.modules.push(path.resolve(__dirname, "../src"));
return config;
};
λΉμ μ μλ¦λ€μ΄ μ¬λ @ kexinlu1121. μλ²½νκ² μλνμ΅λλ€. κ°μ¬ν©λλ€.
@glocore μ μ루μ μ κ·Έκ²μ΄ μλνλ λ° νμν ννΈμμ΅λλ€. κ°μ¬!
μ λ κ°μ Έ μ€κΈ°κ° start-storybook
μμ μλνμ§λ§ λΉλ ν λλ μλνμ§ μλ λΉμ·ν λ¬Έμ κ°μμμ΅λλ€. λκ΅°κ° μ°Έκ³ λ₯Ό μνλ©΄ μ¬κΈ°μ μ°Έκ³ μ©μΌλ‘ λ£κ² μ΅λλ€.
μ λ κ°μ Έ μ€κΈ°μ @src
μ μ¬μ©νκ³ μμΌλ©° λ€μ μ€μ μΆκ°νμ¬ μλνλλ‘ λ§λ€μμ΅λλ€.
# /root/.storybook/webpack.config.js
const path = require("path");
module.exports = ({ config }) => {
// ...
// Add absolute path.resolve so storybook can handle absolute import (eg. @src/resources/...)
config.resolve.alias = {
...config.resolve.alias,
"@src": path.resolve(__dirname, "../src"),
};
return config;
};
컨ν μ€νΈλ₯Ό μν΄ λ΄ νλ‘μ νΈ λλ ν 리λ λ€μκ³Ό κ°μ΅λλ€.
/root
.storybook/
webpack.config.js
src/
components/
λμμ΄λκΈ°λ₯Ό λ°λλλ€ :)
@wzulfikar μ루μ μ κ°μ¬λ립λλ€!
CLIλ₯Ό μ¬μ©ν νμ΄ λ¬Έμ κ° λ°μνμΌλ©° .storybook / main.jsλ₯Ό λ€μκ³Ό κ°μ΄ μμ νμ¬ ν΄κ²°ν μμμμ΅λλ€.
const path = require('path');
module.exports = {
...other settings....,
webpackFinal: async (config) => {
config.resolve.modules = [
...(config.resolve.modules || []),
path.resolve(__dirname, "../src"),
];
return config;
},
}
μλ
νμΈμ
React / TSλ₯Ό μ¬μ©νκ³ μμ΅λλ€.
.storybook / main.jsμ κ°μ λ¬Έμ κ° λ°μνμ΅λλ€.
const path = require('path');
module.exports = {
"stories": [
"../src/**/*.stories.mdx",
"../src/**/*.stories.@(js|jsx|ts|tsx)"
],
"addons": [
"@storybook/addon-links",
"@storybook/addon-essentials",
"@storybook/preset-create-react-app",
"@storybook/addon-knobs",
],
webpackFinal: async (config) => {
config.resolve.alias = {
...config.resolve.alias,
'fs': path.resolve(__dirname, 'fsMock.js'),
'child_process': path.resolve(__dirname, 'fsMock.js'),
'net': path.resolve(__dirname, 'fsMock.js'),
'tls': path.resolve(__dirname, 'fsMock.js'),
// "src/types": path.resolve(__dirname, "../src/types"),
// "src/components": path.resolve(__dirname, "../src/components"),
};
config.resolve.modules = [
...(config.resolve.modules || []),
path.resolve(__dirname, "../src"),
];
// config.resolve.extensions.push('.ts', '.tsx');
return config;
},
}
λ΄ κ΅¬μ‘°
.storybook
src
βββ components
| index.ts
β βββ ChildrenComponent
β β βββ index.tsx
β β βββ index.stories.tsx
β βββ ParentComponent
β β βββ index.tsx
β β βββ index.stories.tsx
βββ stories
ParentComponent κ΅¬μ± μμ
import React from "react";
import { ChildrenComponent } from "src/components";
import { ItemType } from "src/types";
export default ({ item }: { item: ItemType }) => {
return (
<p className="hello">
<ChildrenComponent type={item.type} />
<span className="ellipsis">{item.title}</span>
</p>
);
};
λ¬Έμ λ src/components
μμ λΉλ‘―λ©λλ€. μλνλ©΄ μ κ° src/components/ChildrenComponent
ν μ μκΈ° λλ¬Έμ
λλ€.
λλ κ·Έκ²μ μ΄ν΄νμ§ λͺ»νλ€ λλ μ¬κΈ°μμ λͺ¨λ κ²μ μλνκ³ # 333 # 3291 λ° λ€λ₯Έ λ§μ
μ€λ₯μ μ€ν¬λ¦° μ·
λꡬλ μ§ λμΈ μ μμ΅λκΉ?
κ°μ₯ μ μ©ν λκΈ
λκ΅°κ° μ΄κ±Έ 5 λ² λνμ± μΌλ‘λ³΄κ³ κ³μλ€λ©΄