├── pages ├── about │ ├── index.css │ └── index.page.tsx ├── _default │ ├── types.ts │ ├── PageLayout.tsx │ ├── _default.page.client.tsx │ ├── _default.page.server.tsx │ └── logo.svg ├── _error.page.tsx └── index.page.tsx ├── .env.sample ├── .eslintignore ├── .gitignore ├── .prettierignore ├── screenshot-rocks.jpeg ├── types.d.ts ├── .husky ├── commit-msg └── pre-commit ├── nodemon.json ├── vite.config.ts ├── .commitlintrc.json ├── .prettierrc.js ├── tsconfig.json ├── README.md ├── server ├── auth.ts └── index.ts ├── .eslintrc.js └── package.json /pages/about/index.css: -------------------------------------------------------------------------------- 1 | h1, 2 | p { 3 | color: green; 4 | } 5 | -------------------------------------------------------------------------------- /.env.sample: -------------------------------------------------------------------------------- 1 | NEXTAUTH_URL="" 2 | GOOGLE_CLIENT_ID="" 3 | GOOGLE_CLIENT_SECRET="" -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist 4 | dist-ssr 5 | *.local 6 | node_modules/* -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist 4 | *.local 5 | yarn-error.log 6 | .env 7 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist 4 | dist-ssr 5 | *.local 6 | node_modules/* -------------------------------------------------------------------------------- /screenshot-rocks.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/s-kris/vite-ssr-starter/HEAD/screenshot-rocks.jpeg -------------------------------------------------------------------------------- /types.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.svg" { 2 | const imageUrl: string; 3 | export default imageUrl; 4 | } 5 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx --no-install commitlint --edit 5 | -------------------------------------------------------------------------------- /nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "watch": ["server"], 3 | "exec": "ts-node server/index.ts", 4 | "ext": "js ts" 5 | } -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | tsc --noEmit -p tsconfig.json && yarn lint-staged 5 | -------------------------------------------------------------------------------- /pages/about/index.page.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import "./index.css"; 3 | 4 | export { Page }; 5 | 6 | function Page() { 7 | return ( 8 | <> 9 |
A colored page.
11 | > 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import reactRefresh from "@vitejs/plugin-react-refresh"; 2 | import ssr from "vite-plugin-ssr/plugin"; 3 | import { UserConfig } from "vite"; 4 | 5 | const config: UserConfig = { 6 | plugins: [reactRefresh(), ssr()], 7 | }; 8 | 9 | export default config; 10 | -------------------------------------------------------------------------------- /pages/_default/types.ts: -------------------------------------------------------------------------------- 1 | export type ReactComponent = (pageProps: PageProps) => JSX.Element; 2 | export type PageProps = {}; 3 | export type PageContext = { 4 | Page: ReactComponent; 5 | pageProps: PageProps; 6 | documentProps?: { 7 | title?: string; 8 | description?: string; 9 | }; 10 | }; 11 | -------------------------------------------------------------------------------- /.commitlintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "@commitlint/config-conventional" 4 | ], 5 | "rules": { 6 | "scope-enum": [ 7 | 2, 8 | "always", 9 | [ 10 | "api", 11 | "ui", 12 | "tests" 13 | ] 14 | ] 15 | } 16 | } -------------------------------------------------------------------------------- /pages/_default/PageLayout.tsx: -------------------------------------------------------------------------------- 1 | import { ChakraProvider } from '@chakra-ui/react'; 2 | import React from 'react'; 3 | 4 | export { PageLayout }; 5 | 6 | type Children = React.ReactNode; 7 | 8 | function PageLayout({ children }: { children: Children }) { 9 | return ( 10 |
6 |
7 | It is built using following stack for linting, formatting, type-checking, authentication:
8 |
9 | 1. vite-plugin-ssr
10 | 2. reactjs
11 | 3. typescript
12 | 4. eslint
13 | 5. prettier
14 | 6. husky
15 | 7. commit-lint
16 | 8. chakra-ui
17 | 9. next-auth
18 | 10. lint-staged
19 |
20 |
21 | ## Usage
22 |
23 | 1. ```git clone https://github.com/s-kris/vite-ssr-starter```
24 | 2. Configure ```./server/auth/next.ts``` as mentioned [here](https://next-auth.js.org/configuration/options).
25 | 3. ```yarn install```
26 | 4. ```yarn dev```
27 |
28 |
29 | ## Todo
30 | 1. Add a testing framework
31 |
32 | ## Contributing
33 | Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
34 |
35 |
36 |
37 | ## License
38 | [MIT](https://choosealicense.com/licenses/mit/)
--------------------------------------------------------------------------------
/server/auth.ts:
--------------------------------------------------------------------------------
1 | import { json, urlencoded } from 'body-parser';
2 | import cookieParser from 'cookie-parser';
3 | import { Router } from 'express';
4 | import { IncomingMessage, ServerResponse } from 'http';
5 | import NextAuth, { NextAuthOptions } from 'next-auth';
6 |
7 | /**
8 | * Should match the following paths:
9 | * /api/auth/signin
10 | * /api/auth/signin/:provider
11 | * /api/auth/callback/:provider
12 | * /api/auth/signout
13 | * /api/auth/session
14 | * /api/auth/csrf
15 | * /api/auth/providers
16 | * /api/auth/_log
17 | *
18 | * See: https://next-auth.js.org/getting-started/rest-api
19 | */
20 | const authActions =
21 | /^\/api\/auth\/(session|signin\/?\w*|signout|csrf|providers|callback\/\w+|_log)$/;
22 |
23 | const router = Router();
24 |
25 | /** Compatibility layer for `next-auth` for `express` apps. */
26 | export default function NextAuthMiddleware(options: NextAuthOptions) {
27 | return router
28 | .use(urlencoded({ extended: false }))
29 | .use(json())
30 | .use(cookieParser())
31 | .all(authActions, (req: IncomingMessage, res: ServerResponse, next) => {
32 | if (req.method !== 'POST' && req.method !== 'GET') {
33 | return next();
34 | }
35 | //@ts-ignore
36 | req.query.nextauth = req.path.split('/').slice(3);
37 | //@ts-ignore
38 | NextAuth(req, res, options);
39 | });
40 | }
41 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | parser: '@typescript-eslint/parser',
4 | parserOptions: {
5 | ecmaVersion: 2020,
6 | sourceType: 'module',
7 | ecmaFeatures: {
8 | jsx: true,
9 | },
10 | },
11 | settings: {
12 | react: {
13 | version: 'detect',
14 | },
15 | },
16 | env: {
17 | browser: true,
18 | amd: true,
19 | node: true,
20 | },
21 | extends: [
22 | 'eslint:recommended',
23 | 'plugin:react/recommended',
24 | 'plugin:jsx-a11y/recommended',
25 | 'plugin:prettier/recommended', // Make sure this is always the last element in the array.
26 | ],
27 | plugins: ['simple-import-sort', 'prettier'],
28 | rules: {
29 | 'prettier/prettier': ['error', {}, { usePrettierrc: true }],
30 | 'react/react-in-jsx-scope': 'off',
31 | 'jsx-a11y/accessible-emoji': 'off',
32 | 'react/prop-types': 'off',
33 | '@typescript-eslint/explicit-function-return-type': 'off',
34 | 'simple-import-sort/imports': 'error',
35 | 'simple-import-sort/exports': 'error',
36 | 'jsx-a11y/anchor-is-valid': [
37 | 'error',
38 | {
39 | components: ['Link'],
40 | specialLink: ['hrefLeft', 'hrefRight'],
41 | aspects: ['invalidHref', 'preferButton'],
42 | },
43 | ],
44 | },
45 | };
--------------------------------------------------------------------------------
/pages/_default/_default.page.server.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOMServer from 'react-dom/server';
3 | import { html } from 'vite-plugin-ssr';
4 |
5 | import logoUrl from './logo.svg';
6 | import { PageLayout } from './PageLayout';
7 | import { PageContext } from './types';
8 |
9 | export { render };
10 | export { passToClient };
11 |
12 | // See https://github.com/brillout/vite-plugin-ssr#data-fetching
13 | const passToClient = ['pageProps'];
14 |
15 | function render(pageContext: PageContext) {
16 | const { Page, pageProps } = pageContext;
17 | const pageHtml = ReactDOMServer.renderToString(
18 | Loading...
; 50 | } 51 | 52 | if (session) { 53 | return ( 54 |