Skip to content

Commit 2f6ba18

Browse files
authored
React Refresh (codesandbox#3014)
* Don't unmount components created with createRoot * React Refresh * Remove HMR enabled code * Fix typings * Add babel plugin to prod build * Fix jest typing * Fix regex require finder * Revert change of README.md * Enable React Refresh for all dependencies * Fix typing * Fix typecheck * Add conditional module.hot.accept() * Change default file opened for React templates * Revert "Add conditional module.hot.accept()" This reverts commit 47d98b8. * Fix entry files
1 parent d3a7a0b commit 2f6ba18

25 files changed

+693
-300
lines changed

packages/app/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@
260260
"@types/react-router-dom": "^4.3.1",
261261
"@types/react-stripe-elements": "^1.3.2",
262262
"@types/resolve": "^0.0.8",
263+
"@types/semver": "6.2.0",
263264
"@types/socket.io-client": "^1.4.32",
264265
"@types/stripe-v3": "^3.1.7",
265266
"@types/styled-components": "^4.1.13",

packages/app/src/sandbox/compile.ts

Lines changed: 56 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ import createCodeSandboxOverlay from './codesandbox-overlay';
2121
import getPreset from './eval';
2222
import { consumeCache, deleteAPICache, saveCache } from './eval/cache';
2323
import { Module } from './eval/entities/module';
24-
import Manager, { Manifest } from './eval/manager';
24+
import Manager from './eval/manager';
2525
import TranspiledModule from './eval/transpiled-module';
2626
import handleExternalResources from './external-resources';
27-
import { loadDependencies } from './npm';
27+
import { loadDependencies, NPMDependencies } from './npm';
2828
import { resetScreen } from './status-screen';
2929
import { showRunOnClick } from './status-screen/run-on-click';
3030

@@ -93,6 +93,7 @@ const WHITELISTED_DEV_DEPENDENCIES = [
9393
'react-addons-test-utils',
9494
'react-test-renderer',
9595
'identity-obj-proxy',
96+
'react-refresh',
9697
];
9798

9899
const BABEL_DEPENDENCIES = [
@@ -197,7 +198,11 @@ const PREINSTALLED_DEPENDENCIES = [
197198
...BABEL_DEPENDENCIES,
198199
];
199200

200-
function getDependencies(parsedPackage, templateDefinition, configurations) {
201+
function getDependencies(
202+
parsedPackage,
203+
templateDefinition,
204+
configurations
205+
): NPMDependencies {
201206
const {
202207
dependencies: d = {},
203208
peerDependencies = {},
@@ -304,33 +309,27 @@ function getDependencies(parsedPackage, templateDefinition, configurations) {
304309
return returnedDependencies;
305310
}
306311

307-
async function updateManager(
312+
function initializeManager(
308313
sandboxId: string,
309314
template: TemplateType,
310-
managerModules,
311-
manifest: Manifest,
315+
modules: { [path: string]: Module },
312316
configurations: ParsedConfigurationFiles,
313-
isNewCombination: boolean,
314-
hasFileResolver: boolean
315-
): Promise<TranspiledModule[]> {
316-
let newManager = false;
317-
if (!manager || manager.id !== sandboxId) {
318-
newManager = true;
319-
manager = new Manager(sandboxId, getPreset(template), managerModules, {
317+
{ hasFileResolver = false }: { hasFileResolver?: boolean } = {}
318+
) {
319+
return new Manager(
320+
sandboxId,
321+
getPreset(template, configurations.package.parsed),
322+
modules,
323+
{
320324
hasFileResolver,
321-
});
322-
}
323-
324-
if (isNewCombination || newManager) {
325-
manager.setManifest(manifest);
326-
}
327-
328-
if (firstLoad && newManager) {
329-
// We save the state of transpiled modules, and load it here again. Gives
330-
// faster initial loads.
331-
await consumeCache(manager);
332-
}
325+
}
326+
);
327+
}
333328

329+
async function updateManager(
330+
managerModules: { [path: string]: Module },
331+
configurations: ParsedConfigurationFiles
332+
): Promise<TranspiledModule[]> {
334333
manager.updateConfigurations(configurations);
335334
await manager.preset.setup(manager);
336335
return manager.updateData(managerModules).then(x => {
@@ -402,7 +401,6 @@ interface CompileOptions {
402401
skipEval?: boolean;
403402
hasFileResolver?: boolean;
404403
disableDependencyPreprocessing?: boolean;
405-
showFullScreen?: boolean;
406404
}
407405

408406
async function compile({
@@ -417,7 +415,6 @@ async function compile({
417415
skipEval = false,
418416
hasFileResolver = false,
419417
disableDependencyPreprocessing = false,
420-
showFullScreen = false,
421418
}: CompileOptions) {
422419
dispatch({
423420
type: 'start',
@@ -471,12 +468,20 @@ async function compile({
471468

472469
dispatch({ type: 'status', status: 'installing-dependencies' });
473470

474-
const dependencies = getDependencies(
471+
manager =
472+
manager ||
473+
initializeManager(sandboxId, template, modules, configurations, {
474+
hasFileResolver,
475+
});
476+
477+
let dependencies: NPMDependencies = getDependencies(
475478
parsedPackageJSON,
476479
templateDefinition,
477480
configurations
478481
);
479482

483+
dependencies = await manager.preset.processDependencies(dependencies);
484+
480485
const { manifest, isNewCombination } = await loadDependencies(
481486
dependencies,
482487
{
@@ -486,25 +491,34 @@ async function compile({
486491
}
487492
);
488493

489-
if (isNewCombination && !firstLoad) {
494+
const shouldReloadManager =
495+
(isNewCombination && !firstLoad) || manager.id !== sandboxId;
496+
497+
if (shouldReloadManager) {
490498
// Just reset the whole manager if it's a new combination
491-
if (manager) {
492-
manager.dispose();
493-
}
494-
manager = null;
495-
}
496-
const t = Date.now();
499+
manager.dispose();
497500

498-
const updatedModules =
499-
(await updateManager(
501+
manager = initializeManager(
500502
sandboxId,
501503
template,
502504
modules,
503-
manifest,
504505
configurations,
505-
isNewCombination,
506-
hasFileResolver
507-
)) || [];
506+
{ hasFileResolver }
507+
);
508+
}
509+
510+
if (shouldReloadManager || firstLoad) {
511+
// Now initialize the data the manager can only use once dependencies are loaded
512+
513+
manager.setManifest(manifest);
514+
// We save the state of transpiled modules, and load it here again. Gives
515+
// faster initial loads.
516+
await consumeCache(manager);
517+
}
518+
519+
const t = Date.now();
520+
521+
const updatedModules = (await updateManager(modules, configurations)) || [];
508522

509523
const possibleEntries = templateDefinition.getEntries(configurations);
510524

@@ -521,9 +535,6 @@ async function compile({
521535
const main = absolute(foundMain);
522536
managerModuleToTranspile = modules[main];
523537

524-
// TODO: make this a separate lifecycle
525-
// await manager.preset.setup(manager);
526-
527538
dispatch({ type: 'status', status: 'transpiling' });
528539
manager.setStage('transpilation');
529540

@@ -557,7 +568,7 @@ async function compile({
557568
/* no */
558569
}
559570

560-
manager.preset.preEvaluate(manager, updatedModules);
571+
await manager.preset.preEvaluate(manager, updatedModules);
561572

562573
if (!manager.webpackHMR) {
563574
const htmlModulePath = templateDefinition

packages/app/src/sandbox/eval/hmr.js renamed to packages/app/src/sandbox/eval/hmr.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
// @flow
2-
31
export default class HMR {
4-
callback: ?() => void;
5-
disposeHandler: ?(data: Object) => void;
2+
callback?: () => void;
3+
disposeHandler?: (data: Object) => void;
64
data: Object;
7-
type: ?'accept' | 'decline';
5+
type?: 'accept' | 'decline';
86
dirty: boolean = false;
97
selfAccepted: boolean = false;
108

@@ -22,12 +20,12 @@ export default class HMR {
2220
}
2321
}
2422

25-
setAcceptCallback(callback?: Function) {
23+
setAcceptCallback(callback?: () => void) {
2624
this.callback = callback;
2725
this.setSelfAccepted(false);
2826
}
2927

30-
setDisposeHandler(callback: Function) {
28+
setDisposeHandler(callback: () => void) {
3129
this.disposeHandler = callback;
3230
}
3331

packages/app/src/sandbox/eval/index.js renamed to packages/app/src/sandbox/eval/index.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// @ts-check
1+
/* eslint-disable import/no-named-as-default-member, import/default, import/no-named-as-default */
22
import {
33
react,
44
vue,
@@ -14,7 +14,9 @@ import {
1414
reason,
1515
} from '@codesandbox/common/lib/templates';
1616

17-
import reactPreset from './presets/create-react-app';
17+
import { isBabel7 } from '@codesandbox/common/lib/utils/is-babel-7';
18+
import { PackageJSON } from '@codesandbox/common/lib/types';
19+
import { reactPresetV1, reactPresetV3 } from './presets/create-react-app';
1820
import reactTsPreset from './presets/create-react-app-typescript';
1921
import vuePreset from './presets/vue-cli';
2022
import preactPreset from './presets/preact-cli';
@@ -27,10 +29,15 @@ import reasonPreset from './presets/reason';
2729
import dojoPreset from './presets/dojo';
2830
import customPreset from './presets/custom';
2931

30-
export default function getPreset(template: string) {
32+
export default function getPreset(template: string, pkg: PackageJSON) {
3133
switch (template) {
3234
case react.name:
33-
return reactPreset();
35+
if (isBabel7(pkg.dependencies, pkg.devDependencies)) {
36+
return reactPresetV3();
37+
}
38+
39+
return reactPresetV1();
40+
3441
case reactTs.name:
3542
return reactTsPreset();
3643
case reason.name:
@@ -54,6 +61,6 @@ export default function getPreset(template: string) {
5461
case custom.name:
5562
return customPreset();
5663
default:
57-
return reactPreset();
64+
return reactPresetV3();
5865
}
5966
}

packages/app/src/sandbox/eval/manager.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -308,10 +308,10 @@ export default class Manager {
308308

309309
evaluateModule(
310310
module: Module,
311-
{ force, testGlobals }: { force?: boolean; testGlobals?: boolean } = {
312-
force: false,
313-
testGlobals: false,
314-
}
311+
{
312+
force = false,
313+
testGlobals = false,
314+
}: { force?: boolean; testGlobals?: boolean } = {}
315315
) {
316316
if (this.hardReload && !this.isFirstLoad) {
317317
// Do a hard reload

0 commit comments

Comments
 (0)