Skip to content

Commit

Permalink
0.9.0 (3) - add integration test with experimentally patched React ve…
Browse files Browse the repository at this point in the history
…rsion (#219)

* rename wrapped classes to original name, also export in RSC

* fix up test

* fixup build types

* comment shape

* adjust type resolution

* fixup

* adjust package shapes

* bundling adjustment: no `/index.js` in CJS

* check "package shapes"

* revert changes to examples/integration tests

* reset README changes

* add description to helper scripts

* wrap hook functionality from ApolloClient instance

* move wrappers to `QueryManager`

* update version

* remove hook exports from `@apollo/client-react-streaming`

* run test-bundle in CI

* drop hook exports

* move "integration-test" into "integration-test/nextjs"

* initialize basic vite react-ssr project

* apply prettier

* [WIP] try to set up a streaming server

* fix hydration, force faster flush

* experimental-react demo working

* add delay

* also works with prod build

* update lockfile

* global react version

* simplify a bit

* move experimental detail out to `WrappedApolloProvider`

* adjustments

* remove `@apollo/client-react-streaming/experimental-react-transport`

* alternative installation

* alternative approach

* fix non-failing tests

* fix bug that prevented rerunning hydrated queries if initialized too late

* adjust script

* more packaging foo

* fixup app rendering

* playwright test

* split up

* remove some logs

* update lockfile
  • Loading branch information
phryneas committed Mar 5, 2024
1 parent a78996e commit 80c455f
Show file tree
Hide file tree
Showing 54 changed files with 1,078 additions and 864 deletions.
22 changes: 15 additions & 7 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
- run: yarn install --immutable
- run: yarn workspaces foreach --all --include "@apollo/*" add -D -P @apollo/client@${{ matrix.version }}
- run: yarn workspaces foreach --all --include "@apollo/*" run build
- run: yarn workspaces foreach --all --include "@apollo/*" run test | tee $GITHUB_STEP_SUMMARY
- run: yarn workspaces foreach --all --include "@apollo/*" run test | tee $GITHUB_STEP_SUMMARY; exit ${PIPESTATUS[0]}
packageShapes:
name: Test bundles
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
Expand All @@ -47,7 +47,7 @@ jobs:
cache: "yarn"
- run: yarn install --immutable
- run: yarn workspaces foreach --all --include "@apollo/*" add -D -P @apollo/client@${{ matrix.version }}
- run: yarn workspaces foreach --all --include "@apollo/*" run test-bundle | tee $GITHUB_STEP_SUMMARY
- run: yarn workspaces foreach --all --include "@apollo/*" run test-bundle | tee $GITHUB_STEP_SUMMARY; exit ${PIPESTATUS[0]}
tests_playwright:
name: Run Playwright tests
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
Expand Down Expand Up @@ -80,9 +80,17 @@ jobs:
if: steps.playwright-cache.outputs.cache-hit == 'true'

- run: yarn workspaces foreach --all --include "@apollo/*" add -D -P @apollo/client@${{ matrix.version }}
- run: yarn workspace integration-test add @apollo/client@${{ matrix.version }}
- run: yarn workspaces foreach --all --include "@integration-test/*" add @apollo/client@${{ matrix.version }}

- name: Build
run: yarn workspaces foreach --all -t --include "@apollo/*" --include integration-test run build
- name: Run tests
run: yarn workspace integration-test run test | tee $GITHUB_STEP_SUMMARY
- name: Build libraries
run: yarn workspaces foreach --all -t --include "@apollo/*" --include @integration-test/nextjs run build

- name: "Next.js: Build"
run: yarn workspace @integration-test/nextjs run build
- name: "Next.js: Test"
run: yarn workspace @integration-test/nextjs run test | tee $GITHUB_STEP_SUMMARY; exit ${PIPESTATUS[0]}

- name: "Experimentally patched React: Build"
run: yarn workspace @integration-test/experimental-react run build
- name: "Experimentally patched React: Test"
run: yarn workspace @integration-test/experimental-react run test | tee $GITHUB_STEP_SUMMARY; exit ${PIPESTATUS[0]}
24 changes: 24 additions & 0 deletions integration-test/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
14 changes: 14 additions & 0 deletions integration-test/experimental-react/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">

<head>
<meta charset="UTF-8" />
<!--app-head-->
</head>

<body>
<div id="root"><!--app-html--></div>
<script type="module" src="/src/entry-client.jsx"></script>
</body>

</html>
37 changes: 37 additions & 0 deletions integration-test/experimental-react/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"name": "@integration-test/experimental-react",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"prepare": "rm -rf node_modules/@apollo/client-react-streaming; mkdir node_modules/@apollo/client-react-streaming && cp -r ../../packages/client-react-streaming/{package.json,dist} node_modules/@apollo/client-react-streaming",
"dev": "yarn prepare; node server",
"build": "yarn prepare; npm run build:client && npm run build:server",
"build:client": "vite build --ssrManifest --outDir dist/client",
"build:server": "vite build --ssr src/entry-server.jsx --outDir dist/server",
"preview": "cross-env NODE_ENV=production node server",
"build-and-test": "yarn build && yarn test",
"test": "yarn playwright test"
},
"dependencies": {
"@apollo/client": "^3.9.1",
"@apollo/client-react-streaming": "workspace:*",
"compression": "^1.7.4",
"express": "^4.18.2",
"graphql": "^16.8.1",
"graphql-tag": "^2.12.6",
"react": "npm:@phryneas/experimental-react@0.0.0-phryneas-a1c625c",
"react-dom": "npm:@phryneas/experimental-react-dom@0.0.0-phryneas-a1c625c",
"sirv": "^2.0.4"
},
"devDependencies": {
"@playwright/test": "^1.39.0",
"@tsconfig/vite-react": "^3.0.0",
"@types/react": "^18.2.55",
"@types/react-dom": "^18.2.18",
"@vitejs/plugin-react": "^4.2.1",
"cross-env": "^7.0.3",
"prettier": "^3.2.5",
"vite": "^5.0.10"
}
}
21 changes: 21 additions & 0 deletions integration-test/experimental-react/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { defineConfig } from "@playwright/test";

