Skip to content

Commit

Permalink
refactor(viteroll): inline react-refresh/runtime (#72)
Browse files Browse the repository at this point in the history
  • Loading branch information
hi-ogawa authored Nov 12, 2024
1 parent f8fc795 commit fc38fd3
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 65 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,4 @@ jobs:
- run: pnpm test-e2e
- run: pnpm -C examples/react test-e2e
- run: pnpm -C examples/mpa test-e2e
- run: pnpm -C examples/ssr test-e2e
2 changes: 0 additions & 2 deletions viteroll/examples/ssr/src/entry-client.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// TODO: how to inject automatically?
import "virtual:react-refresh/entry";
import React from "react";
import ReactDOMClient from "react-dom/client";
import { App } from "./app";
Expand Down
116 changes: 53 additions & 63 deletions viteroll/viteroll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,10 @@ export function viteroll(viterollOptions: ViterollOptions = {}): Plugin {
},
ssr: {
dev: {
createEnvironment:
RolldownEnvironment.createFactory(viterollOptions),
createEnvironment: RolldownEnvironment.createFactory({
...viterollOptions,
reactRefresh: false,
}),
},
},
},
Expand Down Expand Up @@ -315,9 +317,6 @@ function viterollEntryPlugin(
htmlEntryMap.set(id, htmlOutput);

let jsOutput = ``;
if (viterollOptions?.reactRefresh) {
jsOutput += `import "virtual:react-refresh/entry";\n`;
}

// extract <script src="...">
const matches = code.matchAll(
Expand Down Expand Up @@ -360,6 +359,9 @@ function viterollEntryPlugin(
}
for (var i = 0; i < module.parents.length; i++) {`,
);
if (viterollOptions.reactRefresh) {
output.prepend(getReactRefreshRuntimeCode());
}
return { code: output.toString(), map: output.generateMap() };
}
},
Expand Down Expand Up @@ -396,7 +398,6 @@ function viterollEntryPlugin(
};
}

// TODO: workaround rolldownExperimental.reactPlugin which injects js to html via `load` hook
function reactRefreshPlugin(): rolldown.Plugin {
return {
name: "react-hmr",
Expand All @@ -407,65 +408,54 @@ function reactRefreshPlugin(): rolldown.Plugin {
},
},
handler(code, id) {
const output = new MagicString(code);
output.prepend(`
import * as __$refresh from 'virtual:react-refresh';
const [$RefreshSig$, $RefreshReg$] = __$refresh.create(${JSON.stringify(id)});
`);
output.append(`
__$refresh.setupHot(module.hot);
`);
return { code: output.toString(), map: output.generateMap() };
return [
`const [$RefreshSig$, $RefreshReg$] = __react_refresh_transform_define(${JSON.stringify(id)})`,
code,
`__react_refresh_transform_setupHot(module.hot)`,
].join(";");
},
},
resolveId: {
filter: {
id: {
include: [/^virtual:react-refresh/],
},
},
handler: (source) => "\0" + source,
},
load: {
filter: {
id: {
include: [/^\0virtual:react-refresh/],
},
},
async handler(id) {
const resolved = require.resolve("react-refresh/runtime");
if (id === "\0virtual:react-refresh/entry") {
return `
import runtime from ${JSON.stringify(resolved)};
runtime.injectIntoGlobalHook(window);
`;
}
if (id === "\0virtual:react-refresh") {
return `
import runtime from ${JSON.stringify(resolved)};
export const create = (file) => [
runtime.createSignatureFunctionForTransform,
(type, id) => runtime.register(type, file + '_' + id),
];
function debounce(fn, delay) {
let handle
return () => {
clearTimeout(handle)
handle = setTimeout(fn, delay)
}
}
const debouncedRefresh = debounce(runtime.performReactRefresh, 16);
};
}

export function setupHot(hot) {
hot.accept((prev) => {
debouncedRefresh();
});
}
`;
// inject react refresh runtime in client runtime to ensure initialized early
function getReactRefreshRuntimeCode() {
let code = fs.readFileSync(
path.resolve(
require.resolve("react-refresh/runtime"),
"..",
"cjs/react-refresh-runtime.development.js",
),
"utf-8",
);
const output = new MagicString(code);
output.prepend("self.__react_refresh_runtime = {};\n");
output.replaceAll('process.env.NODE_ENV !== "production"', "true");
output.replaceAll(/\bexports\./g, "__react_refresh_runtime.");
output.append(`
(() => {
__react_refresh_runtime.injectIntoGlobalHook(self);
__react_refresh_transform_define = (file) => [
__react_refresh_runtime.createSignatureFunctionForTransform,
(type, id) => __react_refresh_runtime.register(type, file + '_' + id)
];
__react_refresh_transform_setupHot = (hot) => {
hot.accept((prev) => {
debouncedRefresh();
});
};
function debounce(fn, delay) {
let handle
return () => {
clearTimeout(handle)
handle = setTimeout(fn, delay)
}
},
},
};
}
const debouncedRefresh = debounce(__react_refresh_runtime.performReactRefresh, 16);
})()
`);
return output.toString();
}

0 comments on commit fc38fd3

Please sign in to comment.