Initial commit for Apollo client/server with express.

This commit is contained in:
richburdon 2020-05-23 13:13:45 -04:00
commit 94559bdf47
23 changed files with 13359 additions and 0 deletions

67
.gitignore vendored Normal file
View File

@ -0,0 +1,67 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# next.js build output
.next
dist/
.idea/workspace.xml
out/
dist/

17
README.md Normal file
View File

@ -0,0 +1,17 @@
# Console
Apollo GraphQL client and server using express.
## Tasks
- [ ] Server React app from server.
- [ ] Trigger server-side commands (separate express path?)
- [ ] Material UI.
- [ ] Router.
- [ ] Shared config.
- [ ] IPFS request.
- [ ] Port modules with dummy resolvers.
- [x] Monorepo for client/server.
- [x] Basic React/Apollo component.

5
lerna.json Normal file
View File

@ -0,0 +1,5 @@
{
"version": "1.0.0-beta.0",
"useWorkspaces": true,
"npmClient": "yarn"
}

66
package.json Normal file
View File

@ -0,0 +1,66 @@
{
"name": "@dxos/console",
"version": "1.0.0-beta.0",
"description": "DxOS Console",
"main": "index.js",
"private": true,
"scripts": {
"build": "lerna run build",
"clean": "lerna run clean",
"lint": "lerna run lint",
"lint:fix": "lerna run lint -- --fix",
"lint:staged": "lint-staged",
"sort-package-json": "lerna exec npx sort-package-json",
"test": "lerna run test"
},
"author": "",
"license": "GPL-3.0",
"workspaces": {
"packages": [
"packages/*"
]
},
"browserslist": [
"> 5%"
],
"jest": {
"testEnvironment": "node"
},
"dependencies": {
"lerna": "^3.19.0"
},
"devDependencies": {
"babel-eslint": "^10.0.3",
"eslint": "^6.7.2",
"eslint-config-airbnb": "^18.0.0",
"eslint-loader": "^3.0.3",
"eslint-plugin-import": "^2.18.2",
"eslint-plugin-jsdoc": "^21.0.0",
"eslint-plugin-jsx-a11y": "^6.2.3",
"lint-staged": "^9.5.0",
"pre-commit": "^1.2.2",
"semistandard": "^14.2.0"
},
"eslintConfig": {
"parser": "babel-eslint",
"extends": [
"plugin:jest/recommended",
"semistandard",
"standard-jsx"
],
"plugins": [
"babel"
],
"rules": {
"babel/semi": 1
}
},
"semistandard": {
"parser": "babel-eslint",
"env": [
"jest",
"node",
"browser"
]
}
}

View File

@ -0,0 +1,14 @@
//
// Copyright 2020 DxOS
//
module.exports = {
presets: [
'@babel/preset-env',
'@babel/preset-react'
],
plugins: [
'@babel/plugin-proposal-class-properties',
'@babel/plugin-proposal-export-default-from'
]
};

View File

@ -0,0 +1,4 @@
{
"port": 4000,
"path": "/graphql"
}

View File

