Skip to content

Commit

Permalink
feat: Test bundling packages which provide environment depended code …
Browse files Browse the repository at this point in the history
…parts (#484)

* feat: Test bundling npm packages which provide environment depended code parts

* add lock file

* fix formating

* Update e2e/fixtures/ssr-target-bundle/package.json

* fix: waku from monorepo, add test to gloabt tsconfig.e2e

* fix lockfile

---------

Co-authored-by: Daishi Kato <[email protected]>
  • Loading branch information
aheissenberger and dai-shi authored Feb 14, 2024
1 parent 6cd492c commit b702b30
Show file tree
Hide file tree
Showing 10 changed files with 282 additions and 0 deletions.
3 changes: 3 additions & 0 deletions e2e/fixtures/ssr-target-bundle/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# SSR Bundling for NPM packages with environment depended code parts

Choosing the right code based on the `export` section of the `react-textarea-autosize` module based on the backend server deployment target ('node' | 'webworker') and the client browser. No browser only code should be bundled with server only code.
23 changes: 23 additions & 0 deletions e2e/fixtures/ssr-target-bundle/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "ssr-target-bundle",
"version": "0.1.0",
"type": "module",
"private": true,
"scripts": {
"dev": "waku dev --with-ssr",
"build": "waku build --with-ssr",
"start": "waku start --with-ssr"
},
"dependencies": {
"react": "18.3.0-canary-4b2a1115a-20240202",
"react-dom": "18.3.0-canary-4b2a1115a-20240202",
"react-server-dom-webpack": "18.3.0-canary-4b2a1115a-20240202",
"react-textarea-autosize": "^8.5.3",
"waku": "workspace:*"
},
"devDependencies": {
"@types/react": "18.2.55",
"@types/react-dom": "18.2.19",
"typescript": "5.3.3"
}
}
13 changes: 13 additions & 0 deletions e2e/fixtures/ssr-target-bundle/src/components/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Textarea } from './Textarea.js';

const App = ({ name }: { name: string }) => {
return (
<div style={{ border: '3px red dashed', margin: '1em', padding: '1em' }}>
<title>Waku example</title>
<h1 data-testid="app-name">{name}</h1>
<Textarea />
</div>
);
};

export default App;
10 changes: 10 additions & 0 deletions e2e/fixtures/ssr-target-bundle/src/components/Textarea.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
'use client';
import TextareaAutosize from 'react-textarea-autosize';

export const Textarea = () => {
return (
<div>
<TextareaAutosize data-testid="textarea" defaultValue={'EMPTY'} />
</div>
);
};
28 changes: 28 additions & 0 deletions e2e/fixtures/ssr-target-bundle/src/entries.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { lazy } from 'react';
import { defineEntries } from 'waku/server';
import { Slot } from 'waku/client';

const App = lazy(() => import('./components/App.js'));

export default defineEntries(
// renderEntries
async (input) => {
return {
App: <App name={input || 'Waku'} />,
};
},
// getBuildConfig
async () => [{ pathname: '/', entries: [{ input: '' }] }],
// getSsrConfig
async (pathname) => {
switch (pathname) {
case '/':
return {
input: '',
body: <Slot id="App" />,
};
default:
return null;
}
},
);
17 changes: 17 additions & 0 deletions e2e/fixtures/ssr-target-bundle/src/main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { StrictMode } from 'react';
import { createRoot, hydrateRoot } from 'react-dom/client';
import { Root, Slot } from 'waku/client';

const rootElement = (
<StrictMode>
<Root>
<Slot id="App" />
</Root>
</StrictMode>
);

if (import.meta.env.WAKU_HYDRATE) {
hydrateRoot(document.body, rootElement);
} else {
createRoot(document.body).render(rootElement);
}
16 changes: 16 additions & 0 deletions e2e/fixtures/ssr-target-bundle/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"compilerOptions": {
"composite": true,
"strict": true,
"target": "esnext",
"downlevelIteration": true,
"esModuleInterop": true,
"module": "nodenext",
"skipLibCheck": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
"jsx": "react-jsx",
"rootDir": "./src",
"outDir": "./dist"
}
}
92 changes: 92 additions & 0 deletions e2e/ssr-target-bundle.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { expect } from '@playwright/test';
import { execSync, exec, ChildProcess } from 'node:child_process';
import { fileURLToPath } from 'node:url';
import waitPort from 'wait-port';
import { getFreePort, test } from './utils.js';
import { rm } from 'node:fs/promises';

const waku = fileURLToPath(
new URL('../packages/waku/dist/cli.js', import.meta.url),
);

const commands = [
{
command: 'dev --with-ssr',
},
{
build: 'build --with-ssr',
command: 'start --with-ssr',
},
];

const cwd = fileURLToPath(
new URL('./fixtures/ssr-target-bundle', import.meta.url),
);

for (const { build, command } of commands) {
test.describe(`ssr-target-bundle: ${command}`, () => {
let cp: ChildProcess;
let port: number;
test.beforeAll('remove cache', async () => {
await rm(`${cwd}/dist`, {
recursive: true,
force: true,
});
});

test.beforeAll(async () => {
if (build) {
execSync(`node ${waku} ${build}`, {
cwd,
});
}
port = await getFreePort();
cp = exec(`node ${waku} ${command}`, {
cwd,
env: {
...process.env,
PORT: `${port}`,
},
});
cp.stdout?.on('data', (data) => {
console.log(`${port} stdout: `, `${data}`);
});
cp.stderr?.on('data', (data) => {
console.error(`${port} stderr: `, `${data}`);
});
await waitPort({
port,
});
});

test.afterAll(async () => {
cp.kill();
});

test('add text input', async ({ page }) => {
await page.goto(`http://localhost:${port}/`);
await expect(page.getByTestId('app-name')).toHaveText('Waku');
await expect(page.getByTestId('textarea')).toHaveValue('EMPTY');
const height = await page
.getByTestId('textarea')
.evaluate((el) => el.clientHeight);
await page.getByTestId('textarea').fill('Line1\nLine2\nLine3');
const heightChanged = await page
.getByTestId('textarea')
.evaluate((el) => el.clientHeight);
expect(heightChanged).toBeGreaterThan(height);
});

test('no js environment should have first screen', async ({ browser }) => {
const context = await browser.newContext({
javaScriptEnabled: false,
});
const page = await context.newPage();
await page.goto(`http://localhost:${port}/`);
await expect(page.getByTestId('app-name')).toHaveText('Waku');
await expect(page.getByTestId('textarea')).toHaveValue('EMPTY');
await page.close();
await context.close();
});
});
}
77 changes: 77 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions tsconfig.e2e.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
},
{
"path": "./e2e/fixtures/rsc-router/tsconfig.json"
},
{
"path": "./e2e/fixtures/ssr-target-bundle/tsconfig.json"
}
]
}

0 comments on commit b702b30

Please sign in to comment.