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

feat: create vite-plugin-simple-hmr #157

Merged
merged 48 commits into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
071d7aa
chore(deps): use vite runtime for vite-plugin-ssr-middleware
hi-ogawa Jan 21, 2024
2157089
wip
hi-ogawa Jan 26, 2024
d3ef170
refactor: minor
hi-ogawa Jan 26, 2024
e88a485
chore: release
hi-ogawa Jan 26, 2024
41857d8
Merge branch 'feat-vite-runtime-ssr-middleware' into feat-vite-plugin…
hi-ogawa Jan 26, 2024
dacaca1
chore: setup example
hi-ogawa Jan 26, 2024
64e08e2
chore: move code
hi-ogawa Jan 26, 2024
61d910b
test: add test
hi-ogawa Jan 26, 2024
d5d230a
chore: typing deps
hi-ogawa Jan 26, 2024
3ebc90b
Merge branch 'main' into feat-vite-runtime-ssr-middleware
hi-ogawa Jan 26, 2024
a74e48d
Merge branch 'feat-vite-runtime-ssr-middleware' into feat-vite-plugin…
hi-ogawa Jan 26, 2024
342733c
chore: fix merge
hi-ogawa Jan 26, 2024
0b1e739
chore: simplify example
hi-ogawa Jan 26, 2024
c5c28cd
chore: comment
hi-ogawa Jan 26, 2024
febfb40
feat: analyze ast
hi-ogawa Jan 26, 2024
c2f2f8c
chore: lock file
hi-ogawa Jan 26, 2024
166f7bc
chore: comment
hi-ogawa Jan 26, 2024
92bd657
chore: comment
hi-ogawa Jan 26, 2024
f5ddd64
Merge branch 'main' into feat-vite-runtime-ssr-middleware
hi-ogawa Jan 31, 2024
0b4744c
chore: fix deps
hi-ogawa Jan 31, 2024
079e4c9
feat: ability to disable ssr hmr
hi-ogawa Jan 31, 2024
818e95d
fix: fix manual full-reload
hi-ogawa Jan 31, 2024
e3d3271
chore: comment
hi-ogawa Jan 31, 2024
3533772
chore: comment
hi-ogawa Jan 31, 2024
e3013f3
Merge branch 'feat-vite-runtime-ssr-middleware' into feat-vite-plugin…
hi-ogawa Jan 31, 2024
15c41ba
chore: comment
hi-ogawa Jan 31, 2024
4e9bcd4
wip: use magic-string
hi-ogawa Feb 2, 2024
edff769
Merge branch 'feat-vite-runtime-ssr-middleware' into feat-vite-plugin…
hi-ogawa Feb 2, 2024
0d8e437
chore: vite beta
hi-ogawa Feb 2, 2024
a571b34
chore: lockfile
hi-ogawa Feb 2, 2024
721d0d6
chore: tweak example
hi-ogawa Feb 2, 2024
c56790b
feat: source map
hi-ogawa Feb 2, 2024
ee556b3
chore: only example
hi-ogawa Feb 2, 2024
15f346f
chore: loosen re-export
hi-ogawa Feb 2, 2024
8061fa0
chore: comment
hi-ogawa Feb 2, 2024
b41923c
chore: hires false
hi-ogawa Feb 2, 2024
29d7053
Merge branch 'main' into feat-vite-runtime-ssr-middleware
hi-ogawa Feb 9, 2024
4023cc4
chore: rename
hi-ogawa Feb 9, 2024
32c9ab4
chore: no hmr
hi-ogawa Feb 9, 2024
af09dee
chore: release
hi-ogawa Feb 9, 2024
bf0b0ff
chore: revert lockfile
hi-ogawa Feb 9, 2024
a0fc2bf
Merge branch 'main' into feat-vite-runtime-ssr-middleware
hi-ogawa Feb 9, 2024
fcbf2f6
Merge branch 'feat-vite-runtime-ssr-middleware' into feat-vite-plugin…
hi-ogawa Feb 9, 2024
44e2e7e
chore: fix merge
hi-ogawa Feb 9, 2024
c36c01c
chore: rename
hi-ogawa Feb 9, 2024
2c8ec51
chore: typo
hi-ogawa Feb 9, 2024
209436a
refactor: move code
hi-ogawa Feb 9, 2024
5eab4e0
chore: pre
hi-ogawa Feb 9, 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: 22 additions & 0 deletions packages/vite-plugin-simple-hmr/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# vite-plugin-simple-hmr

Simple HMR to reassign all exports, which can be useful for [SSR HMR](https://github.com/vitejs/vite/pull/12165) to accompany with React plugin's client HMR.

## example

See [./examples/react](./examples/react).

```tsx
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { vitePluginSimpleHmr } from "@hiogawa/vite-plugin-simple-hmr";

export default defineConfig({
plugins: [
react(),
vitePluginSimpleHmr({
include: ["**/*.tsx"],
}),
],
});
```
3 changes: 3 additions & 0 deletions packages/vite-plugin-simple-hmr/examples/react/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```sh
pnpm -C packages/vite-plugin-hmr/examples/react dev
```
12 changes: 12 additions & 0 deletions packages/vite-plugin-simple-hmr/examples/react/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.0" />
<title>vite-plugin-hmr-ssr-react</title>
</head>
<body>
<div id="root"><!--@INJECT_SSR@--></div>
<script type="module" src="/src/entry-client.tsx"></script>
</body>
</html>
19 changes: 19 additions & 0 deletions packages/vite-plugin-simple-hmr/examples/react/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "@hiogawa/vite-plugin-hmr-example-react",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite dev"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@hiogawa/vite-plugin-simple-hmr": "workspace:*",
"@hiogawa/vite-plugin-ssr-middleware": "workspace:*",
"@types/react": "18.2.12",
"@types/react-dom": "18.2.5"
}
}
23 changes: 23 additions & 0 deletions packages/vite-plugin-simple-hmr/examples/react/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { useState } from "react";
import { AppDep1, AppDep2 } from "./AppDep";
import { AppDepDep } from "./AppDepDep";

export function App() {
const [count, setCount] = useState(0);

return (
<>
<h1>ssr + hmr + react</h1>
<div>
<button onClick={() => setCount((count) => count + 1)}>
count is {count}
</button>
</div>
<div>
<AppDep1 />
<AppDep2 />
<AppDepDep />
</div>
</>
);
}
13 changes: 13 additions & 0 deletions packages/vite-plugin-simple-hmr/examples/react/src/AppDep.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { AppDepDep } from "./AppDepDep";

export function AppDep1() {
return <div>AppDep1</div>;
}

export const AppDep2 = () => {
return (
<div>
AppDep2 - <AppDepDep />
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function AppDepDep() {
return <span>AppDepDep</span>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { hydrateRoot } from "react-dom/client";
import { App } from "./App";

function main() {
hydrateRoot(document.getElementById("root")!, <App />);
}

main();
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import fs from "node:fs";
import type http from "node:http";
import { renderToString } from "react-dom/server";
import type { ViteDevServer } from "vite";
import { App } from "./App";

export default async function handler(
req: http.IncomingMessage & { viteDevServer: ViteDevServer },
res: http.ServerResponse
) {
let html = await fs.promises.readFile("./index.html", "utf-8");
html = await req.viteDevServer.transformIndexHtml("/", html);

const ssrHtml = renderToString(<App />);
html = html.replace("<!--@INJECT_SSR@-->", ssrHtml);

res.setHeader("content-type", "text/html").end(html);
}
7 changes: 7 additions & 0 deletions packages/vite-plugin-simple-hmr/examples/react/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "../../../../tsconfig.base.json",
"compilerOptions": {
"types": ["vite/client"],
"jsx": "react-jsx"
}
}
18 changes: 18 additions & 0 deletions packages/vite-plugin-simple-hmr/examples/react/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { vitePluginSimpleHmr } from "@hiogawa/vite-plugin-simple-hmr";
import { vitePluginSsrMiddleware } from "@hiogawa/vite-plugin-ssr-middleware";
import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";

export default defineConfig({
clearScreen: false,
plugins: [
react(),
vitePluginSimpleHmr({
include: ["**/*.tsx"],
}),
vitePluginSsrMiddleware({
entry: "/src/entry-server.tsx",
mode: "ViteRuntime",
}),
],
});
43 changes: 43 additions & 0 deletions packages/vite-plugin-simple-hmr/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"name": "@hiogawa/vite-plugin-simple-hmr",
"version": "0.0.1-pre.0",
"homepage": "https://github.com/hi-ogawa/vite-plugins/tree/main/packages/vite-plugin-simple-hmr",
"repository": {
"type": "git",
"url": "https://github.com/hi-ogawa/vite-plugins",
"directory": "packages/vite-plugin-simple-hmr"
},
"license": "MIT",
"type": "module",
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"./runtime": {
"types": "./dist/runtime.d.ts",
"default": "./dist/runtime.js"
}
},
"main": "./dist/index.js",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"build": "tsup",
"test": "vitest",
"release": "pnpm publish --no-git-checks --access public"
},
"dependencies": {
"magic-string": "^0.30.6"
},
"devDependencies": {
"@types/estree": "^1.0.5",
"vite": "^5.1.0"
},
"peerDependencies": {
"vite": "*"
}
}
183 changes: 183 additions & 0 deletions packages/vite-plugin-simple-hmr/src/__snapshots__/index.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`hmrTransform > 0 - basic > analyzeExports 1`] = `
{
"errors": [],
"exportIds": [
"Test1",
"Test2",
"Test3",
"Test4",
],
}
`;

