Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add example: with-afterjs-react-native-web-apollo #643

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion .all-contributorsrc
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,15 @@
"example",
"plugin"
]
},
{
"login": "noeljackson",
"name": "Noël Jackson",
"avatar_url": "https://avatars2.githubusercontent.com/u/441058?v=4",
"profile": "https://noeljackson.com/",
"contributions": [
"example",
]
}
]
}
}
10 changes: 10 additions & 0 deletions examples/with-afterjs-react-native-web-apollo/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
logs
*.log
npm-debug.log*
.DS_Store

coverage
node_modules
build
public/static
.env.*.local
25 changes: 25 additions & 0 deletions examples/with-afterjs-react-native-web-apollo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Razzle x After.js x React Native Web x Apollo

## How to use

Download the example [or clone the whole project](https://github.com/jaredpalmer/razzle.git):

```bash
curl https://codeload.github.com/jaredpalmer/razzle/tar.gz/master | tar -xz --strip=2 razzle-master/examples/with-afterjs-react-native-web-apollo
cd with-afterjs-react-native-web-apollo
```

Install it and run:

```bash
yarn install
yarn start
```

Change your GraphQL Endpoint:
1. Open src/apollo.config.js
1. Change api.production and api.dev constants

## Idea behind the example

This is a basic, bare-bones example of how to use Razzle with After.js, react-native-web, and Apollo.
30 changes: 30 additions & 0 deletions examples/with-afterjs-react-native-web-apollo/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "razzle-examples-with-afterjs-react-native-web-apollo",
"version": "2.0.4",
"license": "MIT",
"scripts": {
"start": "razzle start",
"build": "razzle build",
"test": "razzle test --env=jsdom",
"start:prod": "NODE_ENV=production node build/server.js"
},
"dependencies": {
"@jaredpalmer/after": "latest",
"apollo-cache-inmemory": "^1.2.2",
"apollo-client": "^2.3.2",
"apollo-link-http": "^1.5.4",
"babel-plugin-react-native-web": "^0.8.3",
"express": "^4.16.2",
"graphql": "^14.0.0-rc.2",
"graphql-tag": "^2.9.2",
"isomorphic-fetch": "^2.2.1",
"razzle": "^2.0.4",
"react": "^16.4.0",
"react-apollo": "^2.1.4",
"react-art": "^16.4.0",
"react-dom": "^16.2.0",
"react-helmet": "^5.2.0",
"react-native-web": "^0.8.3",
"react-router-dom": "^4.2.2"
}
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
User-agent: *

42 changes: 42 additions & 0 deletions examples/with-afterjs-react-native-web-apollo/razzle.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
'use strict';

module.exports = {
modify(baseConfig, { target, dev }, webpack) {
const appConfig = Object.assign({}, baseConfig);
// Since RN web takes care of CSS, we should remove it for a #perf boost
appConfig.module.rules = appConfig.module.rules
.filter(
rule =>
!(rule.test && rule.test.exec && rule.test.exec('./something.css'))
)
.filter(
rule =>
!(
rule.test &&
rule.test.exec &&
rule.test.exec('./something.module.css')
)
);

//don't load gql/graphql with file-loader
appConfig.module.rules
.find(conf => conf.loader && conf.loader.includes('file-loader'))
.exclude.push(/\.(graphql|gql)/);

// use graphql-tag
const { include } = appConfig.module.rules[0];
appConfig.module.rules.splice(1, 0, {
test: /\.(graphql|gql)$/,
include,
exclude: /node_modules/,
loader: 'graphql-tag/loader',
});

// Change the name of the server output file in production
if (target === 'node' && !dev) {
appConfig.output.filename = 'custom.js';
}

return appConfig;
},
};
19 changes: 19 additions & 0 deletions examples/with-afterjs-react-native-web-apollo/src/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';
import { StyleSheet, Text, View } from 'react-native-web';

class App extends React.Component {
render() {
return (
<View style={styles.box}>
<Text style={styles.text}>Hello, world!</Text>
</View>
);
}
}

const styles = StyleSheet.create({
box: { padding: 10 },
text: { fontWeight: 'bold' },
});

export default App;
52 changes: 52 additions & 0 deletions examples/with-afterjs-react-native-web-apollo/src/Document.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React from 'react';
import { AfterRoot, AfterData } from '@jaredpalmer/after';
import ReactDOMServer from 'react-dom/server';

export default class Document extends React.Component {
static async getInitialProps({ assets, data, renderPage }) {
const page = await renderPage();
return {
assets,
data,
...page,
};
}
render() {
const { helmet, assets, data, css, initialApolloState } = this.props;

const htmlAttrs = helmet.htmlAttributes.toComponent();
const bodyAttrs = helmet.bodyAttributes.toComponent();

return (
<html {...htmlAttrs}>
<head>
<style id="react-native-modality">{`{:focus {outline: none; }}`}</style>
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
<meta charSet="utf-8" />
<title>Razzle</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
{helmet.title.toComponent()}
{helmet.meta.toComponent()}
{helmet.link.toComponent()}
{css}
</head>
<body {...bodyAttrs}>
<AfterRoot />
<AfterData data={data} />
{process.env.NODE_ENV === 'production' ? (
<script src={assets.client.js} defer />
) : (
<script src={assets.client.js} defer crossOrigin="anonymous" />
)}
<script
dangerouslySetInnerHTML={{
__html: `window.__APOLLO_STATE__=${JSON.stringify(
initialApolloState
).replace(/</g, '\\u003c')};`,
}}
/>
</body>
</html>
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const api = {
production: 'http://0.0.0.0:5000',
dev: 'http://0.0.0.0:5000',
};
20 changes: 20 additions & 0 deletions examples/with-afterjs-react-native-web-apollo/src/apollo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { ApolloClient } from 'apollo-client';
import { createHttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
import fetch from 'isomorphic-fetch';
import { api } from './apollo.config';

export function createApolloClient() {
const ssrMode = !process.browser;
return new ApolloClient({
ssrMode,
link: createHttpLink({
uri: process.env.NODE_ENV === 'production' ? api.production : api.dev,
credentials: 'same-origin',
fetch,
}),
cache: ssrMode
? new InMemoryCache()
: new InMemoryCache().restore(window.__APOLLO_STATE__),
});
}
35 changes: 35 additions & 0 deletions examples/with-afterjs-react-native-web-apollo/src/client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react';
import { BrowserRouter } from 'react-router-dom';
import { ensureReady, After } from '@jaredpalmer/after';
import { AppRegistry } from 'react-native-web';
import { ApolloProvider } from 'react-apollo';
import { createApolloClient } from './apollo';
import routes from './routes';

const client = createApolloClient();

class App extends React.Component {
render() {
return (
<ApolloProvider client={client}>
<BrowserRouter>
<After data={this.props.data} routes={routes} />
</BrowserRouter>
</ApolloProvider>
);
}
}

ensureReady(routes).then(data => {
AppRegistry.registerComponent('App', () => App);
AppRegistry.runApplication('App', {
initialProps: {
data,
},
rootTag: document.getElementById('root'),
});
});

if (module.hot) {
module.hot.accept();
}
26 changes: 26 additions & 0 deletions examples/with-afterjs-react-native-web-apollo/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import app from './server';
import http from 'http';

const server = http.createServer(app);

let currentApp = app;

server.listen(process.env.PORT || 3000, error => {
if (error) {
console.log(error);
}

console.log('🚀 started');
});

if (module.hot) {
console.log('✅ Server-side HMR Enabled!');

module.hot.accept('./server', () => {
console.log('🔁 HMR Reloading `./server`...');
server.removeListener('request', currentApp);
const newApp = require('./server').default;
server.on('request', newApp);
currentApp = newApp;
});
}
13 changes: 13 additions & 0 deletions examples/with-afterjs-react-native-web-apollo/src/routes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react';
import { asyncComponent } from '@jaredpalmer/after';

export default [
{
path: '/',
exact: true,
component: asyncComponent({
loader: () => import('./App'), // required
Placeholder: () => <div>...LOADING...</div>, // this is optional, just returns null by default
}),
},
];
56 changes: 56 additions & 0 deletions examples/with-afterjs-react-native-web-apollo/src/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React from 'react';
import express from 'express';
import { renderToString } from 'react-dom/server';
import { ApolloProvider, getDataFromTree } from 'react-apollo';
import { createApolloClient } from './apollo';
import { AppRegistry } from 'react-native';
import { render } from '@jaredpalmer/after';
import routes from './routes';
import Document from './Document';

const assets = require(process.env.RAZZLE_ASSETS_MANIFEST);

const server = express();
server
.disable('x-powered-by')
.use(express.static(process.env.RAZZLE_PUBLIC_DIR))
.get('/*', async (req, res) => {
const customRenderer = node => {
const client = createApolloClient();

class App extends React.Component {
render() {
return <ApolloProvider client={client}>{node}</ApolloProvider>;
}
}

return getDataFromTree(App).then(async data => {
AppRegistry.registerComponent('App', () => App);
const { element, getStyleElement } = AppRegistry.getApplication('App');
const css = getStyleElement();
const initialApolloState = client.extract();
const html = renderToString(element);
return { html, initialApolloState, css };
});
};

try {
const html = await render({
req,
res,
routes,
assets,
customRenderer,
document: Document,
// Anything else you add here will be made available
// within getInitialProps(ctx)
// e.g a redux store...
customThing: 'thing',
});
res.send(html);
} catch (error) {
res.json(error);
}
});

export default server;
Loading