├── .nvmrc ├── .husky ├── .gitignore ├── pre-commit ├── commit-msg └── common.sh ├── .commitlintrc.json ├── .npmrc ├── .prettierrc ├── src ├── pages │ ├── 404.tsx │ └── index.tsx └── components │ ├── Title.tsx │ └── Title.spec.tsx ├── .editorconfig ├── renovate.json ├── gatsby-node.ts ├── gatsby-config.ts ├── vitest.config.ts ├── vitest-setup.ts ├── .gitignore ├── tsconfig.json ├── .github └── workflows │ └── ci.yml ├── LICENSE.md ├── .eslintrc ├── package.json └── README.md /.nvmrc: -------------------------------------------------------------------------------- 1 | 18 2 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.commitlintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["@commitlint/config-conventional"] 3 | } 4 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | save-exact = true 2 | legacy-peer-deps=true 3 | strict-peer-dependencies=false 4 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | . "$(dirname "$0")/common.sh" 4 | 5 | pnpm lint-staged 6 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | . "$(dirname "$0")/common.sh" 4 | 5 | pnpm commitlint --edit $1 6 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "all", 3 | "singleQuote": true, 4 | "printWidth": 80, 5 | "tabWidth": 2, 6 | "endOfLine": "auto" 7 | } 8 | -------------------------------------------------------------------------------- /src/pages/404.tsx: -------------------------------------------------------------------------------- 1 | export default function NotFound() { 2 | return ( 3 |
4 |

Sorry, page not found!

5 |
6 | ); 7 | } 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | -------------------------------------------------------------------------------- /.husky/common.sh: -------------------------------------------------------------------------------- 1 | command_exists () { 2 | command -v "$1" >/dev/null 2>&1 3 | } 4 | 5 | # Workaround for Windows 10, Git Bash and Yarn 6 | if command_exists winpty && test -t 1; then 7 | exec < /dev/tty 8 | fi 9 | -------------------------------------------------------------------------------- /src/components/Title.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react'; 2 | 3 | type TitleProps = { 4 | children: ReactNode; 5 | }; 6 | 7 | export default function Title({ children }: TitleProps) { 8 | return

{children}