exports[`hmrTransform > 0 - basic > hmrTransform 1`] = `
{
"code": "
export function Test1() {}

export let Test2 = () => {}

export /*some*/ let /*comment*/ Test3 = () => {}

export default function Test4() {}


if (import.meta.env.SSR && import.meta.hot) {
const $$hmr = await import("@hiogawa/vite-plugin-simple-hmr/runtime");
const $$registry = $$hmr.createRegistry();


$$registry.exports["Test1"] = {
value: Test1,
update: ($$next) => {
Test1 = $$next;
}
};


$$registry.exports["Test2"] = {
value: Test2,
update: ($$next) => {
Test2 = $$next;
}
};


$$registry.exports["Test3"] = {
value: Test3,
update: ($$next) => {
Test3 = $$next;
}
};


$$registry.exports["Test4"] = {
value: Test4,
update: ($$next) => {
Test4 = $$next;
}
};


$$hmr.setupHot(import.meta.hot, $$registry);
import.meta.hot.accept;
}
",
"map": SourceMap {
"file": undefined,
"mappings": "AAAA;AACA;AACA;AACA;AACA;AACA,mBAAqB;AACrB;AACA;",
"names": [],
"sources": [
"",
],
"sourcesContent": undefined,
"version": 3,
},
}
`;

exports[`hmrTransform > 1 - separate named export (unsupported) > analyzeExports 1`] = `
{
"errors": [
"export { SomeNamed };",
],
"exportIds": [],
}
`;

exports[`hmrTransform > 1 - separate named export (unsupported) > hmrTransform 1`] = `
{
"code": "
const SomeNamed = () => {};
export { SomeNamed };


if (import.meta.env.SSR && import.meta.hot) {
import.meta.hot.accept(() => {
import.meta.hot.invalidate("unsupported usage: export { SomeNamed };")
});
}
",
"map": SourceMap {
"file": undefined,
"mappings": "AAAA;AACA;AACA;",
"names": [],
"sources": [
"",
],
"sourcesContent": undefined,
"version": 3,
},
}
`;

exports[`hmrTransform > 2 - separate default export (unsupported) > analyzeExports 1`] = `
{
"errors": [
"export default SomeDefault;",
],
"exportIds": [],
}
`;

exports[`hmrTransform > 2 - separate default export (unsupported) > hmrTransform 1`] = `
{
"code": "
const SomeDeafult = () => {};
export default SomeDefault;


if (import.meta.env.SSR && import.meta.hot) {
import.meta.hot.accept(() => {
import.meta.hot.invalidate("unsupported usage: export default SomeDefault;")
});
}
",
"map": SourceMap {
"file": undefined,
"mappings": "AAAA;AACA;AACA;",
"names": [],
"sources": [
"",
],
"sourcesContent": undefined,
"version": 3,
},
}
`;

exports[`hmrTransform > 3 - anonymous default export (unsupported) > analyzeExports 1`] = `
{
"errors": [
"export default () => {};",
],
"exportIds": [],
}
`;

exports[`hmrTransform > 3 - anonymous default export (unsupported) > hmrTransform 1`] = `
{
"code": "
export default () => {};


if (import.meta.env.SSR && import.meta.hot) {
import.meta.hot.accept(() => {
import.meta.hot.invalidate("unsupported usage: export default () => {};")
});
}
",
"map": SourceMap {
"file": undefined,
"mappings": "AAAA;AACA;",
"names": [],
"sources": [
"",
],
"sourcesContent": undefined,
"version": 3,
},
}
`;
Loading
Loading