Skip to content

Commit

Permalink
fix(solidjs#66): signals as refs
Browse files Browse the repository at this point in the history
  • Loading branch information
王家祺 committed Jul 19, 2024
1 parent ad30cba commit dfa2422
Show file tree
Hide file tree
Showing 6 changed files with 188 additions and 14 deletions.
8 changes: 4 additions & 4 deletions playground/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion playground/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { createSignal, onCleanup, onMount } from 'solid-js';

export function App() {
const [count, setCount] = createSignal(0);
const [, setEl] = createSignal<HTMLElement>();

function increment() {
setCount(c => c + 1);
Expand All @@ -19,7 +20,7 @@ export function App() {

return (
<>
<h1>Count: {count()}</h1>
<h1 ref={setEl}>Count: {count()}</h1>
<button type="button" onClick={increment}>
Increment
</button>
Expand Down
8 changes: 4 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 15 additions & 5 deletions src/babel/core/transform-jsx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ function extractJSXExpressionFromRef(
let replacement: t.Expression;
if (unwrappedIdentifier) {
const arg = expr.scope.generateUidIdentifier('arg');
const binding = expr.scope.getBinding(unwrappedIdentifier.name);
const cannotAssignKind = ['const', 'module'];
const isConst = binding && cannotAssignKind.includes(binding.kind);

replacement = t.arrowFunctionExpression(
[arg],
t.blockStatement([
Expand All @@ -91,11 +95,17 @@ function extractJSXExpressionFromRef(
t.callExpression(unwrappedIdentifier, [arg]),
),
]),
t.blockStatement([
t.expressionStatement(
t.assignmentExpression('=', unwrappedIdentifier, arg),
),
]),
// fix the new usage of `ref` attribute,
// if use `Signals as refs`, the `else` branch will throw an errow with `Cannot assign to "setter" because it is a constant` message
// issue: https://github.com/solidjs/solid-refresh/issues/66
// docs: https://docs.solidjs.com/concepts/refs#signals-as-refs
isConst
? null
: t.blockStatement([
t.expressionStatement(
t.assignmentExpression('=', unwrappedIdentifier, arg),
),
]),
),
]),
);
Expand Down
110 changes: 110 additions & 0 deletions tests/client/__snapshots__/esm.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1130,6 +1130,116 @@ if (import.meta.hot) {
}"
`;
exports[`esm (client, non-hydratable) > fix build > refs > should work with a function 1`] = `
"import { template as _$template } from "solid-js/web";
import { createComponent as _$createComponent } from "solid-js/web";
import { use as _$use } from "solid-js/web";
var _tmpl$ = /*#__PURE__*/_$template(\`<div>Comp\`);
import { $$component as _$$component } from "solid-refresh";
import { $$refresh as _$$refresh } from "solid-refresh";
import { $$registry as _$$registry } from "solid-refresh";
const _REGISTRY = _$$registry();
const Comp_1 = _$$component(_REGISTRY, "Comp_1", _props => /*@refresh jsx-skip*/(() => {
var _el$ = _tmpl$();
var _ref$ = _props.v0;
typeof _ref$ === "function" ? _$use(_ref$, _el$) : _props.v0 = _el$;
return _el$;
})(), {
location: "example.jsx:4:19",
signature: "6f76290"
});
const Comp = _$$component(_REGISTRY, "Comp", () => {
let el;
return /*@refresh jsx-skip*/_$createComponent(Comp_1, {
v0: _el => el = _el
});
}, {
location: "example.jsx:2:23",
signature: "726057ca"
});
if (import.meta.hot) {
_$$refresh("esm", import.meta.hot, _REGISTRY);
}"
`;
exports[`esm (client, non-hydratable) > fix build > refs > should work with a mutable variable 1`] = `
"import { template as _$template } from "solid-js/web";
import { createComponent as _$createComponent } from "solid-js/web";
import { use as _$use } from "solid-js/web";
var _tmpl$ = /*#__PURE__*/_$template(\`<div>Comp\`);
import { $$component as _$$component } from "solid-refresh";
import { $$refresh as _$$refresh } from "solid-refresh";
import { $$registry as _$$registry } from "solid-refresh";
const _REGISTRY = _$$registry();
const Comp_1 = _$$component(_REGISTRY, "Comp_1", _props => /*@refresh jsx-skip*/(() => {
var _el$ = _tmpl$();
var _ref$ = _props.v0;
typeof _ref$ === "function" ? _$use(_ref$, _el$) : _props.v0 = _el$;
return _el$;
})(), {
location: "example.jsx:4:19",
signature: "6f76290"
});
const Comp = _$$component(_REGISTRY, "Comp", () => {
let el;
return /*@refresh jsx-skip*/_$createComponent(Comp_1, {
v0: _arg => {
if (typeof el === "function") {
el(_arg);
} else {
el = _arg;
}
}
});
}, {
location: "example.jsx:2:23",
signature: "d3db0f89"
});
if (import.meta.hot) {
_$$refresh("esm", import.meta.hot, _REGISTRY);
}"
`;
exports[`esm (client, non-hydratable) > fix build > signals as refs > should work 1`] = `
"import { template as _$template } from "solid-js/web";
import { createComponent as _$createComponent } from "solid-js/web";
import { use as _$use } from "solid-js/web";
var _tmpl$ = /*#__PURE__*/_$template(\`<div>Comp\`);
import { $$component as _$$component } from "solid-refresh";
import { $$refresh as _$$refresh } from "solid-refresh";
import { $$registry as _$$registry } from "solid-refresh";
import { createSignal } from 'solid-js';
const _REGISTRY = _$$registry();
const Comp_1 = _$$component(_REGISTRY, "Comp_1", _props => /*@refresh jsx-skip*/(() => {
var _el$ = _tmpl$();
var _ref$ = _props.v0;
typeof _ref$ === "function" ? _$use(_ref$, _el$) : _props.v0 = _el$;
return _el$;
})(), {
location: "example.jsx:6:19",
signature: "6f76290"
});
const Comp = _$$component(_REGISTRY, "Comp", () => {
const [el, setEl] = createSignal();
return /*@refresh jsx-skip*/_$createComponent(Comp_1, {
v0: _arg => {
if (typeof setEl === "function") {
setEl(_arg);
}
}
});
}, {
location: "example.jsx:4:23",
signature: "57db44c6",
dependencies: () => ({
createSignal
})
});
if (import.meta.hot) {
_$$refresh("esm", import.meta.hot, _REGISTRY);
}"
`;
exports[`esm (client, non-hydratable) > fix render > @refresh reload > should work 1`] = `
"import { createComponent as _$createComponent } from "solid-js/web";
import { $$decline as _$$decline } from "solid-refresh";
Expand Down
53 changes: 53 additions & 0 deletions tests/client/esm.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -810,4 +810,57 @@ describe('esm (client, non-hydratable)', () => {
});
});
});
describe('fix build', () => {
describe('refs', () => {
it('should work with a mutable variable', async () => {
expect(
await transform(
`
const Comp = () => {
let el;
return <div ref={el}>Comp</div>;
}
`,
'esm',
'client',
false,
),
).toMatchSnapshot();
});
it('should work with a function', async () => {
expect(
await transform(
`
const Comp = () => {
let el;
return <div ref={(_el) => el = _el}>Comp</div>;
}
`,
'esm',
'client',
false,
),
).toMatchSnapshot();
});
});
describe('signals as refs', () => {
it('should work', async () => {
expect(
await transform(
`
import { createSignal } from 'solid-js';
const Comp = () => {
const [el, setEl] = createSignal();
return <div ref={setEl}>Comp</div>;
}
`,
'esm',
'client',
false,
),
).toMatchSnapshot();
});
});
});
});

0 comments on commit dfa2422

Please sign in to comment.