@pplancq/react-template 1.0.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.eslintrc.js CHANGED
@@ -1 +1 @@
1
- module.exports = { extends: ['@pplancq/eslint-config/react', '@pplancq/eslint-config/vitest'] };
1
+ module.exports = { extends: ['@pplancq/eslint-config/react', '@pplancq/eslint-config/vitest', '@pplancq/eslint-config/prettier'] };
package/.lintstagedrc.js CHANGED
@@ -2,4 +2,5 @@ module.exports = {
2
2
  '*.{js,jsx,ts,tsx}': 'eslint --fix',
3
3
  '*.{ts,tsx}': 'tsc-files --noEmit',
4
4
  '*.{scss,css}': 'stylelint --fix',
5
+ '(package|package-lock).json': 'npm run package:check',
5
6
  };
package/.stylelintrc.js CHANGED
@@ -1 +1 @@
1
- module.exports = { extends: ['@pplancq/stylelint-config'] };
1
+ module.exports = { extends: ['@pplancq/stylelint-config/prettier'] };
package/CHANGELOG.md CHANGED
@@ -1,3 +1,45 @@
1
+ ## @pplancq/react-template [1.1.1](https://github.com/pplancq/dev-tools/compare/@pplancq/react-template@1.1.0...@pplancq/react-template@1.1.1) (2024-03-14)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **react-template:** fix webpack-dev-server@4 peerDependencies of webpack-config ([24e6db9](https://github.com/pplancq/dev-tools/commit/24e6db9e81dbaf6e874614edee0190a7bf129a6a))
7
+ * **react-template:** fix yarn add on script migrate to vite ([739ee45](https://github.com/pplancq/dev-tools/commit/739ee45f2867d7db1140e03ede235667f5704260))
8
+ * **react-template:** update interpackage dependencies to '*' ([23d766a](https://github.com/pplancq/dev-tools/commit/23d766aa12968d36cbd989c65d92744d926298e6))
9
+
10
+ ## @pplancq/react-template [1.1.0](https://github.com/pplancq/dev-tools/compare/@pplancq/react-template@1.0.0...@pplancq/react-template@1.1.0) (2024-03-12)
11
+
12
+
13
+ ### Features
14
+
15
+ * **react-template:** add fetchApi example ([c2318c3](https://github.com/pplancq/dev-tools/commit/c2318c36097b9d4e3d1c33a15045dafd1a45c8d5))
16
+ * **webpack-config:** add note about the inclusion of environment variable ([e6e4e31](https://github.com/pplancq/dev-tools/commit/e6e4e310aa1a631a4e6013939c52a025f548b31d))
17
+ * **react-template:** add peerDependencies of commitLint and webpack config ([d501781](https://github.com/pplancq/dev-tools/commit/d501781810aae970db0553fd14935e549a0385fc))
18
+ * **react-template:** add script for migrate to vite ([d5d3337](https://github.com/pplancq/dev-tools/commit/d5d333786677f14b846298eba0739c9f55872949))
19
+ * **react-template:** add script for remove Demo ([355d887](https://github.com/pplancq/dev-tools/commit/355d887afdbe09a4b63073ebed6718846eaf717b))
20
+ * **react-template:** add support for yarn and pnpm to script migrate to vite ([b4b9d6b](https://github.com/pplancq/dev-tools/commit/b4b9d6ba9b95f3810b2cfcb03a861a02caf8af8a))
21
+ * **create-react-app:** add support for yarn and pnpm ([eafc39d](https://github.com/pplancq/dev-tools/commit/eafc39d972b178ca21ed307166a9ba394161803f))
22
+ * **react-template:** add test report on .gitignore ([072a240](https://github.com/pplancq/dev-tools/commit/072a2405ed421d22b9ba1b9b11f524a9aa7d0889))
23
+ * **react-template:** rename Error page to UnexpectedError ([c6eea7b](https://github.com/pplancq/dev-tools/commit/c6eea7b1d3e7dd6589945949d03c25485d22fc6c))
24
+ * **react-template:** update eslint un stylelint config ([82a4df3](https://github.com/pplancq/dev-tools/commit/82a4df3e8a3ce1932f915f11ca3495aa43d2aca5))
25
+ * **react-template:** update react-query@3 to @tanstack/react-query@5 ([f79e642](https://github.com/pplancq/dev-tools/commit/f79e6425668bd22b2e278e85a68fc1c214ed8586))
26
+ * **react-template:** update readme ([3aa2543](https://github.com/pplancq/dev-tools/commit/3aa2543948a697f6604f4984884184d3f285d297))
27
+
28
+
29
+ ### Bug Fixes
30
+
31
+ * **react-template:** ambiguous Spacing before <span> ([56c9a8e](https://github.com/pplancq/dev-tools/commit/56c9a8e558a8e0c7e62faba4bf7db85278eb7f80))
32
+ * **react-template:** fix peerDependencies of commitlint-config ([fe0dd7c](https://github.com/pplancq/dev-tools/commit/fe0dd7ca706e4287b36e2ed861a509a8dc7742e2))
33
+
34
+
35
+
36
+ ### Dependencies
37
+
38
+ * **@pplancq/commitlint-config:** upgraded to 2.0.0
39
+ * **@pplancq/eslint-config:** upgraded to 2.0.0
40
+ * **@pplancq/stylelint-config:** upgraded to 2.0.0
41
+ * **@pplancq/webpack-config:** upgraded to 1.1.0
42
+
1
43
  ## @pplancq/react-template 1.0.0 (2024-02-05)
2
44
 
3
45
 
package/README.md CHANGED
@@ -1,221 +1,17 @@
1
- ## 🚀 <span id="getting-started">Getting Started</span>
1
+ # @pplancq/react-template
2
2
 
3
- This project was bootstrapped with [@pplancq/create-react-app](https://github.com/pplancq/dev-tools/tree/main/packages/create-react-app).
3
+ This package is a ready-to-use template for starting up a new React application. It has been designed for easy use via the `@pplancq/create-react-app` script.
4
4
 
5
- ### 🧾 Prerequisites
5
+ ## Usage
6
6
 
7
- - Node.js : [Download here](https://nodejs.org/) (Preferably, use [Volta](https://volta.sh/))
8
- - npm (Node Package Manager)
7
+ To create a new React project, use the following command:
9
8
 
10
- ### 🛠️ Installation
11
-
12
- 1. Clone this repository to your computer.
13
-
14
- ```bash
15
- git clone https://github.com/votre-utilisateur/mon-projet-awesome.git mon-projet
16
- cd mon-projet
17
- ```
18
-
19
- 2. Install dependencies.
20
-
21
- ```bash
22
- npm install
23
- ```
24
-
25
-
26
- In the project directory, you can run the following commands:
27
-
28
- ### `npm start`
29
-
30
- Launches the application in development mode.
31
- Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
32
-
33
- The page will reload automatically if you make edits.
34
-
35
- You will also see lint errors in the console.
36
-
37
- ### `npm test`
38
-
39
- Launches the test runner in interactive mode.
40
-
41
- ### `npm run build`
42
-
43
- Builds the application for production in the `build` folder.
44
-
45
- It correctly bundles React in production mode and optimizes the build for better performance.
46
-
47
- The build is minified, and the filenames include hashes.
48
- Your application is ready to be deployed!
49
-
50
- ### `npm run lint`
51
-
52
- Allows you to see lint errors without fixing them. This command initiates the linting process with three linters: **eslint**, **stylelint**, and **tsc** (TypeScript Compiler).
53
-
54
- ### `npm run eslint:fix`
55
-
56
- Allows you to fix eslint errors.
57
-
58
- ### `npm run stylelint:fix`
59
-
60
- Allows you to fix style lint errors.
61
-
62
- ## 🏗 <span id="project-structure">Project Structure</span>
63
-
64
- ```
65
- 📁 my-projet
66
- ├── 📁 src
67
- │ ├── 📁 ui
68
- │ │ ├── 📁 Atoms
69
- │ │ ├── 📁 Molecules
70
- │ │ ├── 📁 Organisms
71
- │ │ ├── 📁 Templates
72
- │ ├── 📁 components
73
- │ │ ├── 📁 formFields
74
- │ ├── 📁 providers
75
- │ ├── 📁 pages
76
- │ │ ├── 📁 homePage
77
- │ │ ├── 📁 page1
78
- │ │ │ ├── 📁 sousPage1
79
- │ ├── 📁 forms
80
- │ │ ├── 📁 hooks
81
- │ │ ├── 📁 risk
82
- │ │ ├── 📁 contact
83
- │ ├── 📁 hooks
84
- │ │ ├── 📁 api
85
- │ │ ├── 📁 useCustom1
86
- │ │ ├── 📁 useCustom2
87
- │ ├── 📁 utils
88
- │ │ ├── 📁 services
89
- │ │ ├── 📁 tests
90
- │ │ ├── 📁 helpers
91
- │ ├── 📁 routing
92
- │ ├── 📁 api
93
- │ ├── 📁 types
94
- │ ├── 📁 assets
95
- │ ├── 📁 config
96
- ```
97
-
98
- ### 📚 Folder Definitions
99
-
100
- Here is the project folder structure, with a brief description of each folder:
101
-
102
- | Folder | Description|
103
- | -------- | -------- |
104
- | **📁 src** | ***The root directory of the application source code.***
105
- | [**📁 ui**](./src/ui/README.md) | Contains reusable components designed to be used across projects. Components can be basic (Atoms), more complex (Molecules), higher-level components (Organisms), or page templates (Templates). |
106
- | [**📁&#160;components**](./src/components/README.md) | Contains project-specific reusable components, for example, form components using React Hook Form. |
107
- | [**📁 providers**](./src/providers/README.md) | This folder contains context providers or custom hooks that provide data to the entire application. |
108
- | [**📁 pages**](./src/pages/README.md) | Contains the pages of the application. Each subfolder represents a distinct page or view of the application. |
109
- | [**📁 forms**](./src/forms/README.md) | Contains the forms of the application, grouping hooks related to forms. |
110
- | [**📁 hooks**](./src/hooks/README.md) | Includes custom hooks for various application features, such as API calls with React Query. |
111
- | [**📁 utils**](./src/utils/README.md) | Contains utilities and services such as test files, utility functions, etc. |
112
- | [**📁 routing**](./src/routing/README.md) | This folder is intended for native API calls using the `fetch`. function. These calls are essential for fetching real-time data from external sources, such as remote servers or web services. |
113
- | [**📁 types**](./src/types/README.md) | Provides TypeScript type definitions to enhance the robustness of your code. |
114
- | [**📁 assets**](./src/assets/README.md) | Contains static files such as images, fonts, etc., used in the application. |
115
- | [**📁 config**](./src/config/README.md) | Contains all the important configurations and utilities needed for our project. |
116
-
117
- ## 🏗 <span id="component-structure">React Component Structure</span>
118
-
119
- ```
120
- 📁 ComponentName
121
- ├── 📁 __tests__
122
- │ ├── 📄 ComponentName.feature
123
- │ ├── 📄 ComponantName.steps.tsx
124
- │ ├── 📄 ComponentName.test.tsx
125
- ├── 📄 index.ts
126
- ├── 📄 ComponentName.tsx
127
- ├── 📄 ComponentName.hook.ts
128
- ├── 📄 ComponentName.module.scss
129
- ```
130
-
131
- ### 📚 Files Definitions
132
-
133
- #### 📁 **tests**
134
-
135
- The tests folder may contain unit tests specific to the package. The idea is to mainly test through functional tests. However, in some cases, it may be useful to test a component in isolation (for example, when developing a package reused between multiple projects).
136
-
137
- #### 📄 index.ts
138
-
139
- This file allows exposing the component and avoids having to redo imports if the file implementing the component changes its name.
140
-
141
- ```typescript
142
- export { ComponentName } from './ComponentName';
143
- ```
144
-
145
- This will allow importing a component like this:
146
-
147
- ```typescript
148
- import { ComponentName } from '@Front/ComponentName';
149
- ```
150
-
151
- #### 📄 ComponentName.tsx
152
-
153
- Each file contains a single exported component. It will essentially contain the view and very little logic. If the component needs more logic, it is advisable to use a custom hook.
154
-
155
- ```typescript
156
- type ComponentNameProps = {
157
- foo: string;
158
- }
159
-
160
- export const ComponentName = ({ foo }) => {
161
- return (
162
- <div>{foo}</div>
163
- );
164
- };
165
- ```
166
-
167
- #### 📄 ComponentName.hook.ts
168
-
169
- A custom hook allows moving the logic specific to a component outside of its view.
170
-
171
- ```typescript
172
- export type UseComponentNameProps = {
173
- foo: string;
174
- };
175
-
176
- export type UseComponentNameReturn = {
177
- bar: string;
178
- };
179
-
180
- export const useComponentName = ({ foo }: UseComponentNameProps): UseComponentNameReturn => {
181
- return {
182
- bar: foo,
183
- };
184
- };
185
-
186
- ```
187
-
188
- #### 📄 ComponentName.module.scss
189
-
190
- The style specific to the component will be written in module form. This allows scoping the style of the component without overriding global style.
191
-
192
- ```css
193
- .root {
194
- background-color: red;
195
- }
196
-
197
- ```
198
-
199
- ```typescript
200
- import classes from './ComponentName.module.scss'
201
-
202
- export const ComponentName = () => {
203
- return (
204
- <div className={classes.root}>Foo</div>
205
- );
206
- };
9
+ ```shell
10
+ npm create @pplancq/react-app@latest <project_name>
207
11
  ```
208
- ### ❗ Naming Conventions
209
12
 
210
- ==> Component names, file names, and folder names should follow the **PascalCase** convention.
13
+ Replace <project_name> with the name of your new project.
211
14
 
212
- ## 🙇 <span id="learnmore">Learn More</span>
15
+ ## License
213
16
 
214
- - React & co
215
- - [React Documentation.](https://react.dev/).
216
- - [React Router Documentation.](https://reactrouter.com/en/main).
217
- - [React Query Documentation.](https://tanstack.com/query/v3/).
218
- - [React Hook Form Documentation.](https://react-hook-form.com/).
219
- - Test
220
- - [Vitest Documentation.](https://vitest.dev/).
221
- - [Testing Library Documentation.](https://testing-library.com/).
17
+ This project is under the MIT license.
package/_README.md ADDED
@@ -0,0 +1,239 @@
1
+ ## 🚀 <span id="getting-started">Getting Started</span>
2
+
3
+ This project was bootstrapped with [@pplancq/create-react-app](https://github.com/pplancq/dev-tools/tree/main/packages/create-react-app).
4
+
5
+ ### 🧾 Prerequisites
6
+
7
+ - Node.js : [Download here](https://nodejs.org/) (Preferably, use [Volta](https://volta.sh/))
8
+ - npm (Node Package Manager)
9
+
10
+ ### 🛠️ Installation
11
+
12
+ 1. Clone this repository to your computer.
13
+
14
+ ```bash
15
+ git clone https://github.com/votre-utilisateur/mon-projet-awesome.git mon-projet
16
+ cd mon-projet
17
+ ```
18
+
19
+ 2. Install dependencies.
20
+
21
+ ```bash
22
+ npm install
23
+ ```
24
+
25
+
26
+ In the project directory, you can run the following commands:
27
+
28
+ ### `npm start`
29
+
30
+ Launches the application in development mode.
31
+ Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
32
+
33
+ The page will reload automatically if you make edits.
34
+
35
+ You will also see lint errors in the console.
36
+
37
+ ### `npm test`
38
+
39
+ Launches the test runner in interactive mode.
40
+
41
+ ### `npm run build`
42
+
43
+ Builds the application for production in the `build` folder.
44
+
45
+ It correctly bundles React in production mode and optimizes the build for better performance.
46
+
47
+ The build is minified, and the filenames include hashes.
48
+ Your application is ready to be deployed!
49
+
50
+ ### `npm run lint`
51
+
52
+ Allows you to see lint errors without fixing them. This command initiates the linting process with three linters: **eslint**, **stylelint**, and **tsc** (TypeScript Compiler).
53
+
54
+ ### `npm run eslint:fix`
55
+
56
+ Allows you to fix eslint errors.
57
+
58
+ ### `npm run stylelint:fix`
59
+
60
+ Allows you to fix style lint errors.
61
+
62
+ ### `npm run remove:demo`
63
+
64
+ To remove the demo application.
65
+
66
+ ### `npm run migrate:vite`
67
+
68
+ To migrate from webpack to vite.
69
+
70
+ ## 🏗 <span id="project-structure">Project Structure</span>
71
+
72
+ ```
73
+ 📁 my-projet
74
+ ├── 📁 src
75
+ │ ├── 📁 ui
76
+ │ │ ├── 📁 Atoms
77
+ │ │ ├── 📁 Molecules
78
+ │ │ ├── 📁 Organisms
79
+ │ │ ├── 📁 Templates
80
+ │ ├── 📁 components
81
+ │ │ ├── 📁 formFields
82
+ │ ├── 📁 providers
83
+ │ ├── 📁 pages
84
+ │ │ ├── 📁 homePage
85
+ │ │ ├── 📁 page1
86
+ │ │ │ ├── 📁 sousPage1
87
+ │ ├── 📁 forms
88
+ │ │ ├── 📁 hooks
89
+ │ │ ├── 📁 risk
90
+ │ │ ├── 📁 contact
91
+ │ ├── 📁 hooks
92
+ │ │ ├── 📁 api
93
+ │ │ ├── 📁 useCustom1
94
+ │ │ ├── 📁 useCustom2
95
+ │ ├── 📁 utils
96
+ │ │ ├── 📁 services
97
+ │ │ ├── 📁 tests
98
+ │ │ ├── 📁 helpers
99
+ │ ├── 📁 routing
100
+ │ ├── 📁 api
101
+ │ ├── 📁 types
102
+ │ ├── 📁 assets
103
+ │ ├── 📁 config
104
+ ```
105
+
106
+ ### 📚 Folder Definitions
107
+
108
+ Here is the project folder structure, with a brief description of each folder:
109
+
110
+ | Folder | Description|
111
+ | -------- | -------- |
112
+ | **📁 src** | ***The root directory of the application source code.***
113
+ | [**📁 ui**](./src/ui/README.md) | Contains reusable components designed to be used across projects. Components can be basic (Atoms), more complex (Molecules), higher-level components (Organisms), or page templates (Templates). |
114
+ | [**📁&#160;components**](./src/components/README.md) | Contains project-specific reusable components, for example, form components using React Hook Form. |
115
+ | [**📁 providers**](./src/providers/README.md) | This folder contains context providers or custom hooks that provide data to the entire application. |
116
+ | [**📁 pages**](./src/pages/README.md) | Contains the pages of the application. Each subfolder represents a distinct page or view of the application. |
117
+ | [**📁 forms**](./src/forms/README.md) | Contains the forms of the application, grouping hooks related to forms. |
118
+ | [**📁 hooks**](./src/hooks/README.md) | Includes custom hooks for various application features, such as API calls with React Query. |
119
+ | [**📁 utils**](./src/utils/README.md) | Contains utilities and services such as test files, utility functions, etc. |
120
+ | [**📁 routing**](./src/routing/README.md) | This folder is intended for native API calls using the `fetch`. function. These calls are essential for fetching real-time data from external sources, such as remote servers or web services. |
121
+ | [**📁 types**](./src/types/README.md) | Provides TypeScript type definitions to enhance the robustness of your code. |
122
+ | [**📁 assets**](./src/assets/README.md) | Contains static files such as images, fonts, etc., used in the application. |
123
+ | [**📁 config**](./src/config/README.md) | Contains all the important configurations and utilities needed for our project. |
124
+
125
+ ## 🏗 <span id="component-structure">React Component Structure</span>
126
+
127
+ ```
128
+ 📁 ComponentName
129
+ ├── 📁 __tests__
130
+ │ ├── 📄 ComponentName.feature
131
+ │ ├── 📄 ComponantName.steps.tsx
132
+ │ ├── 📄 ComponentName.test.tsx
133
+ ├── 📄 index.ts
134
+ ├── 📄 ComponentName.tsx
135
+ ├── 📄 ComponentName.hook.ts
136
+ ├── 📄 ComponentName.module.scss
137
+ ```
138
+
139
+ ### 📚 Files Definitions
140
+
141
+ #### 📁 **tests**
142
+
143
+ The tests folder may contain unit tests specific to the package. The idea is to mainly test through functional tests. However, in some cases, it may be useful to test a component in isolation (for example, when developing a package reused between multiple projects).
144
+
145
+ #### 📄 index.ts
146
+
147
+ This file allows exposing the component and avoids having to redo imports if the file implementing the component changes its name.
148
+
149
+ ```typescript
150
+ export { ComponentName } from './ComponentName';
151
+ ```
152
+
153
+ This will allow importing a component like this:
154
+
155
+ ```typescript
156
+ import { ComponentName } from '@Front/ComponentName';
157
+ ```
158
+
159
+ #### 📄 ComponentName.tsx
160
+
161
+ Each file contains a single exported component. It will essentially contain the view and very little logic. If the component needs more logic, it is advisable to use a custom hook.
162
+
163
+ ```typescript
164
+ type ComponentNameProps = {
165
+ foo: string;
166
+ }
167
+
168
+ export const ComponentName = ({ foo }) => {
169
+ return (
170
+ <div>{foo}</div>
171
+ );
172
+ };
173
+ ```
174
+
175
+ #### 📄 ComponentName.hook.ts
176
+
177
+ A custom hook allows moving the logic specific to a component outside of its view.
178
+
179
+ ```typescript
180
+ export type UseComponentNameProps = {
181
+ foo: string;
182
+ };
183
+
184
+ export type UseComponentNameReturn = {
185
+ bar: string;
186
+ };
187
+
188
+ export const useComponentName = ({ foo }: UseComponentNameProps): UseComponentNameReturn => {
189
+ return {
190
+ bar: foo,
191
+ };
192
+ };
193
+
194
+ ```
195
+
196
+ #### 📄 ComponentName.module.scss
197
+
198
+ The style specific to the component will be written in module form. This allows scoping the style of the component without overriding global style.
199
+
200
+ ```css
201
+ .root {
202
+ background-color: red;
203
+ }
204
+
205
+ ```
206
+
207
+ ```typescript
208
+ import classes from './ComponentName.module.scss'
209
+
210
+ export const ComponentName = () => {
211
+ return (
212
+ <div className={classes.root}>Foo</div>
213
+ );
214
+ };
215
+ ```
216
+ ### ❗ Naming Conventions
217
+
218
+ ==> Component names, file names, and folder names should follow the **PascalCase** convention.
219
+
220
+ ## ⚠️ Caution with Environment Variables
221
+
222
+ The webpack configuration of this project allows for environment variables to be included in the application bundle. This could potentially expose sensitive information if the bundle is publicly accessible.
223
+
224
+ It is recommended to only include non-sensitive environment variables in the application bundle. Sensitive information should not be exposed even if the bundle is publicly accessible.
225
+
226
+ Ensure you understand the security implications before including environment variables in your bundle.
227
+
228
+ Please note that the web configuration pre-filters environment variables via the default prefix ‘FRONT_’. This means that only environment variables starting with ‘FRONT_’ will be included in the bundle. This is an additional layer of security to prevent the accidental exposure of sensitive environment variables.
229
+
230
+ ## 🙇 <span id="learnmore">Learn More</span>
231
+
232
+ - React & co
233
+ - [React Documentation.](https://react.dev/).
234
+ - [React Router Documentation.](https://reactrouter.com/en/main).
235
+ - [React Query Documentation.](https://tanstack.com/query/v3/).
236
+ - [React Hook Form Documentation.](https://react-hook-form.com/).
237
+ - Test
238
+ - [Vitest Documentation.](https://vitest.dev/).
239
+ - [Testing Library Documentation.](https://testing-library.com/).
package/_gitignore CHANGED
@@ -4,13 +4,15 @@
4
4
  /node_modules
5
5
  /.pnp
6
6
  .pnp.js
7
+ .yarn
7
8
 
8
9
  # testing
9
10
  /coverage
10
11
 
11
12
  # production
12
13
  /build
13
- /test-report.xml
14
+ /junit-report.xml
15
+ /sonar-report.xml
14
16
 
15
17
  # misc
16
18
  .DS_Store
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pplancq/react-template",
3
- "version": "1.0.0",
3
+ "version": "1.1.1",
4
4
  "license": "MIT",
5
5
  "description": "react template",
6
6
  "author": "pplancq <paul.plancq@outlook.fr>",
@@ -20,6 +20,9 @@
20
20
  "stylelint": "stylelint \"src/**/*.{scss,css}\"",
21
21
  "stylelint:fix": "stylelint \"src**/*.{scss,css}\" --fix",
22
22
  "tsc": "tsc --noEmit",
23
+ "package:check": "npm exec --yes package-lock-utd@1.1.3",
24
+ "remove:demo": "./scripts/removeDemo.js",
25
+ "migrate:vite": "./scripts/migrateToVite.js",
23
26
  "_prepare": "husky"
24
27
  },
25
28
  "bugs": {
@@ -31,39 +34,48 @@
31
34
  ],
32
35
  "dependencies": {
33
36
  "@hookform/resolvers": "^3.3.2",
37
+ "@tanstack/react-query": "^5.25.0",
38
+ "@tanstack/react-query-devtools": "^5.25.0",
34
39
  "react": "^18.2.0",
35
40
  "react-dom": "^18.2.0",
36
- "react-hook-form": "^7.49.2",
37
- "react-query": "^3.39.3",
38
- "react-router-dom": "^6.21.0",
39
- "yup": "^1.3.3"
41
+ "react-hook-form": "^7.51.0",
42
+ "react-router-dom": "^6.22.3",
43
+ "yup": "^1.4.0"
40
44
  },
41
45
  "devDependencies": {
42
- "@pplancq/babel-config": "1.0.0",
43
- "@pplancq/commitlint-config": "1.0.0",
44
- "@pplancq/eslint-config": "1.0.0",
45
- "@pplancq/postcss-config": "1.0.0",
46
- "@pplancq/prettier-config": "1.0.0",
47
- "@pplancq/stylelint-config": "1.0.0",
48
- "@pplancq/webpack-config": "1.0.0",
49
- "@svgr/webpack": "^8.1.0",
46
+ "@commitlint/cli": "^19.0.3",
47
+ "@pplancq/babel-config": "*",
48
+ "@pplancq/commitlint-config": "*",
49
+ "@pplancq/eslint-config": "*",
50
+ "@pplancq/postcss-config": "*",
51
+ "@pplancq/prettier-config": "*",
52
+ "@pplancq/stylelint-config": "*",
53
+ "@pplancq/webpack-config": "*",
50
54
  "@testing-library/jest-dom": "^6.1.5",
51
55
  "@testing-library/react": "^14.1.2",
52
56
  "@testing-library/user-event": "^14.5.1",
53
- "@types/react": "^18.2.45",
54
- "@types/react-dom": "^18.2.18",
57
+ "@types/react": "^18.2.64",
58
+ "@types/react-dom": "^18.2.21",
55
59
  "@vitejs/plugin-react": "^4.2.1",
56
- "@vitest/coverage-v8": "^1.0.4",
60
+ "@vitest/coverage-v8": "^1.3.1",
57
61
  "concurrently": "^8.2.2",
58
- "husky": "^9.0.7",
62
+ "eslint": "^8.57.0",
63
+ "eslint-plugin-prettier": "^5.1.3",
64
+ "husky": "^9.0.11",
59
65
  "jsdom": "^24.0.0",
60
66
  "lint-staged": "^15.2.0",
67
+ "prettier": "^3.2.5",
68
+ "stylelint": "^16.2.1",
69
+ "stylelint-prettier": "^5.0.0",
61
70
  "tsc-files": "^1.1.4",
62
- "typescript": "^5.3.3",
71
+ "typescript": "^5.4.2",
63
72
  "vite-plugin-svgr": "^4.2.0",
64
73
  "vite-tsconfig-paths": "^4.2.2",
65
74
  "vitest": "^1.0.4",
66
- "vitest-sonar-reporter": "^1.0.0"
75
+ "vitest-sonar-reporter": "^2.0.0",
76
+ "webpack": "^5.90.3",
77
+ "webpack-cli": "^5.1.4",
78
+ "webpack-dev-server": "^4.15.1"
67
79
  },
68
80
  "volta": {
69
81
  "node": "20.10.0",
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env node
2
+ const { execSync } = require('child_process');
3
+ const { rmSync, writeFileSync, readFileSync } = require('fs');
4
+ const { resolve } = require('path');
5
+
6
+ const NPM = 'npm';
7
+ const YARN = 'yarn';
8
+ const PNPM = 'pnpm';
9
+
10
+ const runCommand = (command, options = { stdio: 'inherit' }) => {
11
+ try {
12
+ execSync(command, options);
13
+ } catch (e) {
14
+ console.error(`Failed to execute ${command}`, e);
15
+ process.exit(-1);
16
+ }
17
+ };
18
+
19
+ const getPackageManager = () => {
20
+ switch (true) {
21
+ case process.env.npm_config_user_agent.includes(YARN):
22
+ return YARN;
23
+ case process.env.npm_config_user_agent.includes(PNPM):
24
+ return PNPM;
25
+ default:
26
+ return NPM;
27
+ }
28
+ };
29
+
30
+ const packageManager = getPackageManager();
31
+
32
+ console.info('\nremove webpack ...');
33
+ runCommand(`${packageManager} remove @pplancq/webpack-config webpack webpack-cli webpack-dev-server`);
34
+ rmSync(resolve(__dirname, '../webpack.config.js'));
35
+ console.info('\ninstall vite package ...');
36
+ runCommand(
37
+ `${packageManager} ${packageManager === YARN ? 'add --dev' : 'install --save-dev'} vite vite-plugin-eslint2 vite-plugin-stylelint`,
38
+ );
39
+
40
+ writeFileSync(
41
+ resolve(__dirname, '../vite.config.mts'),
42
+ `import react from '@vitejs/plugin-react'
43
+ import { resolve } from 'path'
44
+ import { defineConfig, loadEnv } from 'vite'
45
+ import eslintPlugin from 'vite-plugin-eslint2'
46
+ import stylelintPlugin from 'vite-plugin-stylelint'
47
+ import svgr from 'vite-plugin-svgr'
48
+ import viteTsconfigPaths from 'vite-tsconfig-paths'
49
+
50
+ export default defineConfig(({ mode }) => {
51
+ const env = loadEnv(mode, process.cwd(), '')
52
+
53
+ return {
54
+ plugins: [
55
+ react(),
56
+ viteTsconfigPaths(),
57
+ svgr(),
58
+ eslintPlugin({
59
+ useEslintrc: true,
60
+ emitErrorAsWarning: true,
61
+ cache: false
62
+ }),
63
+ stylelintPlugin({
64
+ emitErrorAsWarning: true,
65
+ cache: false
66
+ })
67
+ ],
68
+ envPrefix: env.ENV_PREFIX ?? 'FRONT_',
69
+ server: {
70
+ port: parseInt(process.env.PORT ?? '3000', 10),
71
+ open: (process.env.BROWSER ?? 'false') === 'true'
72
+ },
73
+ root: resolve(__dirname, 'public'),
74
+ publicDir: resolve(__dirname, 'public'),
75
+ resolve: {
76
+ alias: { '/src': resolve(__dirname, 'src') }
77
+ },
78
+ build: {
79
+ outDir: resolve(__dirname, 'build')
80
+ }
81
+ }
82
+ })
83
+ `,
84
+ { encoding: 'utf-8' },
85
+ );
86
+
87
+ const packagesJson = JSON.parse(readFileSync(resolve(__dirname, '../package.json'), { encoding: 'utf-8' }));
88
+ const { start, build, 'migrate:vite': _, ...scripts } = packagesJson.scripts;
89
+ packagesJson.scripts = { start: 'vite', build: 'vite build', preview: 'vite preview', ...scripts };
90
+ writeFileSync(resolve(__dirname, '../package.json'), JSON.stringify(packagesJson, null, 2), { encoding: 'utf-8' });
91
+
92
+ let indexHTML = readFileSync(resolve(__dirname, '../public/index.html'), { encoding: 'utf-8' });
93
+ indexHTML = indexHTML.replace(' </body>', ' <script type="module" src="/src/main.ts"></script>\n </body>');
94
+ writeFileSync(resolve(__dirname, '../public/index.html'), indexHTML, { encoding: 'utf-8' });
95
+
96
+ rmSync(resolve(__dirname, '../scripts/migrateToVite.js'));
97
+
98
+ console.info('\nThe application has been migrate to vite');
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env node
2
+ const { rmSync, readFileSync, writeFileSync } = require('fs');
3
+ const { resolve } = require('path');
4
+
5
+ const resolveSrc = path => resolve(__dirname, `../src${path}`);
6
+
7
+ rmSync(resolveSrc('/api/demoApi.ts'));
8
+
9
+ rmSync(resolveSrc('/assets/css/mainBody.css'));
10
+ rmSync(resolveSrc('/assets/css/reset.css'));
11
+ writeFileSync(resolveSrc('/assets/css/global.css'), ':root {\n --white-color: #fff;\n}\n', { encoding: 'utf-8' });
12
+ let assetsIndex = readFileSync(resolveSrc('/assets/css/index.ts'), { encoding: 'utf-8' });
13
+ assetsIndex = assetsIndex.replaceAll("import './reset.css';\nimport './mainBody.css';\n", "import './global.css';\n");
14
+ writeFileSync(resolveSrc('/assets/css/index.ts'), assetsIndex, { encoding: 'utf-8' });
15
+
16
+ rmSync(resolveSrc('/assets/images/logo.png'));
17
+ rmSync(resolveSrc('/assets/images/templatePlugins.png'));
18
+
19
+ rmSync(resolveSrc('/components/Footer'), { recursive: true });
20
+ rmSync(resolveSrc('/components/Header'), { recursive: true });
21
+ rmSync(resolveSrc('/components/TextInput'), { recursive: true });
22
+
23
+ rmSync(resolveSrc('/forms/ProfileForm'), { recursive: true });
24
+
25
+ rmSync(resolveSrc('/hooks/api/useDemoApi.ts'));
26
+ let queryKey = readFileSync(resolveSrc('/hooks/api/queryKey.ts'), { encoding: 'utf-8' });
27
+ queryKey = queryKey.replaceAll("export const demoQuery = () => ['dataWithDelay'];\n", '');
28
+ writeFileSync(resolveSrc('/hooks/api/queryKey.ts'), queryKey, { encoding: 'utf-8' });
29
+
30
+ rmSync(resolveSrc('/pages/Demo'), { recursive: true });
31
+ rmSync(resolveSrc('/pages/Layout'), { recursive: true });
32
+ rmSync(resolveSrc('/pages/UnexpectedError'), { recursive: true });
33
+ writeFileSync(resolveSrc('/pages/Home/index.ts'), "export { homeRoutes } from './routes';\n", { encoding: 'utf-8' });
34
+ writeFileSync(
35
+ resolveSrc('/pages/Home/routes.tsx'),
36
+ "import type { RouteObject } from 'react-router-dom';\n" +
37
+ "import { Home } from './Home';\n" +
38
+ '\n' +
39
+ 'export const homeRoutes: RouteObject = {\n' +
40
+ ' index: true,\n' +
41
+ ' element: <Home />,\n' +
42
+ '};\n',
43
+ { encoding: 'utf-8' },
44
+ );
45
+ writeFileSync(resolveSrc('/pages/Home/Home.tsx'), 'export const Home = () => {\n return <div>HomePage</div>;\n};\n', {
46
+ encoding: 'utf-8',
47
+ });
48
+
49
+ let appRoutes = readFileSync(resolveSrc('/routing/appRoutes.ts'), { encoding: 'utf-8' });
50
+ appRoutes = appRoutes.replaceAll(
51
+ "\n reactQueryDemo: '/reactQueryDemo',\n reactHookFormDemo: '/reactHookFormDemo',",
52
+ '',
53
+ );
54
+ writeFileSync(resolveSrc('/routing/appRoutes.ts'), appRoutes, { encoding: 'utf-8' });
55
+ let routes = readFileSync(resolveSrc('/routing/routes.tsx'), { encoding: 'utf-8' });
56
+ routes = routes.replaceAll(
57
+ "import { demoRoutes } from '@Front/pages/Demo';",
58
+ "import { homeRoutes } from '@Front/pages/Home';",
59
+ );
60
+ routes = routes.replaceAll("\nimport { Layout } from '@Front/pages/Layout';", '');
61
+ routes = routes.replaceAll("\nimport { UnexpectedError } from 'src/pages/UnexpectedError';", '');
62
+ routes = routes.replaceAll(
63
+ 'element: <Layout />,\n children: [demoRoutes],\n errorElement: <UnexpectedError />,',
64
+ 'children: [homeRoutes],',
65
+ );
66
+ writeFileSync(resolveSrc('/routing/routes.tsx'), routes, { encoding: 'utf-8' });
67
+
68
+ rmSync(resolveSrc('/types/demoApi.ts'));
69
+ rmSync(resolveSrc('/types/profileTypes.ts'));
70
+
71
+ rmSync(resolveSrc('/ui/atoms/Input'), { recursive: true });
72
+ rmSync(resolveSrc('/ui/atoms/Logo'), { recursive: true });
73
+ rmSync(resolveSrc('/ui/atoms/NavLink'), { recursive: true });
74
+ rmSync(resolveSrc('/ui/molecules/Navigation'), { recursive: true });
75
+ rmSync(resolveSrc('/ui/organisms/Footer'), { recursive: true });
76
+ rmSync(resolveSrc('/ui/organisms/Header'), { recursive: true });
77
+ rmSync(resolveSrc('/ui/organisms/MainContent'), { recursive: true });
78
+ rmSync(resolveSrc('/ui/templates/MainTemplate'), { recursive: true });
79
+
80
+ const packagesJson = JSON.parse(readFileSync(resolve(__dirname, '../package.json'), { encoding: 'utf-8' }));
81
+ const { 'remove:demo': _, ...scripts } = packagesJson.scripts;
82
+ packagesJson.scripts = { ...scripts };
83
+ writeFileSync(resolve(__dirname, '../package.json'), JSON.stringify(packagesJson, null, 2), { encoding: 'utf-8' });
84
+
85
+ rmSync(resolve(__dirname, '../scripts/removeDemo.js'));
86
+
87
+ console.info('\nThe demo application has been removed\n');
@@ -0,0 +1,16 @@
1
+ export enum METHODS {
2
+ get = 'GET',
3
+ post = 'POST',
4
+ put = 'PUT',
5
+ patch = 'PATCH',
6
+ delete = 'DELETE',
7
+ }
8
+
9
+ export enum HEADERS {
10
+ contentType = 'content-type',
11
+ }
12
+
13
+ export enum MINE_TYPES {
14
+ json = 'application/json',
15
+ text = 'plain/text',
16
+ }
@@ -1,44 +1,10 @@
1
+ import { fetchApi } from '@Front/api/fetchApi';
1
2
  import type { Users } from '@Front/types/demoApi';
2
3
 
3
- const data: Users = [
4
- {
5
- id: 1,
6
- firstName: 'John',
7
- lastName: 'Doe',
8
- age: 30,
9
- email: 'john.doe@example.com',
10
- },
11
- {
12
- id: 2,
13
- firstName: 'Jane',
14
- lastName: 'Smith',
15
- age: 25,
16
- email: 'jane.smith@example.com',
17
- },
18
- {
19
- id: 3,
20
- firstName: 'Alice',
21
- lastName: 'Johnson',
22
- age: 28,
23
- email: 'alice.johnson@example.com',
24
- },
25
- {
26
- id: 4,
27
- firstName: 'Bob',
28
- lastName: 'Brown',
29
- age: 35,
30
- email: 'bob.brown@example.com',
31
- },
32
- ];
33
-
34
- export const fetchDemoApi = async (): Promise<Users> => {
35
- return new Promise<Users>((resolve, reject) => {
36
- try {
37
- setTimeout(() => {
38
- resolve(data);
39
- }, 3000);
40
- } catch (error) {
41
- reject(error);
42
- }
4
+ export const fetchDemoApi = async () => {
5
+ const users = await fetchApi<Users>({
6
+ path: 'https://jsonplaceholder.typicode.com/users',
43
7
  });
8
+
9
+ return users.map(user => ({ ...user, username: user.username.toUpperCase(), email: user.email.toLowerCase() }));
44
10
  };
@@ -0,0 +1,49 @@
1
+ import type { Json } from '@Front/types/api';
2
+ import { HEADERS, METHODS, MINE_TYPES } from './constant';
3
+
4
+ export type FetchApiError = Error & {
5
+ code?: number;
6
+ contentType?: MINE_TYPES;
7
+ };
8
+
9
+ type FetchApiProps = {
10
+ path: string;
11
+ method?: METHODS;
12
+ data?: Json;
13
+ headers?: HeadersInit;
14
+ };
15
+
16
+ export const fetchApi = async <T extends Json | string>({
17
+ path,
18
+ method = METHODS.get,
19
+ data,
20
+ headers = [],
21
+ }: FetchApiProps): Promise<T> => {
22
+ const mergeHeaders = new Headers(headers);
23
+
24
+ if (data) {
25
+ mergeHeaders.append(HEADERS.contentType, MINE_TYPES.json);
26
+ }
27
+
28
+ const response = await fetch(path, {
29
+ method,
30
+ ...(data && { body: JSON.stringify(data) }),
31
+ headers: mergeHeaders,
32
+ });
33
+
34
+ const content = await response.text();
35
+
36
+ if (!response.ok) {
37
+ const error: FetchApiError = new Error(content);
38
+ error.code = response.status;
39
+ error.contentType = (response.headers.get(HEADERS.contentType) as MINE_TYPES) ?? MINE_TYPES.text;
40
+
41
+ throw error;
42
+ }
43
+
44
+ if ((response.headers.get(HEADERS.contentType) ?? '').includes('json')) {
45
+ return JSON.parse(content) as T;
46
+ }
47
+
48
+ return content as T;
49
+ };
@@ -1,3 +1,3 @@
1
- import { QueryClient } from 'react-query';
1
+ import { QueryClient } from '@tanstack/react-query';
2
2
 
3
3
  export const queryClient = new QueryClient();
@@ -1,6 +1,6 @@
1
1
  import { fetchDemoApi } from '@Front/api/demoApi';
2
2
  import type { Users } from '@Front/types/demoApi';
3
- import { useQuery } from 'react-query';
3
+ import { useQuery } from '@tanstack/react-query';
4
4
  import { demoQuery } from './queryKey';
5
5
 
6
6
  type UseDemoApiReturn = {
@@ -10,7 +10,7 @@ type UseDemoApiReturn = {
10
10
  };
11
11
 
12
12
  export const useDemoApi = (): UseDemoApiReturn => {
13
- const { data = [], isLoading, isError } = useQuery<Users>(demoQuery(), fetchDemoApi);
13
+ const { data = [], isLoading, isError } = useQuery<Users>({ queryKey: demoQuery(), queryFn: fetchDemoApi });
14
14
 
15
15
  return { result: data, isLoading, isError };
16
16
  };
@@ -7,8 +7,7 @@ export const Demo = () => {
7
7
  return (
8
8
  <div className={classes.container}>
9
9
  <div className={classes.bigTitleStyle}>
10
- Welcome to Your React Starter Kit
11
- <span>Welcome</span>
10
+ Welcome to Your React Starter Kit <span>Welcome</span>
12
11
  </div>
13
12
 
14
13
  <div className={classes.foo}>FlexBlug</div>
@@ -28,20 +28,20 @@ export const ReactQueryDemo = () => {
28
28
  <thead>
29
29
  <tr>
30
30
  <th>ID</th>
31
- <th>First Name</th>
32
- <th>Last Name</th>
33
- <th>Age</th>
31
+ <th>Name</th>
32
+ <th>Username</th>
34
33
  <th>Email</th>
34
+ <th>Website</th>
35
35
  </tr>
36
36
  </thead>
37
37
  <tbody>
38
38
  {result?.map(eachResult => (
39
39
  <tr key={eachResult.id}>
40
40
  <td>{eachResult.id}</td>
41
- <td>{eachResult.firstName}</td>
42
- <td>{eachResult.lastName}</td>
43
- <td>{eachResult.age}</td>
41
+ <td>{eachResult.name}</td>
42
+ <td>{eachResult.username}</td>
44
43
  <td>{eachResult.email}</td>
44
+ <td>{eachResult.website}</td>
45
45
  </tr>
46
46
  ))}
47
47
  </tbody>
@@ -8,7 +8,7 @@ exports[`Demo Component > should render the Demo component correctly 1`] = `
8
8
  <div
9
9
  class="_bigTitleStyle_85a2c3"
10
10
  >
11
- Welcome to Your React Starter Kit
11
+ Welcome to Your React Starter Kit
12
12
  <span>
13
13
  Welcome
14
14
  </span>
@@ -1,4 +1,4 @@
1
- .errorPageStyle {
1
+ .root {
2
2
  display: flex;
3
3
  width: 100%;
4
4
  padding-top: 15%;
@@ -2,13 +2,13 @@ import logo from '@Front/assets/images/logo.png';
2
2
  import { Logo } from '@Front/ui/atoms/Logo';
3
3
  import { Link, useRouteError } from 'react-router-dom';
4
4
 
5
- import classes from './Error.module.css';
5
+ import classes from './UnexpectedError.module.css';
6
6
 
7
- export const Error = () => {
7
+ export const UnexpectedError = () => {
8
8
  const error: unknown = useRouteError();
9
9
 
10
10
  return (
11
- <div className={classes.errorPageStyle}>
11
+ <div className={classes.root}>
12
12
  <Link to="/">
13
13
  <Logo src={logo} alt="logo" />
14
14
  </Link>
@@ -0,0 +1 @@
1
+ export { UnexpectedError } from './UnexpectedError';
@@ -1,6 +1,6 @@
1
+ import { type QueryClient, QueryClientProvider as ReactQueryClientProvider } from '@tanstack/react-query';
2
+ import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
1
3
  import type { PropsWithChildren } from 'react';
2
- import { type QueryClient, QueryClientProvider as ReactQueryClientProvider } from 'react-query';
3
- import { ReactQueryDevtools } from 'react-query/devtools';
4
4
 
5
5
  type ClientProviderProps = {
6
6
  client: QueryClient;
@@ -1,13 +1,13 @@
1
1
  import { demoRoutes } from '@Front/pages/Demo';
2
- import { Error } from '@Front/pages/Error';
3
2
  import { Layout } from '@Front/pages/Layout';
4
3
  import type { RouteObject } from 'react-router-dom';
4
+ import { UnexpectedError } from 'src/pages/UnexpectedError';
5
5
 
6
6
  export const routeObject: RouteObject[] = [
7
7
  {
8
8
  path: '/',
9
9
  element: <Layout />,
10
10
  children: [demoRoutes],
11
- errorElement: <Error />,
11
+ errorElement: <UnexpectedError />,
12
12
  },
13
13
  ];
@@ -0,0 +1,6 @@
1
+ export type JsonValue = JsonObject | JsonArray | string | number | boolean | null;
2
+ export type JsonArray = Array<JsonValue>;
3
+ export type JsonObject = {
4
+ [key: string]: JsonValue;
5
+ };
6
+ export type Json = JsonObject | JsonArray;
@@ -1,9 +1,25 @@
1
+ export type Address = {
2
+ street: string;
3
+ suite: string;
4
+ city: string;
5
+ zipcode: string;
6
+ };
7
+
8
+ export type Company = {
9
+ name: string;
10
+ catchPhrase: string;
11
+ bs: string;
12
+ };
13
+
1
14
  export type User = {
2
15
  id: number;
3
- firstName: string;
4
- lastName: string;
5
- age: number;
16
+ name: string;
17
+ username: string;
6
18
  email: string;
19
+ address: Address;
20
+ phone: string;
21
+ website: string;
22
+ company: Company;
7
23
  };
8
24
 
9
25
  export type Users = User[];
@@ -1 +0,0 @@
1
- export { Error } from './Error';