Commit 9a25a8ca authored by jnsone11's avatar jnsone11
Browse files

add ssr

parent 54bab7b0
......@@ -5,9 +5,9 @@
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build" : "docker build -t workshop/graphqlapi .",
"build" : "docker build --no-cache -t workshop/graphqlapi .",
"showImages" : "docker images",
"start" : "node_modules/.bin/postgraphile -c postgresql://postgres@backend-database-postgresql/postgres -s workshop -w"
"start" : "node_modules/.bin/postgraphile -o -c postgresql://postgres@backend-database-postgresql/postgres -s workshop -w"
},
"author": "Jens Neuse <jens.neuse@gmx.de>",
"license": "ISC",
......
webpackJsonp([0],{16:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const l=n(0),o=n(18),r=n(28);o.hydrate(l.createElement(()=>l.createElement(r.default,null),null),document.getElementById("react-root"))},28:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const l=n(0),o=n(0);t.default=class extends o.Component{render(){return l.createElement("div",null,"Hello World !!!")}}},5:function(e,t,n){n(6),e.exports=n(16)}},[5]);
\ No newline at end of file
webpackJsonp([0],{240:function(e,t,l){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const n=l(0),r=l(0),a=l(24);t.default=class extends r.Component{render(){return n.createElement("div",null,n.createElement("h1",null,"Header"),n.createElement("ul",null,n.createElement("li",null,n.createElement(a.Link,{to:"/"},"Main")),n.createElement("li",null,n.createElement(a.Link,{to:"/authors"},"Authors")),n.createElement("li",null,n.createElement(a.Link,{to:"/articles"},"Articles"))))}}},241:function(e,t,l){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const n=l(0),r=l(0);t.default=class extends r.Component{render(){return n.createElement("div",null,n.createElement("p",null,"Main"))}}},242:function(e,t,l){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const n=l(0),r=l(0),a=l(77),o=l(31),u=a.default`
query getAllAuthors {
allAuthors {
totalCount
nodes {
nodeId
id
name
bornIn
articlesByAuthorId {
totalCount
}
}
}
}
`;t.default=class extends r.Component{render(){return n.createElement("div",null,n.createElement("p",null,"Authors"),n.createElement(o.Query,{query:u},e=>e.loading?n.createElement("p",null,"Loading..."):e.error?n.createElement("p",null,e.error.message):n.createElement("ol",null,e.data.allAuthors.nodes.map(e=>n.createElement("li",null,n.createElement("h3",null,e.name),n.createElement("h4",null,e.bornIn),n.createElement("p",null,"Total Articles Count: ",e.articlesByAuthorId.totalCount))))))}}},252:function(e,t,l){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const n=l(0),r=l(0),a=l(77),o=l(31),u=a.default`
query getAllArticles {
allArticles {
totalCount
nodes {
nodeId
id
title
description
content
authorId
authorByAuthorId {
id
}
}
}
}
`;t.default=class extends r.Component{render(){return n.createElement("div",null,n.createElement(o.Query,{query:u},e=>e.loading?n.createElement("div",null,"Loading..."):e.error?n.createElement("div",null,"Error: ",e.error.message):n.createElement("div",null,n.createElement("p",null,"Articles"),n.createElement("ol",null,e.data.allArticles.nodes.map(e=>n.createElement("li",{key:e.nodeId},n.createElement("h3",null,e.title),e.description&&n.createElement("p",null,e.description)||n.createElement("p",null,"No description available")))))))}}},45:function(e,t,l){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const n=l(0),r=l(0),a=l(24),o=l(240),u=l(241),c=l(242),d=l(252);t.default=class extends r.Component{render(){return n.createElement("div",null,n.createElement(o.default,null),n.createElement(a.Route,{exact:!0,path:"/",component:u.default}),n.createElement(a.Route,{exact:!0,path:"/authors",component:c.default}),n.createElement(a.Route,{exact:!0,path:"/articles",component:d.default}))}}},82:function(e,t,l){l(83),e.exports=l(92)},92:function(e,t,l){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const n=l(0),r=l(94),a=l(24),o=l(31),u=l(200),c=l(218),d=l(231),s=new c.default({link:new u.default({uri:"/graphql"}),cache:(new d.InMemoryCache).restore(window.__APOLLO_STATE__)}),i=l(45),m=document.getElementById("react-root"),E=e=>n.createElement(o.ApolloProvider,{client:s},n.createElement(a.BrowserRouter,null,n.createElement(e,null)));e.hot.accept(45,()=>{Promise.resolve().then(()=>l(45)).then(e=>{r.hydrate(E(e.default),m)})}),r.hydrate(E(i.default),m)}},[82]);
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
/* tslint:disable */
// This file was automatically generated and should not be edited.
export interface getAllArticlesQuery {
// Reads and enables pagination through a set of `Article`.
allArticles: {
__typename: "ArticlesConnection",
// The count of *all* `Article` you could get from the connection.
totalCount: number | null,
// A list of `Article` objects.
nodes: Array< {
__typename: "Article",
// A globally unique identifier. Can be used in various places throughout the system to identify this single value.
nodeId: string,
id: string,
title: string | null,
description: string | null,
content: string | null,
authorId: string,
// Reads a single `Author` that is related to this `Article`.
authorByAuthorId: {
__typename: "Author",
id: string,
} | null,
} | null >,
} | null,
};
export interface getAllAuthorsQuery {
// Reads and enables pagination through a set of `Author`.
allAuthors: {
__typename: "AuthorsConnection",
// The count of *all* `Author` you could get from the connection.
totalCount: number | null,
// A list of `Author` objects.
nodes: Array< {
__typename: "Author",
// A globally unique identifier. Can be used in various places throughout the system to identify this single value.
nodeId: string,
id: string,
name: string,
bornIn: string | null,
// Reads and enables pagination through a set of `Article`.
articlesByAuthorId: {
__typename: "ArticlesConnection",
// The count of *all* `Article` you could get from the connection.
totalCount: number | null,
},
} | null >,
} | null,
};
This diff is collapsed.
......@@ -7,23 +7,39 @@
"test": "echo \"Error: no test specified\" && exit 1",
"build-server": "webpack --config webpack.server.config.js --progress",
"build-client": "webpack --config webpack.client.config.js --progress",
"start": "node ./dist/server/server.js"
"start": "node ./dist/server/server.js",
"introspect-graphql-schema": "./node_modules/.bin/apollo-codegen introspect-schema http://localhost:8080/graphql --output schema.json",
"generate-graphql-ts": "./node_modules/.bin/apollo-codegen generate **/*.tsx --addTypename --schema schema.json --target typescript --output graphql-types.ts"
},
"author": "",
"license": "ISC",
"dependencies": {
"@types/graphql": "^0.12.3",
"@types/react": "^16.0.35",
"@types/react-dom": "^16.0.3",
"@types/react-router-dom": "^4.2.3",
"apollo-cache-inmemory": "^1.1.5",
"apollo-client": "^2.2.1",
"apollo-link-http": "^0.6.1-beta.6",
"express": "^4.16.2",
"graphql": "^0.12.3",
"graphql-tag": "^2.6.1",
"node-fetch": "^2.0.0-alpha.9",
"postgraphile": "^4.0.0-alpha2.30",
"react": "^16.2.0",
"react-apollo": "^2.0.4",
"react-dom": "^16.2.0",
"typescript": "^2.6.2"
"react-router-dom": "^4.2.2",
"typescript": "^2.6.2",
"whatwg-fetch": "^2.0.3"
},
"devDependencies": {
"@types/express": "^4.11.0",
"@types/node": "^9.4.0",
"@types/node-fetch": "^1.6.7",
"@types/react-dom": "^16.0.3",
"@types/systemjs": "^0.20.6",
"@types/webpack-env": "^1.13.4",
"apollo-codegen": "^0.18.3",
"awesome-typescript-loader": "^3.4.1",
"extract-text-webpack-plugin": "^3.0.2",
"react-hot-loader": "^3.1.3",
......
This diff is collapsed.
import * as React from 'react'
import {Component} from 'react'
import {hydrate} from 'react-dom'
import {BrowserRouter as Router} from 'react-router-dom'
import { ApolloProvider } from 'react-apollo';
import HttpLink from "apollo-link-http";
import ApolloClient from "apollo-client";
import { InMemoryCache } from "apollo-cache-inmemory";
declare let window: {
__APOLLO_STATE__: any
}
const apolloClient = new ApolloClient({
link: new HttpLink({ uri: "/graphql" }),
cache: new InMemoryCache().restore(window.__APOLLO_STATE__)
});
import Routes from '../common/routes'
......@@ -14,9 +28,11 @@ declare let module: {
const render = (Routings: React.ComponentClass) => {
return (
<div>
<ApolloProvider client={apolloClient}>
<Router>
<Routings/>
</div>
</Router>
</ApolloProvider>
)
}
......
import * as React from 'react'
import {Component} from 'react'
import gql from 'graphql-tag';
import {getAllArticlesQuery} from '../../../graphql-types'
import { graphql } from 'react-apollo';
const query = gql`
query getAllArticles {
allArticles {
totalCount
nodes {
nodeId
id
title
description
content
authorId
authorByAuthorId {
id
}
}
}
}
`
interface Props {
data: getAllArticlesQuery
}
class AllArticles extends Component<Props> {
render() {
return (
<div>
{JSON.stringify(this.props)}
</div>
);
}
}
export default graphql<getAllArticlesQuery,{},Props>(query)(AllArticles);
\ No newline at end of file
import * as React from 'react'
import gql from 'graphql-tag';
import {graphql,QueryProps} from 'react-apollo'
import {getAllAuthorsQuery} from '../../../graphql-types';
const query = gql`
query getAllAuthors {
allAuthors {
totalCount
nodes {
nodeId
id
name
bornIn
articlesByAuthorId {
totalCount
}
}
}
}
`;
interface Props {
data: getAllAuthorsQuery
}
class AllAuthors extends React.Component<Props> {
render() {
return (
<div>
<p>{JSON.stringify(this.props)}</p>
</div>
)
}
}
export default graphql<getAllAuthorsQuery,{},Props>(query)(AllAuthors);
\ No newline at end of file
import * as React from 'react'
import {Component} from 'react'
import {Link} from 'react-router-dom'
class Header extends Component {
render() {
return (
<div>
<h1>Header</h1>
<ul>
<li>
<Link to="/">Main</Link>
</li>
<li>
<Link to="/authors">Authors</Link>
</li>
<li>
<Link to="/articles">Articles</Link>
</li>
</ul>
</div>
)
}
}
export default Header;
\ No newline at end of file
import * as React from 'react'
import {Component} from 'react'
class Home extends Component {
render(){
return (
<div>
<p>
Main
</p>
</div>
)
}
}
export default Home;
\ No newline at end of file
import * as React from 'react'
import {Component} from 'react'
import {Route} from 'react-router-dom'
import Header from './components/header'
import Main from './components/home'
import AllAuthors from './components/allAuthors'
import AllArticles from './components/allArticles'
class Routes extends Component {
render(){
return (
<div>
<div>Hello World!!</div>
<div>OK OK</div>
return <div>
<Header/>
<Route exact path="/" component={Main} />
<Route exact path="/authors" component={AllAuthors}/>
<Route exact path="/articles" component={AllArticles}/>
</div>
)
}
}
......
import * as express from 'express'
import {postgraphile} from 'postgraphile'
import render from './serverRender'
const IS_PRODUCTION: boolean = process.env.NODE_ENV === 'production';
......@@ -8,6 +8,11 @@ const HOST: string = 'localhost';
const server = express();
server.use(postgraphile('postgres://postgres@localhost:15432/postgres','workshop',{
graphiql: true,
graphqlRoute: '/graphql'
}));
if (!IS_PRODUCTION){
const webpackDevMiddleware = require("webpack-dev-middleware");
......@@ -24,6 +29,9 @@ if (!IS_PRODUCTION){
}
server.get('*', (req: express.Request, res: express.Response) => {
const context = {};
render(req.url).then((html: string) => {
res.status(200);
res.end(html);
......
import * as React from "react";
//import {renderToString} from "react-dom/server"
import Routes from '../common/routes'
import ApolloClient from "apollo-client";
import * as fetch from 'node-fetch'
import { ApolloProvider, renderToStringWithData} from 'react-apollo';
import HttpLink from 'apollo-link-http';
import { StaticRouter } from 'react-router';
import { InMemoryCache } from "apollo-cache-inmemory";
import {renderToString} from 'react-dom/server'
export default function(url: string) : Promise<string> {
const link = new HttpLink({
uri: 'http://localhost:8080/graphql'
});
const client = new ApolloClient({
ssrMode: true,
link,
cache: new InMemoryCache()
});
const context = {};
const App = (
<div>
<ApolloProvider client={client}>
<StaticRouter location={url} context={context}>
<Routes/>
</div>
</StaticRouter>
</ApolloProvider>
);
//const applicationHTML = renderToString(App);
console.log(context);
return new Promise((resolve: (result:any )=> void,reject: (error:any) => void ) => {
renderToStringWithData(App)
.then((reactHtmlContent) => {
const initialState = JSON.stringify(client.extract()).replace(/</g, '\\u003c');
return new Promise((resolve,reject) => {
resolve(`<!DOCTYPE html>
<html>
<head>
<link rel="apple-touch-icon" sizes="57x57" href="/icon.png" />
</head>
<body>
<div id="react-root"></div>
<div id="react-root">${reactHtmlContent}</div>
<script>window.__APOLLO_STATE__=${initialState}</script>
<script type="text/javascript" src="/vendor.js"></script>
<script type="text/javascript" src="/client.js"></script>
</body>
</html>`);
}).catch((reason:any) => {
reject(reason);
});
});
}
\ No newline at end of file
declare module 'lodash.flowright';
\ No newline at end of file
declare module 'postgraphile'
\ No newline at end of file
......@@ -8,28 +8,33 @@ const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPl
const IS_PRODUCTION = process.env.NODE_ENV === 'production';
console.log('IS_PRODUCTION: ',IS_PRODUCTION);
console.log('IS_PRODUCTION: ', IS_PRODUCTION);
let plugins = [
new webpack.optimize.CommonsChunkPlugin({
new webpack
.optimize
.CommonsChunkPlugin({
name: 'vendor',
filename: 'vendor.js',
minChunks: function (module, count) {
return module.context && module.context.indexOf("node_modules") !== -1;
return module.context && module
.context
.indexOf("node_modules") !== -1;
}
}),
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('production'),
'NODE_ENV': JSON.stringify('production')
}
}),
new webpack.optimize.AggressiveMergingPlugin(),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack
.optimize
.AggressiveMergingPlugin(),
new webpack
.optimize
.OccurrenceOrderPlugin(),
new UglifyJSPlugin(),
new webpack.LoaderOptionsPlugin({
minimize: true,
debug: false
}),
new webpack.LoaderOptionsPlugin({minimize: true, debug: false}),
/*new CompressionPlugin({
asset: "[path].gz[query]",
algorithm: "gzip",
......@@ -40,35 +45,31 @@ let plugins = [
];
if (IS_PRODUCTION) {
plugins.push(new BundleAnalyzerPlugin({
analyzerMode: 'static'
}));
plugins.push(new BundleAnalyzerPlugin({analyzerMode: 'static'}));
} else {
plugins.push(new webpack.HotModuleReplacementPlugin());
plugins.push(new webpack.NoEmitOnErrorsPlugin());
}
const loaders = IS_PRODUCTION ?
[
const loaders = IS_PRODUCTION
? [
{
loader: 'awesome-typescript-loader'
}
] :
[
]
: [
{
loader: 'react-hot-loader/webpack'
},
{
}, {
loader: 'awesome-typescript-loader'
}
];
module.exports = {
entry: IS_PRODUCTION ? [
'./src/client/client.tsx'
] : [
'webpack-hot-middleware/client',
'./src/client/client.tsx'
entry: IS_PRODUCTION
? ['./src/client/client.tsx']
: [
'webpack-hot-middleware/client', './src/client/client.tsx'
],
output: {
filename: 'client.js',
......@@ -88,15 +89,22 @@ module.exports = {
module: {
rules: [
// All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'.
// All files with a '.ts' or '.tsx' extension will be handled by
// 'awesome-typescript-loader'.
{
test: /\.tsx?$/,
exclude: /(node_modules|bower_components)/,
use: loaders
},
// All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
{enforce: "pre", test: /\.js$/, loader: "source-map-loader"}
// All output '.js' files will have any sourcemaps re-processed by
// 'source-map-loader'.
{
enforce: 'pre',
test: /\.js$/,
loader: "source-map-loader",
exclude: [/node_modules/, /build/, /__test__/]
}
]
}
};
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment