Skip to content

Commit

Permalink
Add support for using using
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewiggins committed Jul 14, 2023
1 parent 1ace900 commit 190d543
Show file tree
Hide file tree
Showing 8 changed files with 155 additions and 95 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"license": "MIT",
"devDependencies": {
"@babel/core": "^7.22.8",
"@babel/plugin-proposal-explicit-resource-management": "^7.22.6",
"@babel/plugin-syntax-jsx": "^7.21.4",
"@babel/plugin-transform-modules-commonjs": "^7.22.5",
"@babel/plugin-transform-react-jsx": "^7.21.4",
Expand Down
8 changes: 4 additions & 4 deletions packages/react-transform/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,11 +173,11 @@ function isValueMemberExpression(
);
}

const tryCatchTemplate = template.statements`var STOP_TRACKING_IDENTIFIER = HOOK_IDENTIFIER();
const tryCatchTemplate = template.statements`var STORE_IDENTIFIER = HOOK_IDENTIFIER();
try {
BODY
} finally {
STOP_TRACKING_IDENTIFIER();
STORE_IDENTIFIER.finishEffect();
}`;

function wrapInTryFinally(
Expand All @@ -186,12 +186,12 @@ function wrapInTryFinally(
state: PluginPass
): FunctionLike {
const stopTrackingIdentifier =
path.scope.generateUidIdentifier("stopTracking");
path.scope.generateUidIdentifier("effect");

const newFunction = t.cloneNode(path.node);
newFunction.body = t.blockStatement(
tryCatchTemplate({
STOP_TRACKING_IDENTIFIER: stopTrackingIdentifier,
STORE_IDENTIFIER: stopTrackingIdentifier,
HOOK_IDENTIFIER: get(state, getHookIdentifier)(),
BODY: t.isBlockStatement(path.node.body)
? path.node.body.body // TODO: Is it okay to elide the block statement here?
Expand Down
23 changes: 23 additions & 0 deletions packages/react-transform/test/browser/e2e.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -212,4 +212,27 @@ describe("React Signals babel transfrom - browser E2E tests", () => {
});
expect(scratch.innerHTML).to.equal("<div>Hello Jane</div>");
});

it("works with the `using` keyword", async () => {
const { App } = await createComponent(
`
import { useSignals } from "@preact/signals-react/runtime";
export function App({ name }) {
using _ = useSignals();
return <div>Hello {name.value}</div>;
}`,
// Disable our babel plugin for this example so the explicit resource management plugin handles this case
{ mode: "manual" }
);

const name = signal("John");
await render(<App name={name} />);
expect(scratch.innerHTML).to.equal("<div>Hello John</div>");

await act(() => {
name.value = "Jane";
});
expect(scratch.innerHTML).to.equal("<div>Hello Jane</div>");
});
});
52 changes: 26 additions & 26 deletions packages/react-transform/test/node/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,12 @@ describe("React Signals Babel Transform", () => {
const expectedOutput = `
import { useSignals as _useSignals } from "@preact/signals-react/runtime";
const MyComponent = () => {
var _stopTracking = _useSignals();
var _effect = _useSignals();
try {
signal.value;
return <div>Hello World</div>;
} finally {
_stopTracking();
_effect.finishEffect();
}
};
`;
Expand All @@ -88,11 +88,11 @@ describe("React Signals Babel Transform", () => {
const expectedOutput = `
import { useSignals as _useSignals } from "@preact/signals-react/runtime";
const MyComponent = () => {
var _stopTracking = _useSignals();
var _effect = _useSignals();
try {
return <div>{name.value}</div>;
} finally {
_stopTracking();
_effect.finishEffect();
}
};
`;
Expand All @@ -111,12 +111,12 @@ describe("React Signals Babel Transform", () => {
const expectedOutput = `
import { useSignals as _useSignals } from "@preact/signals-react/runtime";
function MyComponent() {
var _stopTracking = _useSignals();
var _effect = _useSignals();
try {
signal.value;
return <div>Hello World</div>;
} finally {
_stopTracking();
_effect.finishEffect();
}
}
`;
Expand All @@ -135,12 +135,12 @@ describe("React Signals Babel Transform", () => {
const expectedOutput = `
import { useSignals as _useSignals } from "@preact/signals-react/runtime";
const MyComponent = function () {
var _stopTracking = _useSignals();
var _effect = _useSignals();
try {
signal.value;
return <div>Hello World</div>;
} finally {
_stopTracking();
_effect.finishEffect();
}
};
`;
Expand Down Expand Up @@ -232,11 +232,11 @@ describe("React Signals Babel Transform", () => {
import { useSignals as _useSignals } from "@preact/signals-react/runtime";
/** @trackSignals */
const MyComponent = () => {
var _stopTracking = _useSignals();
var _effect = _useSignals();
try {
return <div>Hello World</div>;
} finally {
_stopTracking();
_effect.finishEffect();
}
};
`;
Expand All @@ -254,11 +254,11 @@ describe("React Signals Babel Transform", () => {
const expectedOutput = `
import { useSignals as _useSignals } from "@preact/signals-react/runtime";
const MyComponent = /** @trackSignals */() => {
var _stopTracking = _useSignals();
var _effect = _useSignals();
try {
return <div>Hello World</div>;
} finally {
_stopTracking();
_effect.finishEffect();
}
};
`;
Expand All @@ -278,11 +278,11 @@ describe("React Signals Babel Transform", () => {
import { useSignals as _useSignals } from "@preact/signals-react/runtime";
/** @trackSignals */
function MyComponent() {
var _stopTracking = _useSignals();
var _effect = _useSignals();
try {
return <div>Hello World</div>;
} finally {
_stopTracking();
_effect.finishEffect();
}
}
`;
Expand All @@ -302,11 +302,11 @@ describe("React Signals Babel Transform", () => {
import { useSignals as _useSignals } from "@preact/signals-react/runtime";
/** @trackSignals */
export default function MyComponent() {
var _stopTracking = _useSignals();
var _effect = _useSignals();
try {
return <div>Hello World</div>;
} finally {
_stopTracking();
_effect.finishEffect();
}
}
`;
Expand All @@ -326,11 +326,11 @@ describe("React Signals Babel Transform", () => {
import { useSignals as _useSignals } from "@preact/signals-react/runtime";
/** @trackSignals */
export default (() => {
var _stopTracking = _useSignals();
var _effect = _useSignals();
try {
return <div>Hello World</div>;
} finally {
_stopTracking();
_effect.finishEffect();
}
});
`;
Expand All @@ -350,11 +350,11 @@ describe("React Signals Babel Transform", () => {
import { useSignals as _useSignals } from "@preact/signals-react/runtime";
/** @trackSignals */
export function MyComponent() {
var _stopTracking = _useSignals();
var _effect = _useSignals();
try {
return <div>Hello World</div>;
} finally {
_stopTracking();
_effect.finishEffect();
}
}
`;
Expand All @@ -374,11 +374,11 @@ describe("React Signals Babel Transform", () => {
import { useSignals as _useSignals } from "@preact/signals-react/runtime";
/** @trackSignals */
export const MyComponent = () => {
var _stopTracking = _useSignals();
var _effect = _useSignals();
try {
return <div>Hello World</div>;
} finally {
_stopTracking();
_effect.finishEffect();
}
};
`;
Expand All @@ -398,11 +398,11 @@ describe("React Signals Babel Transform", () => {
import { useSignals as _useSignals } from "@preact/signals-react/runtime";
/** @trackSignals */
export const MyComponent = function () {
var _stopTracking = _useSignals();
var _effect = _useSignals();
try {
return <div>Hello World</div>;
} finally {
_stopTracking();
_effect.finishEffect();
}
};
`;
Expand Down Expand Up @@ -819,12 +819,12 @@ describe("React Signals Babel Transform", () => {
const expectedOutput = `
import { useSignals as _useSignals } from "custom-source";
const MyComponent = () => {
var _stopTracking = _useSignals();
var _effect = _useSignals();
try {
signal.value;
return <div>Hello World</div>;
} finally {
_stopTracking();
_effect.finishEffect();
}
};
`;
Expand Down
88 changes: 44 additions & 44 deletions packages/react/runtime/src/auto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
import React from "react";
import jsxRuntime from "react/jsx-runtime";
import jsxRuntimeDev from "react/jsx-dev-runtime";
import { useSignals, wrapJsx } from "./index";
import { EffectStore, useSignals, wrapJsx } from "./index";

export interface ReactDispatcher {
useRef: typeof React.useRef;
Expand Down Expand Up @@ -103,50 +103,50 @@ import { createMachine } from "xstate";
// if it doesn't signal a change in the component rendering lifecyle (NOOP).
const dispatcherMachinePROD = createMachine({
id: "ReactCurrentDispatcher_PROD",
initial: "null",
states: {
null: {
on: {
pushDispatcher: "ContextOnlyDispatcher",
},
},
ContextOnlyDispatcher: {
on: {
renderWithHooks_Mount_ENTER: "HooksDispatcherOnMount",
renderWithHooks_Update_ENTER: "HooksDispatcherOnUpdate",
pushDispatcher_NOOP: "ContextOnlyDispatcher",
popDispatcher_NOOP: "ContextOnlyDispatcher",
},
},
HooksDispatcherOnMount: {
on: {
renderWithHooksAgain_ENTER: "HooksDispatcherOnRerender",
resetHooksAfterThrow_EXIT: "ContextOnlyDispatcher",
finishRenderingHooks_EXIT: "ContextOnlyDispatcher",
},
},
HooksDispatcherOnUpdate: {
on: {
renderWithHooksAgain_ENTER: "HooksDispatcherOnRerender",
resetHooksAfterThrow_EXIT: "ContextOnlyDispatcher",
finishRenderingHooks_EXIT: "ContextOnlyDispatcher",
use_ResumeSuspensedMount_NOOP: "HooksDispatcherOnMount",
},
},
HooksDispatcherOnRerender: {
on: {
renderWithHooksAgain_ENTER: "HooksDispatcherOnRerender",
resetHooksAfterThrow_EXIT: "ContextOnlyDispatcher",
finishRenderingHooks_EXIT: "ContextOnlyDispatcher",
},
},
},
id: "ReactCurrentDispatcher_PROD",
initial: "null",
states: {
null: {
on: {
pushDispatcher: "ContextOnlyDispatcher",
},
},
ContextOnlyDispatcher: {
on: {
renderWithHooks_Mount_ENTER: "HooksDispatcherOnMount",
renderWithHooks_Update_ENTER: "HooksDispatcherOnUpdate",
pushDispatcher_NOOP: "ContextOnlyDispatcher",
popDispatcher_NOOP: "ContextOnlyDispatcher",
},
},
HooksDispatcherOnMount: {
on: {
renderWithHooksAgain_ENTER: "HooksDispatcherOnRerender",
resetHooksAfterThrow_EXIT: "ContextOnlyDispatcher",
finishRenderingHooks_EXIT: "ContextOnlyDispatcher",
},
},
HooksDispatcherOnUpdate: {
on: {
renderWithHooksAgain_ENTER: "HooksDispatcherOnRerender",
resetHooksAfterThrow_EXIT: "ContextOnlyDispatcher",
finishRenderingHooks_EXIT: "ContextOnlyDispatcher",
use_ResumeSuspensedMount_NOOP: "HooksDispatcherOnMount",
},
},
HooksDispatcherOnRerender: {
on: {
renderWithHooksAgain_ENTER: "HooksDispatcherOnRerender",
resetHooksAfterThrow_EXIT: "ContextOnlyDispatcher",
finishRenderingHooks_EXIT: "ContextOnlyDispatcher",
},
},
},
});
```
*/

let stopTracking: (() => void) | null = null;
let store: EffectStore | null = null;
let lock = false;
let currentDispatcher: ReactDispatcher | null = null;

Expand All @@ -171,12 +171,12 @@ function installCurrentDispatcherHook() {
isEnteringComponentRender(currentDispatcherType, nextDispatcherType)
) {
lock = true;
stopTracking = useSignals();
store = useSignals();
lock = false;
} else if (
isExitingComponentRender(currentDispatcherType, nextDispatcherType)
) {
stopTracking?.();
store?.finishEffect();
}
},
});
Expand Down Expand Up @@ -325,7 +325,7 @@ function isExitingComponentRender(
): boolean {
return Boolean(
currentDispatcherType & BrowserClientDispatcherType &&
nextDispatcherType & ContextOnlyDispatcherType
nextDispatcherType & ContextOnlyDispatcherType
);
}

Expand Down
Loading

0 comments on commit 190d543

Please sign in to comment.