@ -0,0 +1,62 @@
{
"name": "@dxos/console-client",
"version": "1.0.0-beta.0",
"description": "DxOS Console Client",
"main": "dist/es/index.js",
"scripts": {
"analyzer": "webpack --config webpack-analyzer.config.js",
"build": "npm run clean && babel ./src --out-dir ./dist/es --ignore \"**/*.test.js\" --source-maps inline",
"clean": "rm -rf dist",
"lint": "semistandard 'src/**/*.js'",
"start": "VERBOSE=true webpack-dev-server --mode development",
"test": "jest --rootDir ./src --passWithNoTests --no-cache"
},
"author": "DxOS.org",
"license": "GPL-3.0",
"browserslist": [
"> 5%"
],
"jest": {
"testEnvironment": "node"
},
"dependencies": {
"@apollo/react-hooks": "^3.1.5",
"@babel/runtime": "^7.8.7",
"apollo-boost": "^0.4.9",
"debug": "^4.1.1",
"graphql-tag": "^2.10.3",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"source-map-support": "^0.5.12"
},
"devDependencies": {
"@babel/cli": "7.4.4",
"@babel/core": "^7.4.5",
"@babel/node": "^7.8.7",
"@babel/plugin-proposal-class-properties": "^7.5.5",
"@babel/plugin-proposal-export-default-from": "^7.5.2",
"@babel/preset-env": "^7.4.5",
"@babel/preset-react": "^7.0.0",
"babel-eslint": "^10.0.2",
"babel-jest": "^24.8.0",
"babel-loader": "^8.0.0",
"babel-plugin-add-module-exports": "^1.0.2",
"babel-plugin-inline-import": "^3.0.0",
"dotenv-webpack": "^1.8.0",
"eslint-plugin-babel": "^5.3.0",
"eslint-plugin-jest": "^23.13.1",
"eslint-plugin-react": "^7.17.0",
"html-webpack-plugin": "^4.3.0",
"jest": "^24.8.0",
"semistandard": "^14.2.0",
"webpack": "^4.41.2",
"webpack-bundle-analyzer": "^3.6.0",
"webpack-dev-server": "^3.11.0",
"webpack-cli": "^3.3.10",
"webpack-merge": "^4.2.2",
"webpack-version-file-plugin": "^0.4.0"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title><%= title %></title>
</head>
<body>
<div id="root"></div>
</body>
</html>

View File

@ -0,0 +1,26 @@
//
// Copyright 2020 DxOS
//
import { useQuery } from '@apollo/react-hooks';
import React from 'react';
import QUERY_STATUS from '../gql/status.graphql';
const App = () => {
const { loading, error, data } = useQuery(QUERY_STATUS);
if (loading) {
return <div>Loading...</div>;
}
if (error) {
return <div>Error: ${error}</div>;
}
return (
<pre>
{JSON.stringify(data, undefined, 2)}
</pre>
);
};
export default App;

View File

@ -0,0 +1,5 @@
{
status {
version
}
}

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 { render } from 'react-dom';
import App from './components/App';
const PORT = 4000;
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'));

View File

@ -0,0 +1,7 @@
{
"build": {
"name": "<%= package.name %>",
"buildDate": "<%= currentTime.toISOString() %>",
"version": "<%= package.version %>"
}
}

View File

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

View File

@ -0,0 +1,21 @@
//
// Copyright 2019 DxOS
//
const merge = require('webpack-merge');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const baseConfig = require('./webpack-common.config');
module.exports = merge(baseConfig, {
entry: './src/main',
plugins: [
// http://127.0.0.1:8888
// https://github.com/webpack-contrib/webpack-bundle-analyzer#options-for-plugin
new BundleAnalyzerPlugin({
openAnalyzer: false
})
]
});

View File

@ -0,0 +1,137 @@
//
// Copyright 2019 DxOS
//
const path = require('path');
const Dotenv = require('dotenv-webpack');
const VersionFile = require('webpack-version-file-plugin');
const webpack = require('webpack');
const PUBLIC_URL = process.env.PUBLIC_URL || '';
const STACK_CONFIG = process.env.CONFIG || 'default';
module.exports = {
devtool: 'eval-source-map',
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
disableHostCheck: true,
port: 8080,
watchOptions: {
ignored: /node_modules/,
aggregateTimeout: 600
}
},
node: {
fs: 'empty'
},
output: {
path: `${__dirname}/dist`,
filename: '[name].bundle.js',
publicPath: PUBLIC_URL
},
optimization: {
runtimeChunk: 'single',
splitChunks: {
chunks: 'all',
maxInitialRequests: Infinity,
minSize: 0,
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
// name: 'vendor',
name(module) {
const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];
// return `vendor-${packageName.replace('@', '')}`;
if (packageName.startsWith('@dxos')) {
return 'dxos';
}
if (packageName.startsWith('@material-ui')) {
return 'material-ui';
}
return 'vendor';
}
}
}
}
},
plugins: [
// https://www.npmjs.com/package/dotenv-webpack#properties
new Dotenv({
path: process.env.DOT_ENV || '.env'
}),
// NOTE: Must be defined below Dotenv (otherwise will override).
// https://webpack.js.org/plugins/environment-plugin
new webpack.EnvironmentPlugin({
PUBLIC_URL: String(PUBLIC_URL),
STACK_CONFIG: String(STACK_CONFIG),
DEBUG: ''
}),
// Define the build config file based on the target.
// https://webpack.js.org/plugins/normal-module-replacement-plugin
new webpack.NormalModuleReplacementPlugin(/(.*)__STACK_CONFIG__/, (resource) => {
resource.request = resource.request.replace(/__STACK_CONFIG__/, STACK_CONFIG);
}),
// https://www.npmjs.com/package/webpack-version-file-plugin
new VersionFile({
packageFile: path.join(__dirname, 'package.json'),
outputFile: path.join(__dirname, 'version.json')
}),
],
module: {
rules: [
// js
{
test: /\.js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader'
}
},
// https://www.apollographql.com/docs/react/integrations/webpack/
{
test: /\.(graphql|gql)$/,
exclude: /node_modules/,
loader: 'graphql-tag/loader',
},
// fonts
{
test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'fonts/'
}
}
]
}
]
},
resolve: {
alias: {
'@material-ui/styles': path.resolve(__dirname, '..', '..', 'node_modules/@material-ui/styles'),
'react': path.resolve(__dirname, '..', '..', 'node_modules/react'),
'react-dom': path.resolve(__dirname, '..', '..', 'node_modules/react-dom')
}
}
};

View File

