Serves react app from server.

This commit is contained in:
richburdon 2020-05-23 14:36:15 -04:00
parent 94559bdf47
commit f54cd5b46a
16 changed files with 3266 additions and 178 deletions

View File

@ -5,6 +5,8 @@ Apollo GraphQL client and server using express.
## Tasks ## Tasks
- [ ] Server React app from server. - [ ] Server React app from server.
- https://www.freecodecamp.org/news/how-to-set-up-deploy-your-react-app-from-scratch-using-webpack-and-babel-a669891033d4/
- [ ] Trigger server-side commands (separate express path?) - [ ] Trigger server-side commands (separate express path?)
- [ ] Material UI. - [ ] Material UI.

View File

@ -0,0 +1,39 @@
# Console
Apollo GraphQL client.
## Usage
```bash
yarn
yarn start
```
http://localhost:8080
## Deploy
```bash
yarn build
```
This creates the following folders:
```
/dist
/es # Module imports.
/production # Production build.
```
NOTE: GQL and Production files and exported and may be used by the server.
```javascript
import QUERY_STATUS from '@dxos/console-client/gql/status.graphql';
import config from '@dxos/console-client/config.json';
...
const file = path.join(__dirname + '../../../../node_modules/@dxos/console-client/dist/production', 'index.html');
res.sendFile(file);
```

View File

@ -1,4 +1,5 @@
{ {
"public_url": "/app",
"port": 4000, "port": 4000,
"path": "/graphql" "path": "/graphql"
} }

View File

@ -3,9 +3,16 @@
"version": "1.0.0-beta.0", "version": "1.0.0-beta.0",
"description": "DxOS Console Client", "description": "DxOS Console Client",
"main": "dist/es/index.js", "main": "dist/es/index.js",
"files": [
"config.json",
"dist/production",
"gql"
],
"scripts": { "scripts": {
"analyzer": "webpack --config webpack-analyzer.config.js", "analyzer": "webpack --config webpack-analyzer.config.js",
"build": "npm run clean && babel ./src --out-dir ./dist/es --ignore \"**/*.test.js\" --source-maps inline", "build": "npm run clean && npm run build:module && npm run build:production",
"build:module": "babel ./src --out-dir ./dist/es --ignore \"**/*.test.js\" --source-maps inline",
"build:production": "PUBLIC_URL=/app webpack --mode production",
"clean": "rm -rf dist", "clean": "rm -rf dist",
"lint": "semistandard 'src/**/*.js'", "lint": "semistandard 'src/**/*.js'",
"start": "VERBOSE=true webpack-dev-server --mode development", "start": "VERBOSE=true webpack-dev-server --mode development",
@ -34,7 +41,7 @@
"@babel/core": "^7.4.5", "@babel/core": "^7.4.5",
"@babel/node": "^7.8.7", "@babel/node": "^7.8.7",
"@babel/plugin-proposal-class-properties": "^7.5.5", "@babel/plugin-proposal-class-properties": "^7.5.5",
"@babel/plugin-proposal-export-default-from": "^7.5.2", "@babel/plugin-proposal-export-default-from": "^7.8.3",
"@babel/preset-env": "^7.4.5", "@babel/preset-env": "^7.4.5",
"@babel/preset-react": "^7.0.0", "@babel/preset-react": "^7.0.0",
"babel-eslint": "^10.0.2", "babel-eslint": "^10.0.2",
@ -48,11 +55,12 @@
"eslint-plugin-react": "^7.17.0", "eslint-plugin-react": "^7.17.0",
"html-webpack-plugin": "^4.3.0", "html-webpack-plugin": "^4.3.0",
"jest": "^24.8.0", "jest": "^24.8.0",
"react-scripts": "^3.4.1",
"semistandard": "^14.2.0", "semistandard": "^14.2.0",
"webpack": "^4.41.2", "webpack": "^4.41.2",
"webpack-bundle-analyzer": "^3.6.0", "webpack-bundle-analyzer": "^3.6.0",
"webpack-dev-server": "^3.11.0",
"webpack-cli": "^3.3.10", "webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.11.0",
"webpack-merge": "^4.2.2", "webpack-merge": "^4.2.2",
"webpack-version-file-plugin": "^0.4.0" "webpack-version-file-plugin": "^0.4.0"
}, },

