configure backend

This commit is contained in:
Владислав Чикалкин 2020-08-21 10:14:34 +03:00
parent 1ec8e8c254
commit b8bbdf3799
34 changed files with 590 additions and 59 deletions

3
.gitignore vendored
View File

@ -21,3 +21,6 @@
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
yarn.lock
*.log
package-lock.json

11
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,11 @@
{
"files.exclude": {
"**/.git": true,
"**/.svn": true,
"**/.hg": true,
"**/CVS": true,
"**/.DS_Store": true,
"**/node_modules": true
},
"explorerExclude.backup": null
}

View File

@ -1,25 +1,69 @@
{ {
"name": "evo_calculator", "name": "evo_calculator",
"version": "0.1.0", "version": "0.0.1",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.10.4",
"@babel/helper-split-export-declaration": "^7.11.0",
"@testing-library/jest-dom": "^4.2.4", "@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2", "@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2", "@testing-library/user-event": "^7.1.2",
"@types/jest": "^24.0.0", "axios": "^0.19.2",
"@types/node": "^12.0.0", "body-parser": "^1.19.0",
"@types/react": "^16.9.0", "class-validator": "^0.12.2",
"@types/react-dom": "^16.9.0", "compression": "^1.7.4",
"cookie-parser": "^1.4.5",
"cors": "^2.8.5",
"express": "^4.17.1",
"express-node-sspi": "^1.0.1",
"helmet": "^4.1.0",
"http-errors": "^1.8.0",
"lodash": "^4.17.20",
"morgan": "^1.10.0",
"mssql": "^6.2.1",
"node-sspi": "^0.2.8",
"nodemon": "^2.0.4",
"normalize.css": "^8.0.1",
"react": "^16.13.1", "react": "^16.13.1",
"react-dom": "^16.13.1", "react-dom": "^16.13.1",
"react-redux": "^7.2.1",
"react-router": "^5.2.0",
"react-router-dom": "^5.2.0",
"react-scripts": "3.4.3", "react-scripts": "3.4.3",
"typescript": "~3.7.2" "reflect-metadata": "^0.1.13",
"rxjs": "^6.6.2",
"styled-components": "^5.1.1",
"styled-system": "^5.1.5",
"ts-loader": "^8.0.2",
"typeorm": "^0.2.25",
"typescript": "~3.7.2",
"webpack-cli": "^3.3.12"
},
"devDependencies": {
"@types/body-parser": "^1.19.0",
"@types/compression": "^1.7.0",
"@types/cookie-parser": "^1.4.2",
"@types/cors": "^2.8.7",
"@types/express": "^4.17.7",
"@types/morgan": "^1.9.1",
"@types/node": "^14.6.0",
"@types/react-router-dom": "^5.1.5",
"@types/styled-components": "^5.1.2",
"agentkeepalive": "^4.1.3",
"http-proxy-middleware": "^1.0.5",
"webpack-node-externals": "^2.5.1"
}, },
"scripts": { "scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test", "test": "react-scripts test",
"eject": "react-scripts eject" "eject": "react-scripts eject",
"dev": "cross-env NODE_ENV=development concurrently -p name -c \"yellow,magenta,blue\" -n \"webpack-server,nodemon-server,CRA\" \"yarn dev:server:webpack\" \"yarn dev:server:nodemon\" \"yarn dev:client\"",
"dev:client": "wait-on -l tcp:3001 && react-scripts start",
"dev:server": "concurrently -p name -c \"yellow,magenta\" -n \"webpack-server,nodemon-server\" \"yarn dev:server:webpack\" \"yarn dev:server:nodemon\"",
"dev:server:webpack": "webpack --config webpack.config.server.js --watch",
"dev:server:nodemon": "rimraf build/server.js && wait-on -l build/server.js && nodemon build/server.js",
"build": "yarn build:client && yarn build:server",
"build:client": "react-scripts build",
"build:server": "cross-env NODE_ENV=production webpack --config webpack.config.server.js"
}, },
"eslintConfig": { "eslintConfig": {
"extends": "react-app" "extends": "react-app"

View File

@ -2,19 +2,31 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> <link
rel="icon"
href="%PUBLIC_URL%/favicon.ico"
crossorigin="use-credentials"
/>
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<meta <meta
name="description" name="description"
content="Web site created using create-react-app" content="Web site created using create-react-app"
/> />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> <link
rel="apple-touch-icon"
href="%PUBLIC_URL%/logo192.png"
crossorigin="use-credentials"
/>
<!-- <!--
manifest.json provides metadata used when your web app is installed on a manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
--> -->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <link
rel="manifest"
href="%PUBLIC_URL%/manifest.json"
crossorigin="use-credentials"
/>
<!-- <!--
Notice the use of %PUBLIC_URL% in the tags above. Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build. It will be replaced with the URL of the `public` folder during the build.

View File

@ -1,26 +0,0 @@
import React from 'react';
import logo from './logo.svg';
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.tsx</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;

18
src/client/App.tsx Normal file
View File

@ -0,0 +1,18 @@
import React from "react";
import { ThemeProvider } from "styled-components";
import { BrowserRouter } from "react-router-dom";
import theme from "UIKit/theme";
function App() {
return (
<div className="App">
<ThemeProvider theme={theme}>
<BrowserRouter>
<Layout />
</BrowserRouter>
</ThemeProvider>
</div>
);
}
export default App;

View File

@ -0,0 +1,3 @@
import React from "react";
export const NotFound = () => <div>404 Not Found</div>;

View File

@ -0,0 +1,5 @@
import React from "react";
const Main = () => <div>Main</div>;
export default Main;

View File

@ -0,0 +1,3 @@
import React from "react";
const Background = () => <div></div>;

121
src/client/UIKit/grid.js Normal file
View File

@ -0,0 +1,121 @@
import styled from 'styled-components';
import {
position,
space,
display,
width,
height,
maxWidth,
minWidth,
minHeight,
flex,
alignSelf,
flexDirection,
flexWrap,
justifyContent,
alignItems,
textAlign,
lineHeight,
fontWeight,
letterSpacing,
color,
zIndex,
backgroundImage,
backgroundSize,
backgroundPosition,
top,
right,
bottom,
left,
order,
maxHeight,
borders,
borderColor,
fontSize,
borderRadius,
} from 'styled-system';
import {
overflow,
opacity,
verticalAlign,
userSelect,
textTransform,
whiteSpace,
backgroundColor,
flexShrink,
fill,
} from './lib/customStyleProps';
export const BOX_STYLED_SYSTEM = [
space,
width,
height,
minWidth,
maxWidth,
minHeight,
maxHeight,
overflow,
opacity,
alignSelf,
display,
textAlign,
position,
color,
flex,
order,
top,
right,
bottom,
left,
zIndex,
backgroundColor,
backgroundImage,
backgroundSize,
backgroundPosition,
verticalAlign,
borders,
borderColor,
borderRadius,
userSelect,
whiteSpace,
justifyContent,
flexShrink,
fill,
];
export const TEXT_STYLED_SYSTEM = [
lineHeight,
fontSize,
fontWeight,
letterSpacing,
textTransform,
color,
];
export const Box = styled.div({}, ...BOX_STYLED_SYSTEM, props => props.style);
Box.displayName = 'Box';
export const Flex = styled(Box)(
{
display: 'flex',
},
flexDirection,
flexWrap,
justifyContent,
alignItems
);
Flex.displayName = 'Flex';
export const Text = styled.span(...BOX_STYLED_SYSTEM, ...TEXT_STYLED_SYSTEM);
Text.displayName = 'Text';
export const Image = styled.img`
display: block;
${display};
${position};
${width};
${height};
${flex};
${maxHeight};
${maxWidth};
`;

View File

@ -0,0 +1,46 @@
import { style } from 'styled-system';
export const overflow = style({
prop: 'overflow',
cssProperty: 'overflow',
});
export const opacity = style({
prop: 'opacity',
cssProperty: 'opacity',
});
export const verticalAlign = style({
prop: 'verticalAlign',
cssProperty: 'verticalAlign',
});
export const userSelect = style({
prop: 'userSelect',
cssProperty: 'userSelect',
});
export const textTransform = style({
prop: 'textTransform',
cssProperty: 'textTransform',
});
export const whiteSpace = style({
prop: 'whiteSpace',
cssProperty: 'whiteSpace',
});
export const backgroundColor = style({
prop: 'backgroundColor',
cssProperty: 'backgroundColor',
});
export const flexShrink = style({
prop: 'flexShrink',
cssProperty: 'flexShrink',
});
export const fill = style({
prop: 'fill',
cssProperty: 'fill',
});

34
src/client/UIKit/mq.js Normal file
View File

@ -0,0 +1,34 @@
import { css } from 'styled-components';
export const screens = {
small: 320,
mobile: 480,
tablet640: 640,
tablet: 768,
desktop900: 900,
desktop: 1024,
desktop1280: 1280,
desktop1366: 1366,
desktop1440: 1440,
desktop1680: 1680,
desktop1920: 1920,
desktop2560: 2560
};
export const query = Object.keys(screens).reduce((acc, label) => {
acc[label] = `(min-width: ${screens[label] / 16}em)`;
return acc;
}, {});
const mq = Object.keys(screens).reduce((acc, label) => {
acc[label] = (...args) =>
css`
@media ${query[label]} {
${css(...args)};
}
`;
return acc;
}, {});
export default mq;

14
src/client/UIKit/theme.js Normal file
View File

@ -0,0 +1,14 @@
import { screens } from './mq';
const ALLOWED_BREAKPOINTS = [
//'less'
'tablet',
'desktop',
'desktop1440',
'desktop1920',
'desktop2560'
];
export default {
breakpoints: ALLOWED_BREAKPOINTS.map(breakpoint => screens[breakpoint] + 'px')
};

View File

@ -0,0 +1,21 @@
import { NotFound } from "Components/Result";
import Main from "Containers/Main";
const paths = [
{
id: "Main",
name: "Главная",
route: "/",
content: Main,
exact: true,
},
{
name: 404,
route: undefined,
content: NotFound,
exact: true,
},
];
export default paths;

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

4
src/constants/urls.ts Normal file
View File

@ -0,0 +1,4 @@
export const API_PORT = 3001;
export const API_URL = "http://localhost:" + API_PORT;
export const CLIENT_DEV_URL = "http://localhost:3000";

1
src/core/index.ts Normal file
View File

@ -0,0 +1 @@
export {};

View File

@ -1,13 +1,15 @@
@import "~normalize.css";
body { body {
margin: 0; margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif; sans-serif;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
code { code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
monospace; monospace;
} }

View File

@ -1,14 +1,22 @@
import React from 'react'; import axios from "axios";
import ReactDOM from 'react-dom'; import React from "react";
import './index.css'; import ReactDOM from "react-dom";
import App from './App'; import App from "./client/App";
import * as serviceWorker from './serviceWorker'; import "./index.css";
import * as serviceWorker from "./client/serviceWorker";
import { API_URL } from "./constants/urls";
const isDevelopmentMode = process.env.NODE_ENV === "development";
if (isDevelopmentMode) {
axios.defaults.baseURL = API_URL;
}
ReactDOM.render( ReactDOM.render(
<React.StrictMode> // <React.StrictMode>
<App /> <App />,
</React.StrictMode>, // </React.StrictMode>
document.getElementById('root') document.getElementById("root")
); );
// If you want your app to work offline and load faster, you can change // If you want your app to work offline and load faster, you can change

View File

@ -0,0 +1,23 @@
import { ConnectionOptions } from "typeorm";
import Entities from "../entities";
import credentials from "./credentials";
const connectionOptions: ConnectionOptions = {
type: "mssql",
host: credentials.host,
schema: "dbo",
username: credentials.username,
password: credentials.password,
database: credentials.database,
domain: credentials.domain,
entities: Entities,
synchronize: true,
options: {
cryptoCredentialsDetails: {
minVersion: "TLSv1",
},
encrypt: false,
},
};
export default connectionOptions;

View File

@ -0,0 +1,7 @@
export default {
host: "localhost",
username: "localuser",
password: "123",
domain: undefined,
database: "",
};

View File

@ -0,0 +1,12 @@
import { Request, Response } from "express";
class UsersController {
static getUser = async (req: Request, res: Response): Promise<void> => {
res.send({
//@ts-ignore
user: req.connection.user,
});
};
}
export default UsersController;

View File

@ -0,0 +1,12 @@
import { Request, Response } from "express";
class ValuesController {
static getValue = async (req: Request, res: Response): Promise<void> => {
res.send({
a: 1,
b: 2,
});
};
}
export default ValuesController;

View File

@ -0,0 +1 @@
export default [];

66
src/server/index.ts Normal file
View File

@ -0,0 +1,66 @@
import bodyParser from "body-parser";
import compression from "compression";
import cors from "cors";
// import cookieParser from "cookie-parser";
import express from "express";
import nodeSSPI from "express-node-sspi";
import helmet from "helmet";
import morgan from "morgan";
import path from "path";
import "reflect-metadata";
import routes from "./routes";
import { CLIENT_DEV_URL, API_PORT } from "../constants/urls";
const isDevelopmentMode = process.env.NODE_ENV === "development";
const buildDir = path.join(
process.cwd(),
process.env.NODE_ENV === "development" ? "/build" : ""
);
const app = express();
// app.enable("trust proxy");
// app.set("trust proxy", "loopback");
/** AUTHENTICATION */
app.use(
nodeSSPI({
retrieveGroups: true,
})
);
/** AUTHENTICATION */
/**EXTENTIONS */
app.use(bodyParser.json());
app.use(
bodyParser.urlencoded({
extended: true,
})
);
app.use(helmet({ contentSecurityPolicy: { reportOnly: true } }));
if (isDevelopmentMode) {
app.use(cors({ origin: CLIENT_DEV_URL, credentials: true }));
}
// app.use(cookieParser());
app.use(compression());
app.use(morgan("tiny"));
/**EXTENTIONS */
/**ROUTES */
app.use("/", routes);
/**ROUTES */
/**CLIENT */
app.use(express.static(buildDir));
app.get("*", function (req, res) {
res.sendFile(path.join(buildDir, "index.html"));
});
/**CLIENT */
console.log("checking port", API_PORT);
app.listen(API_PORT, () => {
console.log(`Server now listening on port: ${API_PORT}`);
});

View File

@ -0,0 +1,10 @@
import { Router } from "express";
import values from "./values";
import users from "./users";
const routes = Router();
routes.use("/api/values", values);
routes.use("/api/users", users);
export default routes;

View File

@ -0,0 +1,8 @@
import UsersController from "../controllers/UsersController";
import { Router } from "express";
const router = Router();
router.get("/", UsersController.getUser);
export default router;

View File

@ -0,0 +1,8 @@
import ValuesController from "../controllers/ValuesController";
import { Router } from "express";
const router = Router();
router.get("/", ValuesController.getValue);
export default router;

15
src/server/tsconfig.json Normal file
View File

@ -0,0 +1,15 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "../../dist",
"noEmit": false,
"sourceMap": true,
"module": "esnext",
"strict": true,
"target": "esnext",
"moduleResolution": "node",
"noImplicitAny": false
},
"exclude": ["../../build", "../client"],
"include": ["."]
}

View File

@ -1,11 +1,7 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "es5", "target": "es5",
"lib": [ "lib": ["dom", "dom.iterable", "esnext"],
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true, "allowJs": true,
"skipLibCheck": true, "skipLibCheck": true,
"esModuleInterop": true, "esModuleInterop": true,
@ -17,9 +13,19 @@
"resolveJsonModule": true, "resolveJsonModule": true,
"isolatedModules": true, "isolatedModules": true,
"noEmit": true, "noEmit": true,
"jsx": "react" "jsx": "react",
"baseUrl": "src",
"paths": {
"common/*": ["./client/common/*"],
"Components/*": ["./client/Components/*"],
"Containers/*": ["./client/Containers/*"],
"Elements/*": ["./client/Elements/*"],
"hooks/*": ["./client/hooks/*"],
"services/*": ["./client/services/*"],
"tools/*": ["./client/tools/*"],
"UIKit/*": ["./client/UIKit/*"]
}
}, },
"include": [ "include": ["./src/**/*"],
"src" "exclude": ["src/server", "./node_modules/**/*"]
]
} }

39
webpack.config.server.js Normal file
View File

@ -0,0 +1,39 @@
const path = require("path");
const nodeExternals = require("webpack-node-externals");
module.exports = {
mode: process.env.NODE_ENV || "development",
target: "node",
devtool: "inline-source-map",
entry: { server: "./src/server/index.ts" },
output: {
path: path.resolve(__dirname, "build"),
filename: "[name].js",
},
resolve: {
extensions: [".ts", ".tsx", ".js"],
},
// don't compile node_modules
externals: [nodeExternals()],
optimization: {
splitChunks: {
chunks: "all",
},
},
module: {
rules: [
{
test: /\.tsx?$/,
use: [
{
loader: "ts-loader",
options: {
// use the tsconfig in the server directory
configFile: "src/server/tsconfig.json",
},
},
],
},
],
},
};