├── .babelrc ├── .eslintrc ├── .gitignore ├── .postcssrc ├── .storybook ├── addons.js ├── config.js └── webpack.config.js ├── jest.config.js ├── package-lock.json ├── package.json ├── public ├── favicon.ico └── index.html ├── src ├── App.vue ├── assets │ └── logo.png ├── components │ └── HelloWorld.vue ├── main.ts ├── shims.d.ts └── stories │ ├── MyButton.vue │ ├── Welcome.js │ └── index.stories.ts ├── tests └── unit │ ├── .eslintrc │ └── HelloWorld.spec.ts └── tsconfig.json /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@vue/app"] 3 | } 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": [ 4 | "plugin:vue/essential", 5 | "@vue/prettier", 6 | "@vue/typescript" 7 | ] 8 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | -------------------------------------------------------------------------------- /.postcssrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": { 3 | "autoprefixer": {} 4 | } 5 | } -------------------------------------------------------------------------------- /.storybook/addons.js: -------------------------------------------------------------------------------- 1 | import '@storybook/addon-actions/register' 2 | import '@storybook/addon-links/register' 3 | -------------------------------------------------------------------------------- /.storybook/config.js: -------------------------------------------------------------------------------- 1 | import { configure } from "@storybook/vue"; 2 | 3 | // automatically import all files ending in *.stories.js 4 | const req = require.context("../src/stories", true, /.stories.ts$/); 5 | function loadStories() { 6 | req.keys().forEach(filename => req(filename)); 7 | } 8 | 9 | configure(loadStories, module); 10 | -------------------------------------------------------------------------------- /.storybook/webpack.config.js: -------------------------------------------------------------------------------- 1 | const merge = require("webpack-merge"); 2 | 3 | const genStorybookDefaultConfig = require("@storybook/vue/dist/server/config/defaults/webpack.config.js"); 4 | 5 | const vueConfig = require("@vue/cli-service/webpack.config.js"); 6 | 7 | module.exports = (storybookBaseConfig, configType) => { 8 | const storybookConfig = genStorybookDefaultConfig( 9 | storybookBaseConfig, 10 | configType 11 | ); 12 | 13 | return { 14 | ...vueConfig, // use vue's webpack configuration by default 15 | entry: storybookConfig.entry, // overwite entry 16 | output: storybookConfig.output, // overwrite output 17 | // remove duplicated plugins 18 | plugins: merge({ 19 | customizeArray: merge.unique( 20 | "plugins", 21 | [ 22 | "HotModuleReplacementPlugin", 23 | "CaseSensitivePathsPlugin", 24 | "WatchMissingNodeModulesPlugin" 25 | ], 26 | plugin => plugin.constructor && plugin.constructor.name 27 | ) 28 | })(vueConfig, storybookConfig).plugins, 29 | resolve: { 30 | // <--------- This bit here 31 | ...vueConfig.resolve, 32 | alias: { 33 | ...vueConfig.resolve.alias, 34 | vue$: storybookConfig.resolve.alias.vue$ 35 | } 36 | } 37 | }; 38 | }; 39 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "vue"], 3 | transform: { 4 | "^.+\\.vue$": "vue-jest", 5 | "^.+\\.tsx?$": "ts-jest" 6 | }, 7 | moduleNameMapper: { 8 | "^@/(.*)$": "/src/$1" 9 | }, 10 | snapshotSerializers: ["jest-serializer-vue"] 11 | }; 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typescript-vue-storybook-tutorial", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve --open", 7 | "build": "vue-cli-service build", 8 | "test": "vue-cli-service test", 9 | "lint": "vue-cli-service lint", 10 | "storybook": "start-storybook -p 6006", 11 | "build-storybook": "build-storybook" 12 | }, 13 | "dependencies": { 14 | "vue": "^2.5.13", 15 | "vue-class-component": "^6.0.0", 16 | "vue-property-decorator": "^6.0.0" 17 | }, 18 | "devDependencies": { 19 | "@storybook/addon-actions": "^3.3.15", 20 | "@storybook/addon-links": "^3.3.15", 21 | "@storybook/addons": "^3.3.15", 22 | "@storybook/vue": "^3.3.15", 23 | "@types/jest": "^22.0.1", 24 | "@types/storybook__addon-actions": "^3.0.3", 25 | "@types/storybook__addon-links": "^3.3.0", 26 | "@types/storybook__vue": "^3.3.0", 27 | "@vue/cli-plugin-babel": "^3.0.0-beta.6", 28 | "@vue/cli-plugin-eslint": "^3.0.0-beta.6", 29 | "@vue/cli-plugin-typescript": "^3.0.0-beta.6", 30 | "@vue/cli-plugin-unit-jest": "^3.0.0-beta.6", 31 | "@vue/cli-service": "^3.0.0-beta.6", 32 | "@vue/eslint-config-prettier": "^3.0.0-beta.6", 33 | "@vue/eslint-config-typescript": "^3.0.0-beta.6", 34 | "@vue/test-utils": "^1.0.0-beta.10", 35 | "babel-core": "^7.0.0-0", 36 | "babel-preset-vue": "^2.0.1", 37 | "lint-staged": "^6.0.0", 38 | "node-sass": "^4.7.2", 39 | "sass-loader": "^6.0.6", 40 | "ts-jest": "^22.0.1", 41 | "vue-template-compiler": "^2.5.13", 42 | "webpack-merge": "^4.1.2" 43 | }, 44 | "browserslist": [ 45 | "> 1%", 46 | "last 2 versions", 47 | "not ie <= 8" 48 | ], 49 | "gitHooks": { 50 | "pre-commit": "lint-staged" 51 | }, 52 | "lint-staged": { 53 | "*.js": [ 54 | "vue-cli-service lint", 55 | "git add" 56 | ], 57 | "*.vue": [ 58 | "vue-cli-service lint", 59 | "git add" 60 | ] 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/almeynman/typescript-vue-storybook-tutorial/859624522db910efdbbda207a1c54fff6f72b4fc/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | typescript-vue-storybook-tutorial 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 19 | 20 | 30 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/almeynman/typescript-vue-storybook-tutorial/859624522db910efdbbda207a1c54fff6f72b4fc/src/assets/logo.png -------------------------------------------------------------------------------- /src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 42 | 43 | 44 | 60 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import App from "./App.vue"; 3 | 4 | Vue.config.productionTip = false; 5 | 6 | new Vue({ 7 | render: h => h(App) 8 | }).$mount("#app"); 9 | -------------------------------------------------------------------------------- /src/shims.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.vue" { 2 | import Vue from "vue"; 3 | export default Vue; 4 | } 5 | -------------------------------------------------------------------------------- /src/stories/MyButton.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 32 | -------------------------------------------------------------------------------- /src/stories/Welcome.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-console 2 | const log = () => console.log("Welcome to storybook!"); 3 | 4 | export default { 5 | name: "welcome", 6 | 7 | props: { 8 | showApp: { 9 | type: Function, 10 | default: log 11 | } 12 | }, 13 | 14 | data() { 15 | return { 16 | main: { 17 | margin: 15, 18 | maxWidth: 600, 19 | lineHeight: 1.4, 20 | fontFamily: 21 | '"Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif' 22 | }, 23 | 24 | logo: { 25 | width: 200 26 | }, 27 | 28 | link: { 29 | color: "#1474f3", 30 | textDecoration: "none", 31 | borderBottom: "1px solid #1474f3", 32 | paddingBottom: 2 33 | }, 34 | 35 | code: { 36 | fontSize: 15, 37 | fontWeight: 600, 38 | padding: "2px 5px", 39 | border: "1px solid #eae9e9", 40 | borderRadius: 4, 41 | backgroundColor: "#f3f2f2", 42 | color: "#3a3a3a" 43 | }, 44 | 45 | note: { 46 | opacity: 0.5 47 | } 48 | }; 49 | }, 50 | 51 | template: ` 52 |
53 |

