mirror of
https://github.com/Mastermindzh/react-starter-kit.git
synced 2025-01-20 18:41:41 +01:00
Added the possibility to override partial configs during deployments
Added default output to jest (for terminal output...) Upgraded npm packages. Left jest on 27 because of breaking changes in 28
This commit is contained in:
parent
3324b299fd
commit
5829588665
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -2,11 +2,13 @@
|
|||||||
"cSpell.words": [
|
"cSpell.words": [
|
||||||
"browserslist",
|
"browserslist",
|
||||||
"camelcase",
|
"camelcase",
|
||||||
|
"deepmerge",
|
||||||
"flexbugs",
|
"flexbugs",
|
||||||
"Immer",
|
"Immer",
|
||||||
"languagedetector",
|
"languagedetector",
|
||||||
"luxon",
|
"luxon",
|
||||||
"pmmmwh",
|
"pmmmwh",
|
||||||
|
"preinstall",
|
||||||
"reduxjs",
|
"reduxjs",
|
||||||
"SVGR",
|
"SVGR",
|
||||||
"tailwindcss",
|
"tailwindcss",
|
||||||
|
@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [0.4.0] - 2022-07-25
|
||||||
|
|
||||||
|
- Added the possibility to override partial configs during deployments
|
||||||
|
- Added default output to jest (for terminal output...)
|
||||||
|
- Upgraded npm packages. Left jest on 27 because of breaking changes in 28
|
||||||
|
|
||||||
## [0.3.2] - 2022-07-19
|
## [0.3.2] - 2022-07-19
|
||||||
|
|
||||||
- e2e step now starts a server before running tests
|
- e2e step now starts a server before running tests
|
||||||
|
46
README.md
46
README.md
@ -17,6 +17,9 @@ Includes:
|
|||||||
|
|
||||||
- [Getting started](#getting-started)
|
- [Getting started](#getting-started)
|
||||||
- [Project structure](#project-structure)
|
- [Project structure](#project-structure)
|
||||||
|
- [Configuration](#configuration)
|
||||||
|
- [Using the `config.ts` file](#using-the-configts-file)
|
||||||
|
- [adding values](#adding-values)
|
||||||
|
|
||||||
<!-- tocstop -->
|
<!-- tocstop -->
|
||||||
|
|
||||||
@ -36,7 +39,11 @@ Only the important files are shown
|
|||||||
├── config # tool configuration
|
├── config # tool configuration
|
||||||
├── cypress # e2e tests
|
├── cypress # e2e tests
|
||||||
├── dist # production version
|
├── dist # production version
|
||||||
├── public # directory with public files (config, icons, etc)
|
├── public
|
||||||
|
├── public # directory with public files (config, icons, etc), will be copied to dist
|
||||||
|
│ ├── i18n # directory to house i18n language files
|
||||||
|
│ ├── config.js # default runtime application config
|
||||||
|
│ └── configOverride.js # default config overrides.
|
||||||
├── scripts # Modified default create-react-app scripts
|
├── scripts # Modified default create-react-app scripts
|
||||||
├── src # application source
|
├── src # application source
|
||||||
│ ├── app # redux-toolkit hooks + store
|
│ ├── app # redux-toolkit hooks + store
|
||||||
@ -48,3 +55,40 @@ Only the important files are shown
|
|||||||
├── README.md # keep this up to date
|
├── README.md # keep this up to date
|
||||||
└── tsconfig.json
|
└── tsconfig.json
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
This starter kit comes with runtime configuration out-of-the-box.
|
||||||
|
It achieves this with 2 config files in the public directory: `config.js` and `configOverrides.js`.
|
||||||
|
`config.js` is meant to be filled with a default for all of your application's runtime configurations.
|
||||||
|
`configOverrides.js` is meant to be replaced during deployment with environment specific runtime overrides.
|
||||||
|
|
||||||
|
### Using the `config.ts` file
|
||||||
|
|
||||||
|
To use the config you import `Config` from `config.ts` and use the typed object:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { Config } from "../config";
|
||||||
|
|
||||||
|
import { FunctionComponent } from "react";
|
||||||
|
|
||||||
|
export const Navbar: FunctionComponent<{}> = () => {
|
||||||
|
return <h1>{JSON.stringify(Config)}</h1>;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### adding values
|
||||||
|
|
||||||
|
To add a value to the runtime config you have to take 2 steps:
|
||||||
|
|
||||||
|
1. Add a type to the `RuntimeConfig` type in [src/infrastructure/config/RunTimeConfig.ts](./src/infrastructure/config/RunTimeConfig.ts)
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
type RunTimeConfig = {
|
||||||
|
version: number;
|
||||||
|
name: string;
|
||||||
|
myNewKey: string;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Add a key (if required) to [public/config.js]
|
||||||
|
@ -4,6 +4,7 @@ const config = {
|
|||||||
roots: ["<rootDir>/src"],
|
roots: ["<rootDir>/src"],
|
||||||
collectCoverageFrom: ["src/**/*.{js,jsx,ts,tsx}", "!src/**/*.d.ts"],
|
collectCoverageFrom: ["src/**/*.{js,jsx,ts,tsx}", "!src/**/*.d.ts"],
|
||||||
reporters: [
|
reporters: [
|
||||||
|
"default",
|
||||||
[
|
[
|
||||||
"jest-junit",
|
"jest-junit",
|
||||||
{
|
{
|
||||||
|
2749
package-lock.json
generated
2749
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
20
package.json
20
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-starter-kit",
|
"name": "react-starter-kit",
|
||||||
"version": "0.2.0",
|
"version": "0.4.0",
|
||||||
"description": "A modern, create-react-app-based, starter kit for React projects",
|
"description": "A modern, create-react-app-based, starter kit for React projects",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react",
|
"react",
|
||||||
@ -35,7 +35,7 @@
|
|||||||
"organize-package-json": "npx format-package -w && npx sort-package-json",
|
"organize-package-json": "npx format-package -w && npx sort-package-json",
|
||||||
"pretty-quick": "pretty-quick --staged",
|
"pretty-quick": "pretty-quick --staged",
|
||||||
"start": "node scripts/start.js",
|
"start": "node scripts/start.js",
|
||||||
"test": "node scripts/test.js",
|
"test": "node scripts/test.js --verbose",
|
||||||
"test-ci": "node scripts/test.js --ci --coverage",
|
"test-ci": "node scripts/test.js --ci --coverage",
|
||||||
"test-live-coverage": " concurrently --kill-others \"npm run test-with-coverage\" \"npx http-server -c-1 coverage/lcov-report\"",
|
"test-live-coverage": " concurrently --kill-others \"npm run test-with-coverage\" \"npx http-server -c-1 coverage/lcov-report\"",
|
||||||
"test-with-coverage": "node scripts/test.js --coverage",
|
"test-with-coverage": "node scripts/test.js --coverage",
|
||||||
@ -46,6 +46,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@reduxjs/toolkit": "^1.8.3",
|
"@reduxjs/toolkit": "^1.8.3",
|
||||||
|
"deepmerge": "^4.2.2",
|
||||||
"i18next-http-backend": "^1.4.1",
|
"i18next-http-backend": "^1.4.1",
|
||||||
"luxon": "^2.4.0",
|
"luxon": "^2.4.0",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
@ -57,16 +58,16 @@
|
|||||||
"tailwindcss": "^3.1.6"
|
"tailwindcss": "^3.1.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.18.6",
|
"@babel/core": "^7.18.9",
|
||||||
"@mastermindzh/prettier-config": "^1.0.0",
|
"@mastermindzh/prettier-config": "^1.0.0",
|
||||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.7",
|
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.7",
|
||||||
"@svgr/webpack": "^5.5.0",
|
"@svgr/webpack": "^5.5.0",
|
||||||
"@testing-library/jest-dom": "^5.16.4",
|
"@testing-library/jest-dom": "^5.16.4",
|
||||||
"@testing-library/react": "^13.3.0",
|
"@testing-library/react": "^13.3.0",
|
||||||
"@testing-library/user-event": "^14.2.5",
|
"@testing-library/user-event": "^14.3.0",
|
||||||
"@types/jest": "^28.1.6",
|
"@types/jest": "^28.1.6",
|
||||||
"@types/luxon": "^2.3.2",
|
"@types/luxon": "^3.0.0",
|
||||||
"@types/node": "^18.0.6",
|
"@types/node": "^18.6.1",
|
||||||
"@types/react": "^18.0.15",
|
"@types/react": "^18.0.15",
|
||||||
"@types/react-dom": "^18.0.6",
|
"@types/react-dom": "^18.0.6",
|
||||||
"babel-jest": "^27.4.2",
|
"babel-jest": "^27.4.2",
|
||||||
@ -77,13 +78,13 @@
|
|||||||
"browserslist": "^4.21.2",
|
"browserslist": "^4.21.2",
|
||||||
"camelcase": "^6.2.1",
|
"camelcase": "^6.2.1",
|
||||||
"case-sensitive-paths-webpack-plugin": "^2.4.0",
|
"case-sensitive-paths-webpack-plugin": "^2.4.0",
|
||||||
"concurrently": "^7.2.2",
|
"concurrently": "^7.3.0",
|
||||||
"css-loader": "^6.7.1",
|
"css-loader": "^6.7.1",
|
||||||
"css-minimizer-webpack-plugin": "^3.2.0",
|
"css-minimizer-webpack-plugin": "^3.2.0",
|
||||||
"cypress": "^10.3.0",
|
"cypress": "^10.3.1",
|
||||||
"dotenv": "^10.0.0",
|
"dotenv": "^10.0.0",
|
||||||
"dotenv-expand": "^5.1.0",
|
"dotenv-expand": "^5.1.0",
|
||||||
"eslint": "^8.3.0",
|
"eslint": "^8.20.0",
|
||||||
"eslint-config-prettier": "^8.5.0",
|
"eslint-config-prettier": "^8.5.0",
|
||||||
"eslint-config-react-app": "^7.0.1",
|
"eslint-config-react-app": "^7.0.1",
|
||||||
"eslint-plugin-cypress": "^2.12.1",
|
"eslint-plugin-cypress": "^2.12.1",
|
||||||
@ -100,6 +101,7 @@
|
|||||||
"identity-obj-proxy": "^3.0.0",
|
"identity-obj-proxy": "^3.0.0",
|
||||||
"immer": "^9.0.15",
|
"immer": "^9.0.15",
|
||||||
"jest": "^27.4.3",
|
"jest": "^27.4.3",
|
||||||
|
"jest-environment-jsdom": "^27.4.3",
|
||||||
"jest-junit": "^14.0.0",
|
"jest-junit": "^14.0.0",
|
||||||
"jest-resolve": "^27.4.2",
|
"jest-resolve": "^27.4.2",
|
||||||
"jest-watch-typeahead": "^1.0.0",
|
"jest-watch-typeahead": "^1.0.0",
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
const config = {
|
const defaultConfig = {
|
||||||
version: "0.1.0",
|
version: "0.1.0",
|
||||||
|
name: "React-starter-kit",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ignore this :)
|
||||||
try {
|
try {
|
||||||
window.config = config;
|
window.defaultConfig = defaultConfig;
|
||||||
if (module) {
|
if (module) {
|
||||||
module.exports = config;
|
module.exports = defaultConfig;
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// ignore
|
// ignore
|
||||||
|
17
public/configOverride.js
Normal file
17
public/configOverride.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/**
|
||||||
|
* This is the config override file.
|
||||||
|
* This file is meant to be replaced during deployment with override values compared to the regular config.js
|
||||||
|
* For development purposes this file can be completely empty
|
||||||
|
*/
|
||||||
|
|
||||||
|
const configOverride = {};
|
||||||
|
|
||||||
|
// ignore this :)
|
||||||
|
try {
|
||||||
|
window.configOverride = configOverride;
|
||||||
|
if (module) {
|
||||||
|
module.exports = configOverride;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
@ -4,7 +4,7 @@
|
|||||||
},
|
},
|
||||||
"navBar": {
|
"navBar": {
|
||||||
"intro": "Our fancy header with navigation.",
|
"intro": "Our fancy header with navigation.",
|
||||||
"version": "App version:",
|
"version": "version:",
|
||||||
"currentDate": "Today's date: {{date, formattedDate}}"
|
"currentDate": "Today's date: {{date, formattedDate}}"
|
||||||
},
|
},
|
||||||
"nav": {
|
"nav": {
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
},
|
},
|
||||||
"navBar": {
|
"navBar": {
|
||||||
"intro": "Een fancy header met navigatie",
|
"intro": "Een fancy header met navigatie",
|
||||||
"version": "Aplicatie versie:",
|
"version": "versie:",
|
||||||
"currentDate": "De datum van vandaag: {{date, formattedDate}}"
|
"currentDate": "De datum van vandaag: {{date, formattedDate}}"
|
||||||
},
|
},
|
||||||
"nav": {
|
"nav": {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
|
||||||
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="icon" href="%PUBLIC_URL%/icon/favicon.ico" />
|
<link rel="icon" href="%PUBLIC_URL%/icon/favicon.ico" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
@ -10,9 +11,12 @@
|
|||||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||||
<title>React Base App</title>
|
<title>React Base App</title>
|
||||||
<script src="%PUBLIC_URL%/config.js"></script>
|
<script src="%PUBLIC_URL%/config.js"></script>
|
||||||
</head>
|
<script src="%PUBLIC_URL%/configOverride.js"></script>
|
||||||
<body>
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
4
src/config/RunTimeConfig.ts
Normal file
4
src/config/RunTimeConfig.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export interface RunTimeConfig {
|
||||||
|
version: number;
|
||||||
|
name: string;
|
||||||
|
}
|
15
src/config/config.ts
Normal file
15
src/config/config.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import deepmerge from "deepmerge";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gets and merges both the regular config and the override config from the window
|
||||||
|
* into window.mergedConfig
|
||||||
|
*/
|
||||||
|
export const mergeConfigs = () => {
|
||||||
|
if (!window.mergedConfig) {
|
||||||
|
window.mergedConfig = deepmerge(window.defaultConfig, window.configOverride ?? {});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
mergeConfigs();
|
||||||
|
|
||||||
|
export const Config = window.mergedConfig;
|
1
src/config/index.ts
Normal file
1
src/config/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from "./config";
|
@ -1,5 +0,0 @@
|
|||||||
type RunTimeConfig = {
|
|
||||||
version: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Config = (window as any).config as RunTimeConfig;
|
|
@ -2,7 +2,7 @@ import { DateTime } from "luxon";
|
|||||||
import { FunctionComponent } from "react";
|
import { FunctionComponent } from "react";
|
||||||
import { Trans, useTranslation } from "react-i18next";
|
import { Trans, useTranslation } from "react-i18next";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { Config } from "../config";
|
import { Config } from "../../config";
|
||||||
import "./Navbar.css";
|
import "./Navbar.css";
|
||||||
type Props = {};
|
type Props = {};
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ export const Navbar: FunctionComponent<Props> = () => {
|
|||||||
<h1>{translate("navBar.intro")}</h1>
|
<h1>{translate("navBar.intro")}</h1>
|
||||||
<p>
|
<p>
|
||||||
{/* trans can also be used to translate */}
|
{/* trans can also be used to translate */}
|
||||||
<Trans i18nKey="navBar.version">App version:</Trans>
|
{Config.name} <Trans i18nKey="navBar.version">version:</Trans>
|
||||||
{JSON.stringify(Config.version)}
|
{JSON.stringify(Config.version)}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
32
src/react-app-env.d.ts
vendored
32
src/react-app-env.d.ts
vendored
@ -4,68 +4,68 @@
|
|||||||
|
|
||||||
declare namespace NodeJS {
|
declare namespace NodeJS {
|
||||||
interface ProcessEnv {
|
interface ProcessEnv {
|
||||||
readonly NODE_ENV: 'development' | 'production' | 'test';
|
readonly NODE_ENV: "development" | "production" | "test";
|
||||||
readonly PUBLIC_URL: string;
|
readonly PUBLIC_URL: string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '*.avif' {
|
declare module "*.avif" {
|
||||||
const src: string;
|
const src: string;
|
||||||
export default src;
|
export default src;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '*.bmp' {
|
declare module "*.bmp" {
|
||||||
const src: string;
|
const src: string;
|
||||||
export default src;
|
export default src;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '*.gif' {
|
declare module "*.gif" {
|
||||||
const src: string;
|
const src: string;
|
||||||
export default src;
|
export default src;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '*.jpg' {
|
declare module "*.jpg" {
|
||||||
const src: string;
|
const src: string;
|
||||||
export default src;
|
export default src;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '*.jpeg' {
|
declare module "*.jpeg" {
|
||||||
const src: string;
|
const src: string;
|
||||||
export default src;
|
export default src;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '*.png' {
|
declare module "*.png" {
|
||||||
const src: string;
|
const src: string;
|
||||||
export default src;
|
export default src;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '*.webp' {
|
declare module "*.webp" {
|
||||||
const src: string;
|
const src: string;
|
||||||
export default src;
|
export default src;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '*.svg' {
|
declare module "*.svg" {
|
||||||
import * as React from 'react';
|
import * as React from "react";
|
||||||
|
|
||||||
export const ReactComponent: React.FunctionComponent<React.SVGProps<
|
export const ReactComponent: React.FunctionComponent<
|
||||||
SVGSVGElement
|
React.SVGProps<SVGSVGElement> & { title?: string }
|
||||||
> & { title?: string }>;
|
>;
|
||||||
|
|
||||||
const src: string;
|
const src: string;
|
||||||
export default src;
|
export default src;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '*.module.css' {
|
declare module "*.module.css" {
|
||||||
const classes: { readonly [key: string]: string };
|
const classes: { readonly [key: string]: string };
|
||||||
export default classes;
|
export default classes;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '*.module.scss' {
|
declare module "*.module.scss" {
|
||||||
const classes: { readonly [key: string]: string };
|
const classes: { readonly [key: string]: string };
|
||||||
export default classes;
|
export default classes;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '*.module.sass' {
|
declare module "*.module.sass" {
|
||||||
const classes: { readonly [key: string]: string };
|
const classes: { readonly [key: string]: string };
|
||||||
export default classes;
|
export default classes;
|
||||||
}
|
}
|
||||||
|
@ -4,4 +4,5 @@
|
|||||||
// learn more: https://github.com/testing-library/jest-dom
|
// learn more: https://github.com/testing-library/jest-dom
|
||||||
import "@testing-library/jest-dom/extend-expect";
|
import "@testing-library/jest-dom/extend-expect";
|
||||||
|
|
||||||
(window as any).config = require("./../public/config");
|
window.defaultConfig = require("./../public/config");
|
||||||
|
window.configOverride = require("./../public/configOverride");
|
||||||
|
11
src/types/globals.d.ts
vendored
Normal file
11
src/types/globals.d.ts
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { RunTimeConfig } from "./../config/RunTimeConfig";
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
mergedConfig: RunTimeConfig;
|
||||||
|
defaultConfig: RunTimeConfig;
|
||||||
|
configOverride: Partial<RunTimeConfig>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {};
|
Loading…
Reference in New Issue
Block a user