Skip to content

Commit

Permalink
Installable PWA w/ simple server management plugin (#3380)
Browse files Browse the repository at this point in the history

Co-authored-by: Ted Thibodeau Jr <tthibodeau@openlinksw.com>
  • Loading branch information
acao and TallTed committed Aug 12, 2023
1 parent 7b00774 commit 46aa56e
Show file tree
Hide file tree
Showing 15 changed files with 1,890 additions and 149 deletions.
2 changes: 2 additions & 0 deletions examples/graphiql-webpack/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
This example demonstrates how to transpile your own custom ES6 GraphiQL
implementation with webpack and babel configuration.

It shows how to add plugins and even how to create a custom plugin.

There is also a no-config example with `create-react-app`:

[![Edit graphiql-example](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/graphiql-example-nhzvc)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,19 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<meta name="theme-color" content="#ffffff" />

<link rel="manifest" href="manifest.json" />
<link rel="icon" href="logo.svg" />
<title>GraphiQL Webpack Example!</title>
</head>

<body>
<style>
body {
padding: 0;
margin: 0;
min-height: 100vh;
}
#root {
height: 100vh;
}
</style>
<div id="root"></div>
</body>
</html>
8 changes: 6 additions & 2 deletions examples/graphiql-webpack/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@
"description": "A GraphiQL example with webpack and typescript",
"scripts": {
"build-demo": "webpack-cli && mkdirp ../../packages/graphiql/webpack && cp -r dist/** ../../packages/graphiql/webpack",
"start": "NODE_ENV=development webpack-dev-server"
"start": "NODE_ENV=development webpack-cli serve"
},
"dependencies": {
"@graphiql/plugin-code-exporter": "^0.3.4",
"@graphiql/plugin-explorer": "^0.3.4",
"@graphiql/toolkit": "^0.9.1",
"@graphiql/react": "^0.19.3",
"graphiql": "^3.0.5",
"graphql": "^16.4.0",
"graphql-ws": "^5.5.5",
Expand All @@ -24,6 +25,7 @@
"@babel/preset-env": "^7.20.2",
"@babel/preset-react": "^7.18.6",
"babel-loader": "^9.1.2",
"copy-webpack-plugin": "11.0.0",
"cross-env": "^7.0.2",
"css-loader": "^6.7.3",
"html-webpack-plugin": "^5.5.0",
Expand All @@ -32,6 +34,8 @@
"webpack": "5.76.0",
"webpack-cli": "^5.0.1",
"webpack-dev-server": "^4.11.1",
"worker-loader": "^2.0.0"
"worker-loader": "^2.0.0",
"workbox-webpack-plugin": "^7.0.0",
"webpack-manifest-plugin": "^5.0.0"
}
}
1 change: 1 addition & 0 deletions examples/graphiql-webpack/public/logo.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions examples/graphiql-webpack/src/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const STARTING_URL =
'https://swapi-graphql.netlify.app/.netlify/functions/index';

export const LAST_URL_KEY = 'lastURL';

export const PREV_URLS_KEY = 'previousURLs';
106 changes: 106 additions & 0 deletions examples/graphiql-webpack/src/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
body {
padding: 0;
margin: 0;
min-height: 100vh;
background-color: hsl(var(--color-base));
}
#root {
height: 100vh;
}

.plugin-title {
font-size: var(--font-size-h2);
font-weight: var(--font-weight-medium);
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 1rem;
}

.select-server--button {
background-color: hsl(var(--color-primary));
border: 0 none;
display: block;
width: 100%;
color: hsl(var(--color-base));
padding: 0.5rem;
font-size: 1rem;
margin-bottom: 1rem;
}

.select-server--button.disabled {
background-color: hsl(var(--color-base));
color: hsl(var(--color-primary));
}

.select-server--schema-error {
color: hsl(var(--color-error));
margin-top: 0.5rem;
display: block;
}

.select-server--schema-error code {
padding: 0.5rem;
background-color: hsla(var(--color-base), var(--alpha-secondary));
}

.select-server--schema-success {
color: hsl(var(--color-success));
margin-top: 0.5rem;
display: block;
}

.select-server--schema-loading {
color: hsl(var(--color-warning));
margin-top: 0.5rem;
display: block;
}

