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

Vite plugin for React Server Components #22952

Closed
wants to merge 94 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
94 commits
Select commit Hold shift + click to select a range
e6b5f7e
Start react-server-dom-vite as a copy of the Webpack implementation
frandiox Dec 9, 2021
6d06e0c
Remove Node register/loader in Vite
frandiox Dec 9, 2021
1357205
Add Vite Flight writer and reader
frandiox Dec 10, 2021
502adb4
Add Vite Flight plugin
frandiox Dec 10, 2021
870e149
Generate ESM version of Vite plugin dependencies
frandiox Dec 13, 2021
804699a
Allow convention filenames as server entry
frandiox Dec 13, 2021
3dc6124
Fix checking if variable is a React component
frandiox Dec 13, 2021
d15c918
Tests for Vite plugin
frandiox Dec 13, 2021
7def21a
Do not optimize lib by default
frandiox Dec 13, 2021
979a86b
Fix lint issues
frandiox Dec 13, 2021
80d0e39
Fix tests in production
frandiox Dec 13, 2021
61e2600
Use ClientProxy in main tests
frandiox Dec 13, 2021
f79d872
Do not check component name for classification
frandiox Dec 14, 2021
9081884
Cleanup eslintrc
frandiox Dec 14, 2021
d6a895a
Fix lint-build
frandiox Dec 14, 2021
d556516
fix: use component name convention to avoid wrapping hooks
frandiox Feb 2, 2022
6c5efee
fix: paths in Windows
frandiox Feb 2, 2022
490f8f2
feat: avoid bundling all client components in server
frandiox Feb 2, 2022
1c865ef
feat: use hashes for client component ids instead of absolute paths
frandiox Feb 2, 2022
d96498a
refactor: rename variables in ClientProxy
frandiox Feb 2, 2022
a96cd6e
fix: multiple exports from the same client component file
frandiox Feb 2, 2022
61f7606
fix: regexp flag in ESLint
frandiox Feb 2, 2022
a367895
fix: non-string ids, component name and linter
frandiox Feb 2, 2022
127ec64
fix: Flow ignored path
frandiox Feb 2, 2022
d356888
Merge branch 'main' into rsc-vite
frandiox Feb 2, 2022
ca00cbc
fix: allow registering components more than once in HMR
frandiox Feb 10, 2022
aa6ee98
fix: remove hardcoded src directory when finding client components
frandiox Feb 10, 2022
de32b80
Merge branch 'main' into rsc-vite
frandiox Feb 25, 2022
80d701f
Update tests and config like in Webpack
frandiox Feb 25, 2022
0371ee8
Support non-PascalCase filenames for client components
frandiox Mar 16, 2022
1540a90
Merge remote-tracking branch 'upstream/main' into rsc-vite
frandiox Mar 16, 2022
a3f715a
Switch to ReactDOMClient
frandiox Mar 16, 2022
fc44ec6
Add ServerContext properties
frandiox Mar 16, 2022
e2c7076
Remove stream.lock
frandiox Mar 23, 2022
946a766
Merge remote-tracking branch 'upstream/main' into rsc-vite
frandiox Mar 23, 2022
5404a5f
Replace isModuleReference with getModuleReference in Flight runtime
frandiox Mar 24, 2022
615449e
Wrap every object and function export in proxies
frandiox Mar 25, 2022
8da4866
Register module reference for long strings globally
frandiox Mar 25, 2022
c006f08
Check error message in isRsc utility to fix forwardRefs
frandiox Apr 1, 2022
84933d3
Fix Flow and ESLint
frandiox Apr 1, 2022
f96d221
Remove unnecessary test and code
frandiox Apr 1, 2022
b772f22
Fix Flow and ESLint (one more try)
frandiox Apr 1, 2022
2ca81aa
Fix Flow
frandiox Apr 1, 2022
b7350b8
Rename variables
frandiox Apr 1, 2022
db79789
Fix absolute path for hashes
frandiox Apr 7, 2022
3eaadde
Fix absolute path in Windows
frandiox Apr 8, 2022
a4609ac
Do not return moduleReference for strings in attemptResolveElement
frandiox Apr 8, 2022
bb2397b
Improve client component discovery
frandiox Apr 14, 2022
da787c2
Fix flow
frandiox Apr 14, 2022
902e7a8
Fix importer HMR, make hooks synchronous and change parameters
frandiox Apr 15, 2022
465af3e
Fix sync function call
frandiox Apr 15, 2022
8d2bbbd
Add special proxy getters for extending behavior
frandiox Apr 18, 2022
5f0a159
Add flight-vite fixture
frandiox May 9, 2022
7e91c67
Fix sourcemaps
frandiox May 23, 2022
3c6c151
Do not create module references for nested client components
frandiox May 25, 2022
7c0da17
Refactor variables and drop parameter
frandiox May 27, 2022
d90e49c
Add Viteception for client build and refactor code
frandiox May 27, 2022
210e67f
Update magic-string to use replace utility
frandiox May 27, 2022
fb2c712
Augment Vite module graph and improve client component bundling
frandiox May 27, 2022
a7bb131
Revert to isModuleReference
frandiox May 31, 2022
095b4f6
Support strings and functions with proxies
frandiox May 31, 2022
58696e2
Fix Windows paths
frandiox May 31, 2022
b80d02e
Add tree-shaking hints
frandiox May 31, 2022
7da680d
Merge remote-tracking branch 'upstream/main' into rsc-vite
frandiox May 31, 2022
8e1cf13
Sync changes with upstream
frandiox May 31, 2022
d5071ac
Fix race condition in unit tests
frandiox May 31, 2022
4900414
Use isModuleReference in function branch
frandiox Jun 6, 2022
ca2b978
Fix Flow
frandiox Jun 6, 2022
02707c8
Fix Flow
frandiox Jun 6, 2022
b8982cd
Add highWaterMark default
frandiox Jun 7, 2022
9336728
Resolve aliases in RSC using Rollup
frandiox Jun 9, 2022
ffc564a
Improve isRsc performance
frandiox Jun 13, 2022
b67db07
Merge remote-tracking branch 'upstream/main' into rsc-vite
frandiox Jun 15, 2022
7b64e75
Support options.identifierPrefix
frandiox Jun 15, 2022
c8a747d
Remove unnecessary throttling to fix importer cache in dev
frandiox Jun 15, 2022
4d88b35
Refactor: change parameter order
frandiox Jun 15, 2022
d046c03
Count default imports as aliases in module graph meta
frandiox Jun 15, 2022
677fc0a
Account for intermediate export renaming in module resolution
frandiox Jun 15, 2022
b612e89
Add types
frandiox Jun 15, 2022
ca10c21
Fix HMR when mixing server and client components in facade files
frandiox Jun 17, 2022
f141a3f
Dispatcher could be undefined in some weird scenarios
frandiox Jun 17, 2022
2f959b3
Fix file alias resolution
frandiox Jun 17, 2022
ed732ab
Refresh glob importer on error
frandiox Jun 21, 2022
9e25cc6
Refresh glob importer when changing server files
frandiox Jun 21, 2022
3238c03
Make the boundaries optimization optional
frandiox Jun 21, 2022
81da17d
Support re-exports in non-facade files
frandiox Jun 21, 2022
94101cb
Remove Jest line from prod build
frandiox Jun 22, 2022
70deae9
Fix HMR in client components
frandiox Jul 11, 2022
52ba115
Add env var to detect RSC builds
frandiox Aug 5, 2022
5ba81eb
Pass root to every Vite instance
frandiox Aug 16, 2022
3d5640c
Merge remote-tracking branch 'upstream/main' into rsc-vite
frandiox Aug 17, 2022
baec73c
Abort Flight
frandiox Aug 17, 2022
1295639
Fix alias resolving in some situations
frandiox Aug 17, 2022
e03c8cc
Support Vite 3
frandiox Aug 17, 2022
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 .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ module.exports = {
'packages/react-fs/**/*.js',
'packages/react-refresh/**/*.js',
'packages/react-server-dom-webpack/**/*.js',
'packages/react-server-dom-vite/**/*.js',
'packages/react-test-renderer/**/*.js',
'packages/react-debug-tools/**/*.js',
'packages/react-devtools-extensions/**/*.js',
Expand Down
1 change: 1 addition & 0 deletions ReactVersions.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const experimentalPackages = [
'react-fs',
'react-pg',
'react-server-dom-webpack',
'react-server-dom-vite',
];

module.exports = {
Expand Down
1 change: 1 addition & 0 deletions fixtures/flight-vite/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SKIP_PREFLIGHT_CHECK=true
25 changes: 25 additions & 0 deletions fixtures/flight-vite/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# production
/build
/dist
.eslintcache

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
12 changes: 12 additions & 0 deletions fixtures/flight-vite/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Flight</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/index.jsx"></script>
</body>
</html>
47 changes: 47 additions & 0 deletions fixtures/flight-vite/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"name": "flight-vite",
"type": "module",
"version": "0.1.0",
"private": true,
"dependencies": {
"@typescript-eslint/eslint-plugin": "^4.5.0",
"@typescript-eslint/parser": "^4.5.0",
"@vitejs/plugin-react": "^1.3.2",
"eslint": "^7.11.0",
"eslint-config-react-app": "^6.0.0",
"eslint-plugin-flowtype": "^5.2.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-jest": "^24.1.0",
"eslint-plugin-jsx-a11y": "^6.3.1",
"eslint-plugin-react": "^7.21.5",
"eslint-plugin-react-hooks": "^4.2.0",
"eslint-plugin-testing-library": "^3.9.2",
"express": "^4.17.1",
"sass-loader": "8.0.2",
"vite": "^2.9.8"
},
"scripts": {
"prestart": "cp -r ../../build/node_modules/* ./node_modules/",
"prebuild": "cp -r ../../build/node_modules/* ./node_modules/",
"start": "vite",
"start:prod": "node dist/server",
"build": "yarn build:client && yarn build:server",
"build:client": "vite build --outDir dist/client --manifest ",
"build:server": "vite build --outDir dist/server --ssr ./server && sed -e 's/module/commonjs/' server/package.json > dist/server/package.json"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
Empty file.
22 changes: 22 additions & 0 deletions fixtures/flight-vite/server/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export default [
{
route: '/todos',
method: 'GET',
handler(req, res) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Content-Type', 'application/json');
res.end(
JSON.stringify([
{
id: 1,
text: 'Shave yaks',
},
{
id: 2,
text: 'Eat kale',
},
])
);
},
},
];
39 changes: 39 additions & 0 deletions fixtures/flight-vite/server/index.server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import express from 'express';
import apiRoutes from './api';
import handleRSC from './rsc.server.js';
import path from 'path';

const app = express();

app.use(express.static(path.resolve(process.cwd(), 'dist/client')));

apiRoutes.forEach(({route, handler, method}) =>
app[method.toLowerCase()](route, handler)
);

app.get('/__react', handleRSC);

app.listen(3000, () => {
console.log('Flight Server listening on port 3000...');
});

app.on('error', function(error) {
if (error.syscall !== 'listen') {
throw error;
}

var bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port;

switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
});
4 changes: 4 additions & 0 deletions fixtures/flight-vite/server/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"type": "module",
"main": "./index.server.js"
}
9 changes: 9 additions & 0 deletions fixtures/flight-vite/server/rsc.server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import {renderToPipeableStream} from 'react-server-dom-vite/writer';
import React from 'react';
import App from '../src/App.server.jsx';

export default function(req, res) {
res.setHeader('Access-Control-Allow-Origin', '*');
const {pipe} = renderToPipeableStream(React.createElement(App));
pipe(res);
}
28 changes: 28 additions & 0 deletions fixtures/flight-vite/src/App.server.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import * as React from 'react';
import {fetch} from 'react-fetch';

import Container from './Container';

import {Counter} from './Counter.client';
import {Counter as Counter2} from './Counter2.client';

import ShowMore from './ShowMore.client';

export default function App() {
const todos = fetch('http://localhost:3000/todos').json();
return (
<Container>
<h1>Hello, world</h1>
<Counter />
<Counter2 />
<ul>
{todos.map(todo => (
<li key={todo.id}>{todo.text}</li>
))}
</ul>
<ShowMore>
<p>Lorem ipsum</p>
</ShowMore>
</Container>
);
}
5 changes: 5 additions & 0 deletions fixtures/flight-vite/src/Container.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import * as React from 'react';

export default function Container({children}) {
return <div>{children}</div>;
}
12 changes: 12 additions & 0 deletions fixtures/flight-vite/src/Counter.client.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import * as React from 'react';

import Container from './Container';

export function Counter() {
const [count, setCount] = React.useState(0);
return (
<Container>
<button onClick={() => setCount(c => c + 1)}>Count: {count}</button>
</Container>
);
}
3 changes: 3 additions & 0 deletions fixtures/flight-vite/src/Counter2.client.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// TODO support export * from xyz
import {Counter as _Counter} from './Counter.client';
export const Counter = _Counter;
11 changes: 11 additions & 0 deletions fixtures/flight-vite/src/ShowMore.client.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import * as React from 'react';

import Container from './Container';

export default function ShowMore({children}) {
const [show, setShow] = React.useState(false);
if (!show) {
return <button onClick={() => setShow(true)}>Show More</button>;
}
return <Container>{children}</Container>;
}
16 changes: 16 additions & 0 deletions fixtures/flight-vite/src/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as React from 'react';
import {Suspense} from 'react';
import {createRoot} from 'react-dom/client';
import {createFromFetch} from 'react-server-dom-vite';

let data = createFromFetch(fetch('http://localhost:3000/__react'));

function Content() {
return data.readRoot();
}

createRoot(document.getElementById('root')).render(
<Suspense fallback={<h1>Loading...</h1>}>
<Content />
</Suspense>
);
49 changes: 49 additions & 0 deletions fixtures/flight-vite/vite.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import {defineConfig, createServer} from 'vite';
import react from '@vitejs/plugin-react';
import rsc from 'react-server-dom-vite/plugin';
import apiRoutes from './server/api.js';

const RSC_ENTRY = '/server/rsc.server.js';

// https://vitejs.dev/config/
export default defineConfig({
ssr: {
noExternal: [/react-server-dom-vite/],
},
optimizeDeps: {
// Turn CJS deps into ESM
include: [
'react',
'react-dom/client',
// https://github.com/vitejs/vite/issues/6215
'react/jsx-runtime',
'react-fetch',
],
},
plugins: [
react(),
rsc({serverBuildEntries: [RSC_ENTRY]}),

// Custom plugin
{
name: 'my-dev-server',
configureServer(server) {
apiRoutes.forEach(({route, handler}) =>
server.middlewares.use(route, handler)
);

return () => {
server.middlewares.use(async function(req, res, next) {
if (!/^\/__react($|\?)/.test(req.originalUrl)) {
return next();
}

const {default: handleRSC} = await server.ssrLoadModule(RSC_ENTRY);

return handleRSC(req, res);
});
};
},
},
],
});
Loading