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

fix: partial support of server-client-mixed package + chore: add react-tweet demo #384

Merged
Merged
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
1 change: 1 addition & 0 deletions packages/react-server/examples/basic/deps/mixed/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fixture package to test the same package structure as https://github.com/vercel/react-tweet
13 changes: 13 additions & 0 deletions packages/react-server/examples/basic/deps/mixed/client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"use client";

import React from "react";

export function TestClient() {
const [count, setCount] = React.useState(0);

return React.createElement(
"button",
{ onClick: () => setCount((v) => v + 1) },
"TestDepMixed(Client): " + count,
);
}
3 changes: 3 additions & 0 deletions packages/react-server/examples/basic/deps/mixed/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
declare function TestDepMixed(): Promise<JSX.Element>;

export { TestDepMixed };
17 changes: 17 additions & 0 deletions packages/react-server/examples/basic/deps/mixed/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from "react";
import { TestClient } from "./client.js";

export function TestDepMixed() {
return React.createElement(
React.Fragment,
null,
React.createElement(TestServer, null),
" ",
React.createElement(TestClient, null),
);
}

async function TestServer() {
await new Promise((resolve) => setTimeout(resolve, 50));
return React.createElement("span", null, "TestDepMixed(Server)");
}
15 changes: 15 additions & 0 deletions packages/react-server/examples/basic/deps/mixed/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "@hiogawa/test-deps-mixed",
"private": true,
"type": "module",
"exports": {
"types": "./index.d.ts",
"default": "./index.js"
},
"dependencies": {
"react": "*"
},
"peerDependencies": {
"react": "*"
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "@hiogawa/test-dep-use-client",
"name": "@hiogawa/test-deps-server-component",
"private": true,
"type": "module",
"exports": {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "@hiogawa/test-dep-use-client",
"name": "@hiogawa/test-deps-use-client",
"private": true,
"type": "module",
"exports": {
Expand Down
7 changes: 7 additions & 0 deletions packages/react-server/examples/basic/e2e/basic.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,13 @@ test("server compnoent > fixture", async ({ page }) => {
await page.getByText("TestDepServerComponent").click();
});

test("server-client-mixed package", async ({ page }) => {
await page.goto("/test/deps");
await page.getByText("TestDepMixed(Server)").click();
await page.getByRole("button", { name: "TestDepMixed(Client): 0" }).click();
await page.getByRole("button", { name: "TestDepMixed(Client): 1" }).click();
});

test("client module used at boundary and non-boundary basic", async ({
page,
}) => {
Expand Down
2 changes: 2 additions & 0 deletions packages/react-server/examples/basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@
},
"dependencies": {
"@hiogawa/react-server": "latest",
"@hiogawa/test-dep-mixed": "file:deps/mixed",
"@hiogawa/test-dep-server-component": "file:deps/server-component",
"@hiogawa/test-dep-use-client": "file:deps/use-client",
"react": "rc",
"react-dom": "rc",
"react-server-dom-webpack": "rc",
"react-tweet": "^3.2.1",
"react-wrap-balancer": "^1.1.0",
"styled-jsx": "^5.1.6"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { LayoutProps } from "@hiogawa/react-server/server";
import { NavMenu } from "../../../components/nav-menu";

export default function Layout(props: LayoutProps) {
return (
<div className="flex flex-col gap-2 p-2">
<h4 className="font-bold">Test Dependencies</h4>
<NavMenu links={["/test/deps", "/test/deps/react-tweet"]} />
{props.children}
</div>
);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { TestVirtualUseClient } from "virtual:test-use-client";
import { TestDepMixed } from "@hiogawa/test-dep-mixed";
import { TestDepServerComponent } from "@hiogawa/test-dep-server-component";
import { TestDepUseClient } from "@hiogawa/test-dep-use-client";
import {
Expand All @@ -11,7 +12,6 @@ import { Client2Provider } from "./_client2";
export default function Page() {
return (
<div className="flex flex-col items-start gap-2">
<h4 className="font-bold">Test Dependencies</h4>
<div>
<TestVirtualUseClient />
</div>
Expand All @@ -21,6 +21,9 @@ export default function Page() {
<div>
<TestDepServerComponent />
</div>
<div>
<TestDepMixed />
</div>
<div>
<Client2Provider>
<Client1 />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Tweet } from "react-tweet";

export default function Page() {
return (
<div className="flex flex-col items-start">
<a
className="text-lg font-bold antd-link"
href="https://github.com/vercel/react-tweet"
target="_blank"
>
vercel/react-tweet
</a>
<Tweet id="1725168756454785119" />
</div>
);
}
13 changes: 8 additions & 5 deletions packages/react-server/examples/basic/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,14 @@ export default defineConfig({
testVitePluginVirtual(),
],
ssr: {
// needs to inline react-wrap-balancer since its default export
// is not recognized by NodeJS. See:
// node -e 'import("react-wrap-balancer").then(console.log)'
// https://publint.dev/[email protected]
noExternal: ["react-wrap-balancer"],
noExternal: [
// cjs default export. try
// node -e 'import("react-wrap-balancer").then(console.log)'
// https://publint.dev/[email protected]
"react-wrap-balancer",
// css import
"react-tweet",
],
},
});

Expand Down
8 changes: 8 additions & 0 deletions packages/react-server/src/features/client-component/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,14 @@ export function vitePluginServerUseClient({
const useClientPlugin: Plugin = {
name: vitePluginServerUseClient.name,
async transform(code, id, _options) {
// when using external library's server component includes client reference,
// it will end up here with deps optimization hash `?v=` resolved by server module graph.
// this is not entirely free from double module issue,
// but it allows handling simple server-client-mixed package such as react-tweet.
// cf. https://github.com/hi-ogawa/vite-plugins/issues/379
if (!manager.buildType && id.includes("?v=")) {
id = id.split("?v=")[0]!;
}
manager.serverIds.add(id);
manager.clientReferenceMap.delete(id);
if (!code.includes(USE_CLIENT)) {
Expand Down
Loading