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

0.9.0 (3) - add integration test with experimentally patched React version #219

Merged
merged 46 commits into from
Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
9eaac4f
rename wrapped classes to original name, also export in RSC
phryneas Feb 21, 2024
f1535a6
fix up test
phryneas Feb 21, 2024
10817a5
fixup build types
phryneas Feb 21, 2024
ad9022a
comment shape
phryneas Feb 21, 2024
abe6c96
adjust type resolution
phryneas Feb 21, 2024
43c1ef2
fixup
phryneas Feb 21, 2024
3d61cc1
adjust package shapes
phryneas Feb 27, 2024
835f780
bundling adjustment: no `/index.js` in CJS
phryneas Feb 28, 2024
41a9ea7
check "package shapes"
phryneas Feb 28, 2024
e0919aa
revert changes to examples/integration tests
phryneas Feb 28, 2024
b330f7c
reset README changes
phryneas Feb 28, 2024
19a4a4f
add description to helper scripts
phryneas Feb 28, 2024
1b3d70e
Merge branch 'main' into pr/unify-exports
phryneas Feb 28, 2024
2ae052b
wrap hook functionality from ApolloClient instance
phryneas Feb 23, 2024
ac239d9
move wrappers to `QueryManager`
phryneas Feb 23, 2024
12b6ff3
update version
phryneas Feb 27, 2024
7b6da7e
remove hook exports from `@apollo/client-react-streaming`
phryneas Feb 28, 2024
9fe9582
run test-bundle in CI
phryneas Feb 28, 2024
b81176c
Merge branch 'pr/unify-exports' into pr/wrapHooks-2
phryneas Feb 28, 2024
2d7c8d9
drop hook exports
phryneas Feb 28, 2024
9410422
move "integration-test" into "integration-test/nextjs"
phryneas Feb 14, 2024
b523520
initialize basic vite react-ssr project
phryneas Feb 14, 2024
fbbd152
apply prettier
phryneas Feb 14, 2024
0c0b47b
[WIP] try to set up a streaming server
phryneas Feb 16, 2024
70b970b
fix hydration, force faster flush
phryneas Feb 16, 2024
91beaa2
experimental-react demo working
phryneas Feb 16, 2024
a66a502
add delay
phryneas Feb 16, 2024
1db1623
also works with prod build
phryneas Feb 16, 2024
c62ec33
update lockfile
phryneas Feb 16, 2024
7f44046
global react version
phryneas Feb 20, 2024
ef3d2ef
simplify a bit
phryneas Feb 20, 2024
b0c0f78
move experimental detail out to `WrappedApolloProvider`
phryneas Feb 20, 2024
66af26f
adjustments
phryneas Feb 28, 2024
101958c
remove `@apollo/client-react-streaming/experimental-react-transport`
phryneas Feb 28, 2024
85c32a9
alternative installation
phryneas Feb 28, 2024
8f6b8d5
alternative approach
phryneas Feb 29, 2024
6fe73df
fix non-failing tests
phryneas Feb 29, 2024
8f36c3f
fix bug that prevented rerunning hydrated queries if initialized too …
phryneas Feb 29, 2024
131199b
adjust script
phryneas Feb 29, 2024
48ceaad
more packaging foo
phryneas Feb 29, 2024
f79953a
fixup app rendering
phryneas Feb 29, 2024
c6196aa
playwright test
phryneas Feb 29, 2024
a5d525f
split up
phryneas Feb 29, 2024
c1a0f20
Merge remote-tracking branch 'origin/main' into pr/integration-test-e…
phryneas Mar 5, 2024
9d22153
remove some logs
phryneas Mar 5, 2024
6b4bc5f
update lockfile
phryneas Mar 5, 2024
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
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",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is necessary so it doesn't pick up the react folder from packages/client-react-streaming/node_modules and mixes two react versions.

"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]);
}
}
Comment on lines +18 to +42
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this is meant to be more of a "demo" (ish), but any chance we could flip the conditional here? I always find it easier with if/else to use the positive connotation first.

Rather than:

if (!isProduction) {
  // other envs
} else {
  // production builds
}

Use this:

if (isProduction) {
  // production stuff
} else {
  // other environments
}

This keeps the "production" configuration closer to the conditional test for it, rather than breaking it apart.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is based on the Vite React SSR template and I'm trying to keep the diff as small as possible, so while I agree and would really like to swap it, it's probably better we don't :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't realize these were copy-pasted so makes sense! Thanks for pointing me to that.


// 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