From a5fbab53a4ebe3cd9592b41bc76abec1ee66fcb9 Mon Sep 17 00:00:00 2001 From: Konstantin Solovev Date: Sat, 10 Dec 2022 23:10:32 +0400 Subject: [PATCH] add global styles and react app entry point; update README --- README.md | 37 +++++++++++++-- config/webpack.client.config.js | 24 ++++++++-- package.json | 4 +- src/App.tsx | 12 +++++ src/assets/styles/body/body.styl | 8 ++++ src/assets/styles/body/index.styl | 1 + src/assets/styles/html/html.styl | 12 +++++ src/assets/styles/html/index.styl | 1 + src/assets/styles/main.global.styl | 3 ++ src/assets/styles/root/index.styl | 1 + src/assets/styles/root/root.styl | 52 ++++++++++++++++++++++ src/client/index.tsx | 4 +- src/server/server.tsx | 4 +- src/shared/{ => Header}/Header.tsx | 2 +- src/shared/{ => Header}/header.module.styl | 0 src/shared/Header/index.ts | 1 + src/shared/Layout/Layout.tsx | 9 ++++ src/shared/Layout/index.ts | 1 + src/shared/Layout/layout.module.styl | 0 src/{ => types}/custom.d.ts | 0 20 files changed, 162 insertions(+), 14 deletions(-) create mode 100644 src/App.tsx create mode 100644 src/assets/styles/body/body.styl create mode 100644 src/assets/styles/body/index.styl create mode 100644 src/assets/styles/html/html.styl create mode 100644 src/assets/styles/html/index.styl create mode 100644 src/assets/styles/main.global.styl create mode 100644 src/assets/styles/root/index.styl create mode 100644 src/assets/styles/root/root.styl rename src/shared/{ => Header}/Header.tsx (87%) rename src/shared/{ => Header}/header.module.styl (100%) create mode 100644 src/shared/Header/index.ts create mode 100644 src/shared/Layout/Layout.tsx create mode 100644 src/shared/Layout/index.ts create mode 100644 src/shared/Layout/layout.module.styl rename src/{ => types}/custom.d.ts (100%) diff --git a/README.md b/README.md index f9a8f45..8bd8126 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # template-for-react-ts-ssr-hmr -Template for a project with React, TypeScript, SSR, HMR. Template imply using CSS Modules and Stylus. But it can be easily changed. +Template for a project with React, TypeScript, SSR, and HMR. The template implies the use of CSS Modules and Stylus. -## Quick start: +## Quick start: To copy the template in an empty local folder without creating of a repo or in an existing repo use the following: @@ -10,7 +10,7 @@ To copy the template in an empty local folder without creating of a repo or in a npx degit Kallenju/template-for-react-ts-ssr-hmr ``` -Install packages and run development servers: +Install packages and run development servers: ```shell npm install @@ -18,10 +18,39 @@ npm install npm run dev ``` +## Structure of the template + +### Structure of the source folder (`./src`) + +- **assets** + - **styles** + - **body** + - **html** + - **root** +- **client** +- **server** +- **shared** + - **Header** + - **Layout** +- **types** + +## How it works + +`./src` contains `App.tsx`, which is the entry point of the React app. It imports components from `./src/shared` and global styles from `./assets/styles/`. `App.tsx` is in turn imported be server and client files in `./src/server/` and `./src/client/`, respectively. + +The `app.get()` method specifies a callback function that will render to string React component from `App.tsx` and past it in a HTML template, whenever there is an HTTP GET request with a path ('/') relative to the site root. HTML template are in `./src/server`. + +After the `load` event is fired, the client code `hydrate` obtained React component. + ## What is used in the template? -### Hot module replacement +### Hot Module Replacement +- express server - react-refresh-webpack-plugin - React Fast Refresh - Webpack modules and plugins (webpack-dev-middleware, webpack-hot-middleware, webpack.HotModuleReplacementPlugin) + +### Server-Side Rendering + +- express server diff --git a/config/webpack.client.config.js b/config/webpack.client.config.js index 7300d7f..d56b009 100644 --- a/config/webpack.client.config.js +++ b/config/webpack.client.config.js @@ -5,7 +5,10 @@ const webpack = require('webpack'); const ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin'); const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); -const { NODE_ENV } = globalThis.process.env; +const { NODE_ENV } = process.env; +const MODULE_CODE_REGEXP = /\.[tj]sx?$/; +const MODULE_STYLES_REGEXP = /\.module\.styl$/; +const GLOBAL_STYLES_REGEXP = /\.global\.styl$/; module.exports = { entry: [ @@ -21,7 +24,7 @@ module.exports = { module: { rules: [ { - test: /\.[tj]sx?$/, + test: MODULE_CODE_REGEXP, use: [ { loader: 'babel-loader', @@ -29,7 +32,8 @@ module.exports = { ], }, { - test: /\.styl$/, + test: MODULE_STYLES_REGEXP, + exclude: GLOBAL_STYLES_REGEXP, use: [ { loader: 'style-loader', @@ -58,6 +62,20 @@ module.exports = { }, ], }, + { + test: GLOBAL_STYLES_REGEXP, + use: [ + { + loader: 'css-loader', + }, + { + loader: 'postcss-loader', + }, + { + loader: 'stylus-loader', + }, + ], + }, ], }, diff --git a/package.json b/package.json index 98b88d6..333bf57 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "template-for-react-ts-ssr-hmr", - "version": "1.0.1", - "description": "Template for a project with React, TypeScript, SSR, HMR. Template imply using CSS Modules and Stylus. But it can be easily changed.", + "version": "1.1.0", + "description": "Template for a project with React, TypeScript, SSR, HMR. The template implies the use of CSS Modules and Stylus.", "repository": { "type": "git", "url": "https://github.com/Kallenju/template-for-react-ts-ssr-hmr.git" diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..c3bb973 --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import { Layout } from './shared/Layout'; +import { Header } from './shared/Header'; +import './assets/styles/main.global.styl'; + +export default function App(): React.ReactElement { + return ( + +
+ + ); +} diff --git a/src/assets/styles/body/body.styl b/src/assets/styles/body/body.styl new file mode 100644 index 0000000..0463a14 --- /dev/null +++ b/src/assets/styles/body/body.styl @@ -0,0 +1,8 @@ +body + margin 0 + min-width 320px + font-family --font-family-primary, sans-serif + font-size --font-size_sm + font-weight --font-weight_xs + line-height --line-height_xs + background-color --color-white diff --git a/src/assets/styles/body/index.styl b/src/assets/styles/body/index.styl new file mode 100644 index 0000000..b995e1c --- /dev/null +++ b/src/assets/styles/body/index.styl @@ -0,0 +1 @@ +@import 'body' diff --git a/src/assets/styles/html/html.styl b/src/assets/styles/html/html.styl new file mode 100644 index 0000000..b7dba77 --- /dev/null +++ b/src/assets/styles/html/html.styl @@ -0,0 +1,12 @@ +html + box-sizing border-box + font-size 0.625em + +* + box-sizing inherit + + &::before + box-sizing inherit + + &::after + box-sizing inherit diff --git a/src/assets/styles/html/index.styl b/src/assets/styles/html/index.styl new file mode 100644 index 0000000..6bc98a6 --- /dev/null +++ b/src/assets/styles/html/index.styl @@ -0,0 +1 @@ +@import 'html' diff --git a/src/assets/styles/main.global.styl b/src/assets/styles/main.global.styl new file mode 100644 index 0000000..caab3c6 --- /dev/null +++ b/src/assets/styles/main.global.styl @@ -0,0 +1,3 @@ +@import './root' +@import './html' +@import './body' diff --git a/src/assets/styles/root/index.styl b/src/assets/styles/root/index.styl new file mode 100644 index 0000000..0c40890 --- /dev/null +++ b/src/assets/styles/root/index.styl @@ -0,0 +1 @@ +@import 'root'; diff --git a/src/assets/styles/root/root.styl b/src/assets/styles/root/root.styl new file mode 100644 index 0000000..eb22800 --- /dev/null +++ b/src/assets/styles/root/root.styl @@ -0,0 +1,52 @@ +--container-width = 1400px +--container-margins = 55px +--container-margins_md = 31px +--container-margins_sm = 27px +--container-margins_xs = 21px +--font-family-primary = 'Roboto' +--font-family-secondary = 'ttfirsneue' +--font-size_xxs = 1.20rem +--font-size_xs = 1.40rem +--font-size_sm = 1.60rem +--font-size_md = 1.80rem +--font-size_lg = 2.00rem +--font-size_xl = 2.40rem +--font-size_xxl = 3.40rem +--line-height_xs = 1.04 +--line-height_sm = 1.17 +--line-height_md = 1.29 +--line-height_lg = 1.38 +--line-height_xl = 1.75 +--font-weight_xs = 400 +--font-weight_sm = 500 +--font-weight_md = 600 +--font-weight_lg = 700 +--font-weight_xl = 800 +--warning-color-primary = #ff3030 +--success-color-primary = #7cbc4a +--brend-color = #ff6e30 +--background-color-primary = #ff5c00 +--background-color-secondary = #202020 +--color-focus-primary = #ff6e30 +--color-hover-primary = #bc572b +--color-active-primary = #ce4307 +--border-color-primary = #ff6e30 +--border-color-secondary = #ce4307 +--text-color-primary = #fff +--text-color-secondary = #202020 +--form-text-color-primary = #202020 +--color-dark-grey = #202020 +--color-middle-grey = #999 +--color-light-grey = #e9e9e9 +--color-white = #fff +--color-black = #000 +--transition-time_slow = 0.210s +--transition-time_fast = 0.100s + +--breakpoint_xs = 40em +--breakpoint_sm = 56em +--breakpoint_md = 66em +--breakpoint_lg = 82em +--grid-columns = 12 +--grid-gap = 3.00rem +--link_css-effects = 'plain' diff --git a/src/client/index.tsx b/src/client/index.tsx index 7006d2f..8077a07 100644 --- a/src/client/index.tsx +++ b/src/client/index.tsx @@ -1,11 +1,11 @@ import React from 'react'; import ReactDom from 'react-dom/client'; -import Header from '../shared/Header'; +import App from '../App'; window.addEventListener('load', () => { const container: Element | null = document.querySelector('#react_root'); if (container) { - ReactDom.hydrateRoot(container,
); + ReactDom.hydrateRoot(container, ); } }); diff --git a/src/server/server.tsx b/src/server/server.tsx index 37e23fe..78ef8f7 100644 --- a/src/server/server.tsx +++ b/src/server/server.tsx @@ -1,7 +1,7 @@ import express from 'express'; import React from 'react'; import ReactDOMServer from 'react-dom/server'; -import Header from '../shared/Header'; +import App from '../App'; import indexTemplate from './indexTemplate'; const app = express(); @@ -9,7 +9,7 @@ const app = express(); app.use('/static', express.static('./dist/client')); app.get('/', (req, res) => { - res.send(indexTemplate(ReactDOMServer.renderToString(
))); + res.send(indexTemplate(ReactDOMServer.renderToString())); }); app.listen(3000); diff --git a/src/shared/Header.tsx b/src/shared/Header/Header.tsx similarity index 87% rename from src/shared/Header.tsx rename to src/shared/Header/Header.tsx index d32ded6..7d88aa5 100644 --- a/src/shared/Header.tsx +++ b/src/shared/Header/Header.tsx @@ -1,7 +1,7 @@ import React, { useState } from 'react'; import styles from './header.module.styl'; -export default function Header(): React.ReactElement { +export function Header(): React.ReactElement { const [count, setCount] = useState(0); function handleClick() { setCount(count + 1); diff --git a/src/shared/header.module.styl b/src/shared/Header/header.module.styl similarity index 100% rename from src/shared/header.module.styl rename to src/shared/Header/header.module.styl diff --git a/src/shared/Header/index.ts b/src/shared/Header/index.ts new file mode 100644 index 0000000..266dec8 --- /dev/null +++ b/src/shared/Header/index.ts @@ -0,0 +1 @@ +export * from './Header'; diff --git a/src/shared/Layout/Layout.tsx b/src/shared/Layout/Layout.tsx new file mode 100644 index 0000000..c409999 --- /dev/null +++ b/src/shared/Layout/Layout.tsx @@ -0,0 +1,9 @@ +import React from 'react'; + +interface ILayoutProps { + children?: React.ReactNode; +} + +export function Layout({ children }: ILayoutProps): React.ReactElement { + return
{children}
; +} diff --git a/src/shared/Layout/index.ts b/src/shared/Layout/index.ts new file mode 100644 index 0000000..9877e7f --- /dev/null +++ b/src/shared/Layout/index.ts @@ -0,0 +1 @@ +export * from './Layout'; diff --git a/src/shared/Layout/layout.module.styl b/src/shared/Layout/layout.module.styl new file mode 100644 index 0000000..e69de29 diff --git a/src/custom.d.ts b/src/types/custom.d.ts similarity index 100% rename from src/custom.d.ts rename to src/types/custom.d.ts