The project is a Signle Page Appliation, it uses react as frontend framework, Nest as backend framework. Both frontend and backend are using typescript. The project is using sqlite as backend database, for demo purpose, to eliminate database configuration. It has the following features:
- JWT authorization and authentication
- Generaral Entity CRUD Web Api
- Type Orm as entity framework
- User Login and User Profile
- User CRUD and Client CRUD
- Material UI Design
Authough both frontend and backend are written by typescript, it's tricky to put code in to same repository my ideal strutrue would be like
- -backend/src
- -frontend/src
- -shared/src in this way, main.js of the backend need to refrence some file in ../../shared/src, it didn't work after I publish the project production enviroment. so share files must reside in backend src directory, so I changed the structure as following
- package.json
- -src
- -[nest code]
- -src\client
- -scr\client\package.json
- -src\client\src
- -scr\client\src\share //entities, shared utility functions,etc...
- -src\client\src[react code]
the root directory of the project is the backend code, it was generated by nest cli the src\client direcotry is frontend code, it is a react app generated by 'create react app' both nest app and react app have their own package.json, so frontend and backend can has their own node_modules.
add the following line to src\client.env, otherwise react app won't compile
SKIP_PREFLIGHT_CHECK=true
also set baseUrl to src in both package.json and src/client/package.json
"baseUrl": "./src",
add src/client to tsconfig.build.json
"exclude": ["node_modules", "test", "dist","src/client", "**/*spec.ts"]
- start backend first
yarn start:dev
- start the frontend
cd /src/clinet
yarn start
the headend is listening to port 4000, the frontend is listening to port 3000 add the following code to src/client/package.json, so if the frontend requests to a backend webapi, eg 'api/sign/sign', it would send the request to 'http://localhost:4000/api/sign/sign'
"proxy": "http://localhost:4000/",
frontend and backend can be put to seperate app service, I prefered to put them in the same app service to save costs, also I don't need to enable cros.
After deploy to app service, the structure is like
- main.js
- client //here is all react code
- client/src/share //the code shared between frontend and backend
- other headend code
- node_modules
a client request was handled by nest router first, if nest router find the url match a controller, then it calls the web api, otherwise it looks if there is a static file in the client directory
ServeStaticModule.forRoot({
rootPath: join(__dirname, 'client')
}),
typeorm require add decorator @entity to class, and add @column decorator to class properies. also I want to use a lib 'class-validator' to validate form inputs. so the entity code ends up as the following
import { Entity, Unique,Column, ManyToOne } from 'decorators/myTypeOrmDecorator';
import { IsEmail, IsString, MinLength, MaxLength, Matches} from 'class-validator';
@Entity('user')
@Unique(['username'])
export class User extends MyBaseEntity {
@IsEmail()
@Column()
username: string = '';
@MinLength(1)
@Column()
firstname: string ='';
...
For the backend project, I can import @Entity(), @Column() from typeorm, but I don't want to do that for frontend project. so instead of import Entity, Column from typeorm directly, I import the decorators from myTypeOrmDecorator
import { Entity, Unique,Column, ManyToOne } from 'decorators/myTypeOrmDecorator';
because in both package.json and src/client/package.json, I set baseUrl to 'src', 'decorators/myTypeOrmDecorator' refrence to diffrent files for frontend project and backend project
- for frontend project, it refrence to 'src/client/src/decorators/myTypeOrmDecorator'
- for backend project, it refrence to 'src/decorators/myTypeOrmDecorator'
in 'src/decorators/myTypeOrmDEcorator', I export * from typeorm
export * from "typeorm";
in 'src/client/src/decorators/myTypeOrmDecorator', I create some dummy decorators, the decorators do nothing, just to let frontend code be compiled
todo: when create use, if validate fail, it clear the form, maybe useMemory?