├── .gitignore
├── .storybook
├── main.js
├── next-preset.js
└── preview.js
├── README.md
├── babel.config.json
├── components
├── Button.stories.tsx
├── Button.tsx
└── __test__
│ ├── Button.snapshot.test.tsx
│ ├── __snapshots__
│ └── Button.snapshot.test.tsx.snap
│ └── index.test.tsx
├── config
└── setup.js
├── jest.config.js
├── next-env.d.ts
├── package-lock.json
├── package.json
├── pages
├── api
│ └── hello.js
└── index.tsx
├── public
├── favicon.ico
└── vercel.svg
├── styles
└── global.scss
├── tsconfig.json
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 |
21 | # debug
22 | npm-debug.log*
23 | yarn-debug.log*
24 | yarn-error.log*
25 |
26 | # local env files
27 | .env.local
28 | .env.development.local
29 | .env.test.local
30 | .env.production.local
31 |
--------------------------------------------------------------------------------
/.storybook/main.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 |
3 | module.exports = {
4 | stories: ["../components/**/*.stories.tsx"],
5 | // Add nextjs preset
6 | presets: [path.resolve(__dirname, "./next-preset.js")],
7 | };
8 |
--------------------------------------------------------------------------------
/.storybook/next-preset.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 |
3 | module.exports = {
4 | webpackFinal: async (baseConfig, options) => {
5 | const { module = {} } = baseConfig;
6 |
7 | const newConfig = {
8 | ...baseConfig,
9 | module: {
10 | ...module,
11 | rules: [...(module.rules || [])],
12 | },
13 | };
14 |
15 | // TypeScript with Next.js
16 | newConfig.module.rules.push({
17 | test: /\.(ts|tsx)$/,
18 | include: [path.resolve(__dirname, "../components")],
19 | use: [
20 | {
21 | loader: "babel-loader",
22 | options: {
23 | presets: ["next/babel", require.resolve("babel-preset-react-app")],
24 | plugins: ["react-docgen"],
25 | },
26 | },
27 | ],
28 | });
29 | newConfig.resolve.extensions.push(".ts", ".tsx");
30 |
31 | // SCSS preset for Storybook
32 | newConfig.module.rules.push({
33 | test: /\.(s*)css$/,
34 | loaders: ["style-loader", "css-loader", "sass-loader"],
35 | include: path.resolve(__dirname, "../styles/global.scss"),
36 | });
37 |
38 | return newConfig;
39 | },
40 | };
41 |
--------------------------------------------------------------------------------
/.storybook/preview.js:
--------------------------------------------------------------------------------
1 | // Import global css here
2 | import "../styles/global.scss";
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #
2 |
3 |
Template for Storybook, Next, Typescript, SCSS and Jest
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | This simple guide will help you to set up `Storybook`, `Next`, `Typescript`, `SCSS` and `Jest`.
16 |
17 | You can find the full tutorial on [Medium](https://medium.com/@trinwin/2020-complete-setup-for-storybook-nextjs-typescript-scss-and-jest-1c9ce41e6481) 📕 or [DEV.to](https://dev.to/trinwin/2020-complete-setup-for-storybook-nextjs-typescript-scss-and-jest-4khm)
18 |
19 | ## ✅ Getting Started
20 |
21 | These instructions will get you a copy of the project up and running on your local machine for development and testing purposes.
22 |
23 | ### ⚒️ Installation
24 |
25 | ```
26 | # Clone this repository
27 | git clone https://github.com/trinwin/storybook-next-ts-template
28 |
29 | # Go into the repository
30 | cd storybook-next-ts-template
31 |
32 | # Install client dependencies
33 | yarn install
34 |
35 | # Start client on localhost:3000
36 | yarn run dev
37 |
38 | # Start Storybook
39 | yarn storybook
40 |
41 | # Run your test
42 | yarn test
43 | ```
44 |
45 | ## ⭐️ Author
46 |
47 | 👩🏻💻 **Trinity Nguyen** - [trinwin](https://github.com/trinwin)
48 |
49 | ➡️ I will continue to update and make changes to the tutorial.
50 |
51 | 🤙🏻 Please let me know if you run into any problem.
52 |
53 | 🤝 Connect with me and find my works on:
54 |
55 | - [Twitter](https://twitter.com/_trinwin)
56 | - [Medium](https://medium.com/@trinwin)
57 | - [DEV.to](https://dev.to/trinwin)
58 | - [LinkedIn](https://www.linkedin.com/in/trinwin)
59 |
--------------------------------------------------------------------------------
/babel.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-env", "@babel/preset-react", "@babel/preset-flow"],
3 | "plugins": [
4 | "@babel/plugin-transform-runtime",
5 | "@babel/plugin-syntax-dynamic-import",
6 | "@babel/plugin-transform-modules-commonjs",
7 | "@babel/plugin-proposal-class-properties"
8 | ],
9 | "env": {
10 | "development": {
11 | "plugins": ["transform-es2015-modules-commonjs"]
12 | },
13 | "test": {
14 | "plugins": [
15 | "transform-es2015-modules-commonjs",
16 | "@babel/plugin-proposal-class-properties"
17 | ],
18 | "presets": ["@babel/preset-react"]
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/components/Button.stories.tsx:
--------------------------------------------------------------------------------
1 | import { storiesOf } from "@storybook/react";
2 | import Button from "./Button";
3 |
4 | storiesOf("Button", module).add("with text", () => {
5 | return ;
6 | });
7 |
8 | storiesOf("Button", module).add("with emoji", () => {
9 | return ;
10 | });
11 |
--------------------------------------------------------------------------------
/components/Button.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | type Props = {
4 | text: string;
5 | };
6 |
7 | export default ({ text }: Props) => ;
8 |
--------------------------------------------------------------------------------
/components/__test__/Button.snapshot.test.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Button from "../Button";
3 | import renderer from "react-test-renderer";
4 |
5 | it("renders correctly", () => {
6 | const tree = renderer.create().toJSON();
7 | expect(tree).toMatchSnapshot();
8 | });
9 |
--------------------------------------------------------------------------------
/components/__test__/__snapshots__/Button.snapshot.test.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`renders correctly 1`] = `
4 |
7 | `;
8 |
--------------------------------------------------------------------------------
/components/__test__/index.test.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { mount } from "enzyme";
3 | import Home from "../../pages/index";
4 | describe("Pages", () => {
5 | describe("Home", () => {
6 | it("should render without throwing an error", function () {
7 | const wrap = mount();
8 | expect(wrap.find("h1").text()).toBe("Welcome to My Next App!");
9 | });
10 | });
11 | });
12 |
--------------------------------------------------------------------------------
/config/setup.js:
--------------------------------------------------------------------------------
1 | const enzyme = require("enzyme");
2 | const Adapter = require("enzyme-adapter-react-16");
3 |
4 | enzyme.configure({ adapter: new Adapter() });
5 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | collectCoverageFrom: [
3 | "**/*.{ts,tsx}",
4 | "!**/node_modules/**",
5 | "!**/.storybook/**",
6 | "!**/tests/**",
7 | "!**/coverage/**",
8 | "!jest.config.js",
9 | ],
10 | coverageThreshold: {
11 | global: {
12 | branches: 100,
13 | functions: 100,
14 | lines: 100,
15 | statements: 100,
16 | },
17 | },
18 | setupFiles: ["/config/setup.js"],
19 | preset: "ts-jest",
20 | testPathIgnorePatterns: [
21 | "/.next/",
22 | "/node_modules/",
23 | "/lib/",
24 | "/tests/",
25 | "/coverage/",
26 | "/.storybook/",
27 | ],
28 | testRegex: "(/__test__/.*|\\.(test|spec))\\.(ts|tsx|js)$",
29 | testURL: "http://localhost",
30 | testEnvironment: "jsdom",
31 | moduleFileExtensions: ["ts", "tsx", "js", "json"],
32 | moduleNameMapper: {
33 | "\\.(css|less)$": "/__mocks__/styleMock.js",
34 | "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$":
35 | "/__mocks__/fileMock.js",
36 | },
37 | transform: {
38 | ".(ts|tsx)": "babel-jest",
39 | },
40 | transformIgnorePatterns: ["/node_modules/"],
41 | };
42 |
--------------------------------------------------------------------------------
/next-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "my-app",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "storybook": "start-storybook -p 6006 -c .storybook",
10 | "test": "jest",
11 | "test:watch": "jest --watch",
12 | "test:coverage": "jest --coverage"
13 | },
14 | "dependencies": {
15 | "next": "9.5.4",
16 | "react": "16.13.1",
17 | "react-dom": "16.13.1",
18 | "sass": "^1.26.10"
19 | },
20 | "devDependencies": {
21 | "@babel/core": "^7.11.0",
22 | "@babel/plugin-transform-runtime": "^7.11.0",
23 | "@babel/preset-env": "^7.11.0",
24 | "@babel/preset-flow": "^7.10.4",
25 | "@babel/preset-react": "^7.10.4",
26 | "@storybook/react": "^6.0.27",
27 | "@types/enzyme": "^3.10.5",
28 | "@types/jest": "^26.0.8",
29 | "@types/node": "^14.0.27",
30 | "@types/react": "^16.9.44",
31 | "babel-jest": "^26.2.2",
32 | "babel-loader": "^8.1.0",
33 | "babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
34 | "babel-preset-react-app": "^9.1.2",
35 | "css-loader": "^4.2.0",
36 | "enzyme": "^3.11.0",
37 | "enzyme-adapter-react-16": "^1.15.2",
38 | "jest": "^26.2.2",
39 | "sass-loader": "^9.0.2",
40 | "style-loader": "^1.2.1",
41 | "ts-jest": "^26.1.4",
42 | "typescript": "^3.9.7"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/pages/api/hello.js:
--------------------------------------------------------------------------------
1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
2 |
3 | export default (req, res) => {
4 | res.statusCode = 200
5 | res.json({ name: 'John Doe' })
6 | }
7 |
--------------------------------------------------------------------------------
/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | const Home = () => {
4 | return Welcome to My Next App!
;
5 | };
6 |
7 | export default Home;
8 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trinwin/storybook-next-ts-template/363694179db1a2c61d3308e983e57df3338992af/public/favicon.ico
--------------------------------------------------------------------------------
/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/styles/global.scss:
--------------------------------------------------------------------------------
1 | html {
2 | background: #f1f1f1;
3 | max-width: 100%;
4 | }
5 |
6 | body {
7 | background: linear-gradient(315deg, var(#f1f1f1) 0%, var(#e7e7e7) 100%);
8 | font-family: "SF Pro Display", -apple-system, BlinkMacSystemFont, "Segoe UI",
9 | "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans",
10 | "Helvetica Neue", system-ui, sans-serif !important;
11 | }
12 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "noEmit": true,
10 | "esModuleInterop": true,
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "noImplicitAny": false,
16 | "jsx": "preserve",
17 | "baseUrl": "./",
18 | "paths": {
19 | "@components/*": ["./components/*"]
20 | }
21 | },
22 | "exclude": ["node_modules"],
23 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"]
24 | }
25 |
--------------------------------------------------------------------------------