export default defineConfig({
webServer: {
command: "node server",
port: 3000,
timeout: 120 * 1000,
reuseExistingServer: !process.env.CI,
env: {
PORT: 3000,
NODE_ENV: "production",
},
},
timeout: 120 * 1000,
use: {
headless: true,
viewport: { width: 1280, height: 720 },
ignoreHTTPSErrors: true,
},
testDir: "src/",
});
95 changes: 95 additions & 0 deletions integration-test/experimental-react/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import express from "express";
import { renderToPipeableStream } from "react-dom/server";
import { readFile } from "node:fs/promises";

// Constants
const isProduction = process.env.NODE_ENV === "production";
const port = process.env.PORT || 5173;
const base = process.env.BASE || "/";
const ABORT_DELAY = 10000;

// Create http server
const app = express();

// Add Vite or respective production middlewares
let vite;
let bootstrapModules = [];
let assets = [];
if (!isProduction) {
const { createServer } = await import("vite");
vite = await createServer({
server: { middlewareMode: true, hmr: true },
appType: "custom",
base,
});
app.use(vite.middlewares);
} else {
const compression = (await import("compression")).default;
const sirv = (await import("sirv")).default;
app.use(compression());
app.use(base, sirv("./dist/client", { extensions: [] }));
const index = await readFile("./dist/client/index.html", "utf-8");
for (const script of index.matchAll(
/<script type="module" \w+ src="(.*)">/g
)) {
bootstrapModules.push(script[1]);
}
for (const link of index.matchAll(
/<link rel="stylesheet" \w+ href="(.*)">/g
)) {
assets.push(link[1]);
}
}

// based on https://github.com/facebook/react/blob/9cdf8a99edcfd94d7420835ea663edca04237527/fixtures/fizz/server/render-to-stream.js
app.use("*", async (req, res) => {
// The new wiring is a bit more involved.
res.socket.on("error", (error) => {
console.error("Fatal", error);
});
let didError = false;
let didFinish = false;
const App = (
await (isProduction
? import("./dist/server/entry-server.js")
: vite.ssrLoadModule("/src/entry-server.jsx"))
).render({
isProduction,
assets,
});
const { pipe, abort } = renderToPipeableStream(App, {
bootstrapModules,
onAllReady() {
// Full completion.
// You can use this for SSG or crawlers.
didFinish = true;
},
onShellReady() {
// If something errored before we started streaming, we set the error code appropriately.
res.statusCode = didError ? 500 : 200;
res.setHeader("Content-type", "text/html");
setImmediate(() => pipe(res));
},
onShellError(x) {
// Something errored before we could complete the shell so we emit an alternative shell.
res.statusCode = 500;
res.send("<!doctype><p>Error</p>");
},
onError(x) {
didError = true;
console.error(x);
},
});
// Abandon and switch to client rendering if enough time passes.
// Try lowering this to see the client recover.
setTimeout(() => {
if (!didFinish) {
abort();
}
}, ABORT_DELAY);
});

// Start http server
app.listen(port, () => {
console.log(`Server started at http://localhost:${port}`);
});
81 changes: 81 additions & 0 deletions integration-test/experimental-react/src/App.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
:root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;

color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;

font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
}

a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}

body {
margin: 0;
display: flex;
place-items: center;
min-width: 320px;
min-height: 100vh;
}

h1 {
font-size: 3.2em;
line-height: 1.1;
}

button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}

@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}


#root {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}

.card {
padding: 2em;
}
Loading

0 comments on commit 80c455f

Please sign in to comment.