├── .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 |
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 |
21 |
22 |
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 |
--------------------------------------------------------------------------------