Welcome to STORYBOOK

54 |

55 | This is a UI component dev environment for your app. 56 |

57 |

58 | We've added some basic stories inside the 59 |
60 | src/stories 61 |
62 | directory. 63 |
64 | A story is a single state of one or more UI components. You can have as many stories as 65 | you want. 66 |
67 | (Basically a story is like a visual test case.) 68 |

69 |

70 | See these sample 71 |
72 | stories 73 |
74 | for a component called 75 |
76 | Button 77 | . 78 |

79 |

80 | Just like that, you can add your own components as stories. 81 |
82 | You can also edit those components and see changes right away. 83 |
84 | (Try editing the Button component 85 | located at src/stories/Button.js.) 86 |

87 |

88 | This is just one thing you can do with Storybook. 89 |
90 | Have a look at the 91 |
92 | 98 | Storybook 99 | 100 |
101 | repo for more information. 102 |

103 |

104 | NOTE: 105 |
106 | Have a look at the 107 |
108 | .storybook/webpack.config.js 109 |
110 | to add webpack 111 | loaders and plugins you are using in this project. 112 |

113 |
114 | `, 115 | 116 | methods: { 117 | onClick(event) { 118 | event.preventDefault(); 119 | this.showApp(); 120 | } 121 | } 122 | }; 123 | -------------------------------------------------------------------------------- /src/stories/index.stories.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable react/react-in-jsx-scope */ 2 | 3 | import { storiesOf } from "@storybook/vue"; 4 | import { action } from "@storybook/addon-actions"; 5 | import { linkTo } from "@storybook/addon-links"; 6 | 7 | import MyButton from "./MyButton.vue"; 8 | import Welcome from "./Welcome"; 9 | 10 | storiesOf("Welcome", module).add("to Storybook", () => ({ 11 | components: { Welcome }, 12 | template: '', 13 | methods: { action: linkTo("Button") } 14 | })); 15 | 16 | storiesOf("Button", module) 17 | .add("with text", () => ({ 18 | components: { MyButton }, 19 | template: 'Hello Button', 20 | methods: { action: action("clicked") } 21 | })) 22 | .add("with some emoji", () => ({ 23 | components: { MyButton }, 24 | template: '😀 😎 👍 💯', 25 | methods: { action: action("clicked") } 26 | })); 27 | 28 | /* eslint-enable react/react-in-jsx-scope */ 29 | -------------------------------------------------------------------------------- /tests/unit/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "jest": true 4 | }, 5 | "rules": { 6 | "import/no-extraneous-dependencies": "off" 7 | } 8 | } -------------------------------------------------------------------------------- /tests/unit/HelloWorld.spec.ts: -------------------------------------------------------------------------------- 1 | import { shallow } from "@vue/test-utils"; 2 | import HelloWorld from "@/components/HelloWorld.vue"; 3 | 4 | describe("HelloWorld.vue", () => { 5 | it("renders props.msg when passed", () => { 6 | const msg = "new message"; 7 | const wrapper = shallow(HelloWorld, { 8 | propsData: { msg } 9 | }); 10 | expect(wrapper.text()).toMatch(msg); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2015", 4 | "module": "es2015", 5 | "strict": true, 6 | "jsx": "preserve", 7 | "moduleResolution": "node", 8 | "experimentalDecorators": true, 9 | "emitDecoratorMetadata": true, 10 | "allowSyntheticDefaultImports": true, 11 | "sourceMap": true, 12 | "baseUrl": ".", 13 | "types": [ 14 | "node", 15 | "jest" 16 | ], 17 | "paths": { 18 | "@/*": [ 19 | "src/*" 20 | ] 21 | } 22 | }, 23 | "include": [ 24 | "src/**/*.ts", 25 | "src/**/*.vue", 26 | "tests/**/*.ts" 27 | ], 28 | "exclude": [ 29 | "node_modules" 30 | ] 31 | } 32 | --------------------------------------------------------------------------------