View File

@ -2,12 +2,15 @@
// Copyright 2020 DxOS // Copyright 2020 DxOS
// //
import { useQuery } from '@apollo/react-hooks'; import debug from 'debug';
import React from 'react'; import React from 'react';
import { useQuery } from '@apollo/react-hooks';
import QUERY_STATUS from '../gql/status.graphql'; import QUERY_STATUS from '../../gql/status.graphql';
const App = () => { const log = debug('dxos:console:client:app');
const Status = () => {
const { loading, error, data } = useQuery(QUERY_STATUS); const { loading, error, data } = useQuery(QUERY_STATUS);
if (loading) { if (loading) {
return <div>Loading...</div>; return <div>Loading...</div>;
@ -16,6 +19,8 @@ const App = () => {
return <div>Error: ${error}</div>; return <div>Error: ${error}</div>;
} }
log(JSON.stringify(data));
return ( return (
<pre> <pre>
{JSON.stringify(data, undefined, 2)} {JSON.stringify(data, undefined, 2)}
@ -23,4 +28,4 @@ const App = () => {
); );
}; };
export default App; export default Status;

View File

@ -0,0 +1,31 @@
//
// Copyright 2020 DxOS
//
import { ApolloProvider } from '@apollo/react-hooks';
import ApolloClient from 'apollo-boost';
import React from 'react';
import Status from '../components/Status';
import config from '../../config.json';
const { port, path } = config;
// TODO(burdon): Error handling for server errors.
// TODO(burdon): Authentication:
// https://www.apollographql.com/docs/react/networking/authentication/
const client = new ApolloClient({
uri: `http://localhost:${port}${path}`
});
const Main = () => {
return (
<ApolloProvider client={client}>
<Status />
</ApolloProvider>
);
};
export default Main;

View File

@ -0,0 +1,5 @@
//
// Copyright 2020 DxOS
//
export Main from './main';

View File

@ -2,30 +2,12 @@
// Copyright 2020 DxOS // Copyright 2020 DxOS
// //
import { ApolloProvider } from '@apollo/react-hooks'; import debug from 'debug';
import ApolloClient from 'apollo-boost';
import React from 'react'; import React from 'react';
import { render } from 'react-dom'; import { render } from 'react-dom';
import App from './components/App'; import Main from './containers/Main';
const PORT = 4000; debug.enable('dxos:console:client:*');
const client = new ApolloClient({
uri: `http://localhost:${PORT}/graphql`
});
// TODO(burdon): Error handling for server errors.
// TODO(burdon): Auth
// https://www.apollographql.com/docs/react/networking/authentication/
const Main = () => {
return (
<ApolloProvider client={client}>
<App />
</ApolloProvider>
);
};
render(<Main />, document.getElementById('root')); render(<Main />, document.getElementById('root'));

View File

@ -1,7 +1,7 @@
{ {
"build": { "build": {
"name": "@dxos/console-client", "name": "@dxos/console-client",
"buildDate": "2020-05-23T17:02:38.800Z", "buildDate": "2020-05-23T18:35:48.873Z",
"version": "1.0.0-beta.0" "version": "1.0.0-beta.0"
} }
} }

View File

@ -30,8 +30,9 @@ module.exports = {
fs: 'empty' fs: 'empty'
}, },
// TODO(burdon): Config production path for apollo (diff webpack config).
output: { output: {
path: `${__dirname}/dist`, path: `${__dirname}/dist/production`,
filename: '[name].bundle.js', filename: '[name].bundle.js',
publicPath: PUBLIC_URL publicPath: PUBLIC_URL
}, },

View File

@ -0,0 +1,12 @@
# Console
Apollo GraphQL client.
## Usage
```bash
yarn
yarn start
```
http://localhost:4000

View File

@ -26,6 +26,7 @@
"express-graphql": "^0.9.0", "express-graphql": "^0.9.0",
"graphql": "^15.0.0", "graphql": "^15.0.0",
"graphql-tag": "^2.10.3", "graphql-tag": "^2.10.3",
"react-dom": "^16.13.1",
"source-map-support": "^0.5.12" "source-map-support": "^0.5.12"
}, },
"devDependencies": { "devDependencies": {

View File

@ -8,28 +8,30 @@ import path from 'path';
import { ApolloServer, gql } from 'apollo-server-express'; import { ApolloServer, gql } from 'apollo-server-express';
import { print } from 'graphql/language'; import { print } from 'graphql/language';
import SCHEMA from './gql/api.graphql'; import QUERY_STATUS from '@dxos/console-client/gql/status.graphql';
import QUERY_STATUS from './gql/status.graphql'; import clientConfig from '@dxos/console-client/config.json';
import { resolvers } from './resolvers';
import config from '../config.json'; import config from '../config.json';
import { version } from '../package.json';
const log = debug('c2:src'); import SCHEMA from './gql/api.graphql';
debug.enable('c2:*');
// Resolver const log = debug('dxos:console:server');
const resolvers = {
Query: { // TODO(burdon): Config.
status: () => ({ debug.enable('dxos:console:*');
version
}) //
} // Express server.
}; //
// Server
const app = express(); const app = express();
//
// CORS // CORS
//
// import cors from 'cors' // import cors from 'cors'
// https://expressjs.com/en/resources/middleware/cors.html // https://expressjs.com/en/resources/middleware/cors.html
// https://www.prisma.io/blog/enabling-cors-for-express-graphql-apollo-server-1ef999bfb38d // https://www.prisma.io/blog/enabling-cors-for-express-graphql-apollo-server-1ef999bfb38d
@ -38,14 +40,23 @@ const app = express();
// credentials: true // credentials: true
// })); // }));
//
// React app // React app
// TODO(burdon): Create HTML file. //
// TODO(burdon): Load JS.
app.get('/app', (req,res) =>{ const { public_url } = clientConfig;
res.sendFile(path.join(__dirname + '/../../../node_modules/@dxos/console-client/dist/es/main.js'));
app.get(`${public_url}(/:filePath)?`, (req, res) => {
const { filePath = 'index.html' } = req.params;
const file = path.join(__dirname + '../../../../node_modules/@dxos/console-client/dist/production', filePath);
res.sendFile(file);
}); });
//
// Apollo Server
// https://www.apollographql.com/docs/apollo-server/api/apollo-server // https://www.apollographql.com/docs/apollo-server/api/apollo-server
//
const server = new ApolloServer({ const server = new ApolloServer({
typeDefs: SCHEMA, typeDefs: SCHEMA,
resolvers, resolvers,
@ -66,12 +77,20 @@ const server = new ApolloServer({
} }
}); });
//
// Apollo middleware
// https://www.apollographql.com/docs/apollo-server/api/apollo-server/#apolloserverapplymiddleware // https://www.apollographql.com/docs/apollo-server/api/apollo-server/#apolloserverapplymiddleware
//
server.applyMiddleware({ server.applyMiddleware({
app, app,
path: config.path path: config.path
}); });
//
// Start server
//
app.listen({ port: config.port }, () => { app.listen({ port: config.port }, () => {
log(`Running: http://localhost:${config.port}`); log(`Running: http://localhost:${config.port}`);
}); });

View File

@ -0,0 +1,21 @@
//
// Copyright 2020 DxOS
//
import debug from 'debug';
import { version } from '../package.json';
const log = debug('dxos:console:resolver');
//
// Resolver
//
export const resolvers = {
Query: {
status: () => ({
version
})
}
};

3221
yarn.lock

File diff suppressed because it is too large Load Diff