@ -0,0 +1,23 @@
//
// Copyright 2019 DxOS
//
const merge = require('webpack-merge');
const HtmlWebPackPlugin = require('html-webpack-plugin');
const commonConfig = require('./webpack-common.config');
module.exports = merge(commonConfig, {
entry: './src/main',
plugins: [
// https://github.com/jantimon/html-webpack-plugin#options
new HtmlWebPackPlugin({
template: './public/index.html',
templateParameters: {
title: 'Planner'
}
})
]
});

View File

@ -0,0 +1,24 @@
//
// Copyright 2020 DxOS
//
module.exports = {
presets: [
[
'@babel/preset-env'
]
],
plugins: [
[
'babel-plugin-inline-import', {
extensions: [
'.graphql',
'.proto',
'.txt'
]
}
],
'@babel/plugin-proposal-class-properties',
'@babel/plugin-proposal-export-default-from'
]
};

View File

@ -0,0 +1,4 @@
{
"port": 4000,
"path": "/graphql"
}

View File

@ -0,0 +1,51 @@
{
"name": "@dxos/console-server",
"version": "1.0.0-beta.0",
"description": "DxOS Console Server",
"main": "index.js",
"scripts": {
"lint": "semistandard 'src/**/*.js'",
"test": "jest --rootDir ./src --passWithNoTests --no-cache",
"start": "nodemon --exec babel-node ./src/main.js"
},
"author": "DxOS.org",
"license": "GPL-3.0",
"browserslist": [
"> 5%"
],
"jest": {
"testEnvironment": "node"
},
"dependencies": {
"@babel/runtime": "^7.8.7",
"@dxos/console-client": "^1.0.0-beta.0",
"apollo-boost": "^0.4.9",
"apollo-server-express": "^2.13.1",
"debug": "^4.1.1",
"express": "^4.17.1",
"express-graphql": "^0.9.0",
"graphql": "^15.0.0",
"graphql-tag": "^2.10.3",
"source-map-support": "^0.5.12"
},
"devDependencies": {
"@babel/cli": "7.4.4",
"@babel/core": "^7.4.5",
"@babel/node": "^7.8.7",
"@babel/plugin-proposal-class-properties": "^7.5.5",
"@babel/plugin-proposal-export-default-from": "^7.5.2",
"@babel/preset-env": "^7.4.5",
"babel-eslint": "^10.0.2",
"babel-jest": "^24.8.0",
"babel-plugin-add-module-exports": "^1.0.2",
"babel-plugin-inline-import": "^3.0.0",
"eslint-plugin-babel": "^5.3.0",
"eslint-plugin-jest": "^23.13.1",
"jest": "^24.8.0",
"nodemon": "^2.0.4",
"semistandard": "^14.2.0"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -0,0 +1,7 @@
type Status {
version: String
}
type Query {
status: Status
}

View File

@ -0,0 +1,5 @@
{
status {
version
}
}

View File

@ -0,0 +1,77 @@
//
// Copyright 2020 DxOS
//
import debug from 'debug';
import express from 'express';
import path from 'path';
import { ApolloServer, gql } from 'apollo-server-express';
import { print } from 'graphql/language';
import SCHEMA from './gql/api.graphql';
import QUERY_STATUS from './gql/status.graphql';
import config from '../config.json';
import { version } from '../package.json';
const log = debug('c2:src');
debug.enable('c2:*');
// Resolver
const resolvers = {
Query: {
status: () => ({
version
})
}
};
// Server
const app = express();
// CORS
// import cors from 'cors'
// https://expressjs.com/en/resources/middleware/cors.html
// https://www.prisma.io/blog/enabling-cors-for-express-graphql-apollo-server-1ef999bfb38d
// app.use(cors({
// origin: true,
// credentials: true
// }));
// React app
// TODO(burdon): Create HTML file.
// TODO(burdon): Load JS.
app.get('/app', (req,res) =>{
res.sendFile(path.join(__dirname + '/../../../node_modules/@dxos/console-client/dist/es/main.js'));
});
// https://www.apollographql.com/docs/apollo-server/api/apollo-server
const server = new ApolloServer({
typeDefs: SCHEMA,
resolvers,
// https://www.apollographql.com/docs/apollo-server/testing/graphql-playground
// https://github.com/prisma-labs/graphql-playground#usage
// introspection: true,
playground: {
settings: {
'editor.theme': 'light'
},
tabs: [
{
endpoint: config.path,
query: print(gql(QUERY_STATUS))
}
]
}
});
// https://www.apollographql.com/docs/apollo-server/api/apollo-server/#apolloserverapplymiddleware
server.applyMiddleware({
app,
path: config.path
});
app.listen({ port: config.port }, () => {
log(`Running: http://localhost:${config.port}`);
});

12689
yarn.lock Normal file

File diff suppressed because it is too large Load Diff