; 9 | } 10 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["config:base"], 3 | "semanticCommits": true, 4 | "stabilityDays": 3, 5 | "prCreation": "not-pending", 6 | "labels": ["type: dependencies"], 7 | "packageRules": [ 8 | { 9 | "packageNames": ["node"], 10 | "enabled": false 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /gatsby-node.ts: -------------------------------------------------------------------------------- 1 | import type { GatsbyNode } from 'gatsby'; 2 | import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin'; 3 | 4 | export const onCreateWebpackConfig: GatsbyNode['onCreateWebpackConfig'] = ({ 5 | actions, 6 | }) => { 7 | actions.setWebpackConfig({ 8 | resolve: { 9 | plugins: [new TsconfigPathsPlugin()], 10 | }, 11 | }); 12 | }; 13 | -------------------------------------------------------------------------------- /gatsby-config.ts: -------------------------------------------------------------------------------- 1 | import type { GatsbyConfig } from 'gatsby'; 2 | 3 | const config: GatsbyConfig = { 4 | // Since `gatsby-plugin-typescript` is automatically included in Gatsby you 5 | // don't need to define it here (just if you need to change the options) 6 | plugins: [`gatsby-plugin-pnpm`], 7 | jsxRuntime: `automatic`, 8 | }; 9 | 10 | export default config; 11 | -------------------------------------------------------------------------------- /src/components/Title.spec.tsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import { it, describe, expect } from 'vitest'; 3 | 4 | import Title from '@/components/Title'; 5 | 6 | describe(`Title`, () => { 7 | it(`renders a Title component`, () => { 8 | render(Test Title); 9 | 10 | expect(screen.getByText(`Test Title`)).toBeInTheDocument(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import Title from '@/components/Title'; 2 | 3 | export default function Home() { 4 | return ( 5 |
6 | Hello TypeScript! 7 |

A TypeScript starter for Gatsby. Great for advanced users.

8 |

9 | Follow me on Twitter ( 10 | @jpedroschmitz) 11 |

12 |
13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitest/config'; 2 | import tsconfigPaths from 'vite-tsconfig-paths'; 3 | import react from '@vitejs/plugin-react'; 4 | 5 | export default defineConfig({ 6 | plugins: [tsconfigPaths(), react()], 7 | test: { 8 | globals: true, 9 | setupFiles: `./vitest-setup.ts`, 10 | environment: `jsdom`, 11 | include: [`src/**/*.{spec,test}.{ts,tsx}`], 12 | coverage: { 13 | reporter: [`text`, `json`, `html`], 14 | }, 15 | }, 16 | }); 17 | -------------------------------------------------------------------------------- /vitest-setup.ts: -------------------------------------------------------------------------------- 1 | import { vi } from 'vitest'; 2 | import React from 'react'; 3 | import '@testing-library/jest-dom'; 4 | 5 | vi.mock(`gatsby`, async () => { 6 | const gatsby = await vi.importActual(`gatsby`); 7 | 8 | return { 9 | ...gatsby, 10 | graphql: vi.fn(), 11 | Link: vi.fn().mockImplementation(({ to, ...rest }) => 12 | React.createElement(`a`, { 13 | ...rest, 14 | href: to, 15 | }), 16 | ), 17 | StaticQuery: vi.fn(), 18 | useStaticQuery: vi.fn(), 19 | }; 20 | }); 21 | -------------------------------------------------------------------------------- /.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 | # JetBrains IDE files 9 | .idea/ 10 | 11 | # testing 12 | /coverage 13 | 14 | # gatsby 15 | .cache/ 16 | public/ 17 | 18 | # production 19 | /build 20 | 21 | # misc 22 | .DS_Store 23 | *.pem 24 | tsconfig.tsbuildinfo 25 | 26 | # debug 27 | npm-debug.log* 28 | yarn-debug.log* 29 | yarn-error.log* 30 | .pnpm-debug.log* 31 | 32 | # local env files 33 | .env\* 34 | 35 | # vercel 36 | .vercel 37 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "lib": ["dom", "esnext"], 5 | "jsx": "react-jsx", 6 | "module": "esnext", 7 | "moduleResolution": "node", 8 | "esModuleInterop": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "strict": true, 11 | "skipLibCheck": true, 12 | "baseUrl": ".", 13 | "paths": { 14 | "@/*": ["./src/*"], 15 | "@/static/*": ["./static/*"] 16 | }, 17 | "types": ["node", "@testing-library/jest-dom"] 18 | }, 19 | "exclude": ["node_modules"], 20 | "include": ["./src/**/*"] 21 | } 22 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Check PR 2 | 3 | on: [pull_request] 4 | 5 | jobs: 6 | run-ci: 7 | env: 8 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 9 | 10 | name: Run Type Check & Linters 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - name: Checkout repository 15 | uses: actions/checkout@v3 16 | with: 17 | fetch-depth: 0 18 | 19 | - name: Install pnpm 20 | uses: pnpm/action-setup@v2.2.4 21 | with: 22 | version: 7 23 | 24 | - name: Set up Node 25 | uses: actions/setup-node@v3 26 | with: 27 | node-version: lts/* 28 | cache: 'pnpm' 29 | 30 | - name: Install dependencies 31 | run: pnpm install 32 | 33 | - name: Check types 34 | run: pnpm type-check 35 | 36 | - name: Check linting 37 | run: pnpm lint 38 | 39 | - name: Run tests 40 | run: pnpm test 41 | 42 | - name: Check commits messages 43 | uses: wagoid/commitlint-github-action@v5 44 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 João Pedro Schmitz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@typescript-eslint/parser", 3 | "parserOptions": { 4 | "ecmaFeatures": { 5 | "jsx": true 6 | }, 7 | "ecmaVersion": "latest", 8 | "sourceType": "module" 9 | }, 10 | "env": { 11 | "browser": true, 12 | "es6": true, 13 | "node": true 14 | }, 15 | "plugins": ["react", "jsx-a11y", "prettier", "@typescript-eslint"], 16 | "extends": [ 17 | "plugin:react/recommended", 18 | "plugin:react/jsx-runtime", 19 | "plugin:react-hooks/recommended", 20 | "standard", 21 | "plugin:prettier/recommended" 22 | ], 23 | "rules": { 24 | "prettier/prettier": "error", 25 | "react/prop-types": "off", 26 | "react/jsx-filename-extension": "off", 27 | "react/jsx-props-no-spreading": "off", 28 | "import/prefer-default-export": "off", 29 | "import/extensions": [ 30 | "error", 31 | "ignorePackages", 32 | { 33 | "ts": "never", 34 | "tsx": "never", 35 | "js": "never", 36 | "jsx": "never" 37 | } 38 | ], 39 | "@typescript-eslint/explicit-function-return-type": "off", 40 | "@typescript-eslint/no-explicit-any": "off", 41 | "@typescript-eslint/no-var-requires": "off", 42 | "quotes": "off", 43 | "@typescript-eslint/quotes": [ 44 | 2, 45 | "backtick", 46 | { 47 | "avoidEscape": true 48 | } 49 | ], 50 | "@typescript-eslint/no-unused-vars": [2, { "argsIgnorePattern": "^_" }] 51 | }, 52 | "settings": { 53 | "import/resolver": { 54 | "typescript": { 55 | "project": "." 56 | } 57 | }, 58 | "react": { 59 | "version": "detect" 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gatsby-starter-ts", 3 | "description": "A TypeScript starter for Gatsby that includes all you need to build amazing projects", 4 | "version": "1.0.0", 5 | "private": true, 6 | "author": "João Pedro Schmitz (https://joaopedro.dev)", 7 | "license": "MIT", 8 | "keywords": [ 9 | "gatsby", 10 | "starter", 11 | "typescript" 12 | ], 13 | "scripts": { 14 | "start": "gatsby develop", 15 | "build": "gatsby build", 16 | "serve": "gatsby serve", 17 | "clean": "gatsby clean", 18 | "type-check": "tsc --noEmit", 19 | "lint": "eslint --ignore-path .gitignore \"src/**/*.+(ts|js|tsx)\"", 20 | "format": "prettier --ignore-path .gitignore \"src/**/*.+(ts|js|tsx)\" --write", 21 | "postinstall": "husky install", 22 | "test": "vitest", 23 | "test:watch": "vitest watch" 24 | }, 25 | "engines": { 26 | "node": ">=18.0.0" 27 | }, 28 | "lint-staged": { 29 | "./src/**/*.{ts,js,jsx,tsx}": [ 30 | "eslint --ignore-path .gitignore --fix", 31 | "prettier --ignore-path .gitignore --write" 32 | ] 33 | }, 34 | "dependencies": { 35 | "gatsby": "5.9.0", 36 | "gatsby-plugin-pnpm": "1.2.10", 37 | "react": "18.2.0", 38 | "react-dom": "18.2.0", 39 | "tsconfig-paths-webpack-plugin": "4.0.1" 40 | }, 41 | "devDependencies": { 42 | "@babel/preset-react": "7.18.6", 43 | "@babel/preset-typescript": "7.21.5", 44 | "@commitlint/cli": "17.6.3", 45 | "@commitlint/config-conventional": "17.6.3", 46 | "@testing-library/dom": "9.2.0", 47 | "@testing-library/jest-dom": "5.16.5", 48 | "@testing-library/react": "14.0.0", 49 | "@testing-library/react-hooks": "8.0.1", 50 | "@types/node": "18.16.5", 51 | "@types/react": "18.2.6", 52 | "@types/react-dom": "18.2.4", 53 | "@types/testing-library__jest-dom": "5.14.5", 54 | "@typescript-eslint/eslint-plugin": "5.59.2", 55 | "@typescript-eslint/parser": "5.59.2", 56 | "@vitejs/plugin-react": "4.0.0", 57 | "babel-preset-gatsby": "3.9.0", 58 | "c8": "7.13.0", 59 | "eslint": "8.40.0", 60 | "eslint-config-prettier": "8.8.0", 61 | "eslint-config-standard": "17.0.0", 62 | "eslint-import-resolver-typescript": "3.5.5", 63 | "eslint-plugin-import": "2.27.5", 64 | "eslint-plugin-jsx-a11y": "6.7.1", 65 | "eslint-plugin-n": "15.7.0", 66 | "eslint-plugin-prettier": "4.2.1", 67 | "eslint-plugin-promise": "6.1.1", 68 | "eslint-plugin-react": "7.32.2", 69 | "eslint-plugin-react-hooks": "4.6.0", 70 | "husky": "8.0.3", 71 | "identity-obj-proxy": "3.0.0", 72 | "jsdom": "22.0.0", 73 | "lint-staged": "13.2.2", 74 | "prettier": "2.8.8", 75 | "typescript": "5.0.4", 76 | "vite-tsconfig-paths": "4.2.0", 77 | "vitest": "0.31.0" 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Gatsby TypeScript Starter 3 |

4 | 5 |
6 | 7 |
Non-opinionated TypeScript starter for Gatsby
8 |
A TypeScript starter for Gatsby. No plugins and styling. Exactly the necessary to start.
9 | 10 |
11 | 12 |
13 | PRs welcome! 14 | 15 | License 16 | 17 | 18 | Follow @jpedroschmitz 19 | 20 |
21 | 22 |
23 | Created by João Pedro with the help of many wonderful contributors. 24 |
25 | 26 |
27 | 28 | ## Features 29 | 30 | - ⚡️ Gatsby 5 31 | - ⚛️ React 18 32 | - ⛑ TypeScript 33 | - 🐐 Tests — Vitest and Testing Library out of the box 34 | - 📏 ESLint — To find and fix problems in your code 35 | - 💖 Prettier — Code Formatter for consistent style 36 | - 🐶 Husky — For running scripts before committing 37 | - 🚓 Commitlint — To make sure your commit messages follow the convention 38 | - 🖌 Renovate — To keep your dependencies up to date 39 | - 🚫 lint-staged — Run ESLint and Prettier against staged Git files 40 | - 👷 PR Workflow — Run Type Check & Linters on Pull Requests 41 | - ⚙️ EditorConfig - Consistent coding styles across editors and IDEs 42 | - 🗂 Path Mapping — Import components or images using the `@` prefix 43 | 44 | ## Quick Start 45 | 46 | The best way to start with this template is using the [Gatsby CLI](https://www.gatsbyjs.com/docs/reference/gatsby-cli/). 47 | 48 | ``` 49 | npx gatsby new starter-ts https://github.com/jpedroschmitz/gatsby-starter-ts 50 | ``` 51 | 52 | ### Development 53 | 54 | To start the project locally, run: 55 | 56 | ```bash 57 | pnpm start 58 | ``` 59 | 60 | Open `http://localhost:8000` with your browser to see the result. 61 | 62 | ## Documentation 63 | 64 | ### Requirements 65 | 66 | - Node.js >= 18 67 | - pnpm 7 68 | 69 | ### Directory Structure 70 | 71 | - [`__helpers__`](./__helpers__/) — Helpers files for testing configuration.
72 | - [`__mocks__`](./__mocks__/) — Mocks for testing.
73 | - [`.github`](.github) — GitHub configuration including the CI workflow.
74 | - [`.husky`](.husky) — Husky configuration and hooks.
75 | - [`src`](./src) — Application source code, including pages, components, styles. 76 | 77 | ### Scripts 78 | 79 | - `pnpm start` — Starts the application in development mode at `http://localhost:8000`. 80 | - `pnpm build` — Compile your application and make it ready for deployment. 81 | - `pnpm serve` — Serve the production build of your site 82 | - `pnpm clean` — Wipe out the cache (`.cache` folder). 83 | - `pnpm type-check` — Validate code using TypeScript compiler. 84 | - `pnpm lint` — Runs ESLint for all files in the `src` directory. 85 | - `pnpm format` — Runs Prettier for all files in the `src` directory. 86 | - `pnpm test` — Run tests with Vitest. 87 | - `pnpm test:watch` — Run tests on watch mode. 88 | 89 | ### Path Mapping 90 | 91 | TypeScript are pre-configured with custom path mappings. To import components or files, use the `@` prefix. 92 | 93 | ```tsx 94 | import { Button } from '@/components/Button'; 95 | 96 | // To import images or other files from the static folder 97 | import avatar from '@/static/avatar.png'; 98 | ``` 99 | 100 | ### Switch to Yarn/npm 101 | 102 | This starter uses pnpm by default, but this choice is yours. If you'd like to switch to Yarn/npm, delete the `pnpm-lock.yaml` file, install the dependencies with Yarn/npm, change the CI workflow, Husky Git hooks to use Yarn/npm commands, and uninstall the `gatsby-plugin-pnpm` plugin (you also need to remove it from the `gatsby-config` file). 103 | 104 | ## License 105 | 106 | This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for more information. 107 | --------------------------------------------------------------------------------