input.select-server--input {
display: block;
width: 100%;
color: hsla(var(--color-neutral), var(--alpha-secondary));
padding: 0.5rem;
background-color: hsla(var(--color-primary), var(--alpha-background-medium));
border: 0 none;
font-size: 1.05rem;
}

.select-server--input-error {
color: hsl(var(--color-error));
margin-top: 0.5rem;
display: block;
}

li.select-server--previous-entry {
display: flex;
flex-direction: row;
flex-grow: inherit;
width: 100%;
}

li.select-server--previous-entry span {
display: flex;
cursor: pointer;
padding: 0.5rem;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
flex-grow: 1;
}

li.select-server--previous-entry span:hover,
li.select-server--previous-entry button:hover {
background-color: hsl(var(--color-primary));
color: hsl(var(--color-base));
}

li.select-server--previous-entry button {
background-color: transparent;
border: hsla(var(--color-neutral), 1);
display: flex;
color: hsla(var(--color-neutral), 1);
font-size: 1rem;
cursor: pinter;
padding: 0.5rem;
}
83 changes: 62 additions & 21 deletions examples/graphiql-webpack/src/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,53 @@ import * as React from 'react';
import { createRoot } from 'react-dom/client';
import { GraphiQL } from 'graphiql';
import { explorerPlugin } from '@graphiql/plugin-explorer';
import { snippets } from './snippets';
import { getSnippets } from './snippets';
import { codeExporterPlugin } from '@graphiql/plugin-code-exporter';
import 'graphiql/graphiql.css';
import '@graphiql/plugin-explorer/dist/style.css';
import '@graphiql/plugin-code-exporter/dist/style.css';
import { createGraphiQLFetcher } from '@graphiql/toolkit';
import { useStorageContext } from '@graphiql/react';

export const STARTING_URL =
'https://swapi-graphql.netlify.app/.netlify/functions/index';

import './index.css';
import { serverSelectPlugin, LAST_URL_KEY } from './select-server-plugin';

if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker
.register('/service-worker.js')
.then(registration => {
console.log('SW registered: ', registration);
})
.catch(registrationError => {
console.log('SW registration failed: ', registrationError);
});
});
}

/**
* A manual fetcher implementation, you should probably
* just use `createGraphiQLFetcher` from `@graphiql/toolkit
* A manual fetcher implementation example
* @returns
*/
const fetcher = async (graphQLParams, options) => {
const data = await fetch(
'https://swapi-graphql.netlify.app/.netlify/functions/index',
{
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
...options.headers,
},
body: JSON.stringify(graphQLParams),
credentials: 'same-origin',
},
);
return data.json().catch(() => data.text());
};
// const fetcher = async (graphQLParams, options) => {
// const data = await fetch(
// STARTING_URL,
// {
// method: 'POST',
// headers: {
// Accept: 'application/json',
// 'Content-Type': 'application/json',
// ...options.headers,
// },
// body: JSON.stringify(graphQLParams),
// credentials: 'same-origin',
// },
// );
// return data.json().catch(() => data.text());
// };

const style = { height: '100vh' };
/**
Expand All @@ -38,15 +58,36 @@ const style = { height: '100vh' };
* then use the `useMemo` hook
*/
const explorer = explorerPlugin();
const exporter = codeExporterPlugin({ snippets });

const App = () => {
const storage = useStorageContext();

const lastUrl = storage?.get(LAST_URL_KEY);
const [currentUrl, setUrl] = React.useState(lastUrl ?? STARTING_URL);
// TODO: a breaking change where we make URL an internal state concern, and then expose hooks
// so that you can handle/set URL state internally from a plugin
// fetcher could then pass a dynamic URL config object to the fetcher internally
const exporter = React.useMemo(
() =>
codeExporterPlugin({ snippets: getSnippets({ serverUrl: currentUrl }) }),
[currentUrl],
);
const fetcher = React.useMemo(
() => createGraphiQLFetcher({ url: currentUrl }),
[currentUrl],
);
const serverSelect = React.useMemo(
() => serverSelectPlugin({ url: currentUrl, setUrl }),
[currentUrl],
);

return (
<GraphiQL
style={style}
// eslint-disable-next-line @arthurgeron/react-usememo/require-usememo
plugins={[explorer, exporter]}
plugins={[serverSelect, explorer, exporter]}
fetcher={fetcher}
shouldPersistHeaders
/>
);
};
Expand Down

0 comments on commit 46aa56e

Please sign in to comment.