Skip to content

Commit f82fa5f

Browse files
committed
fix(#66): signals as refs
1 parent ad30cba commit f82fa5f

File tree

6 files changed

+188
-14
lines changed

6 files changed

+188
-14
lines changed

playground/pnpm-lock.yaml

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

playground/src/App.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { createSignal, onCleanup, onMount } from 'solid-js';
22

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

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

2021
return (
2122
<>
22-
<h1>Count: {count()}</h1>
23+
<h1 ref={setEl}>Count: {count()}</h1>
2324
<button type="button" onClick={increment}>
2425
Increment
2526
</button>

pnpm-lock.yaml

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/babel/core/transform-jsx.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ function extractJSXExpressionFromRef(
7777
let replacement: t.Expression;
7878
if (unwrappedIdentifier) {
7979
const arg = expr.scope.generateUidIdentifier('arg');
80+
const binding = expr.scope.getBinding(unwrappedIdentifier.name);
81+
const cannotAssignKind = ['const', 'module'];
82+
const isConst = binding && cannotAssignKind.includes(binding.kind);
83+
8084
replacement = t.arrowFunctionExpression(
8185
[arg],
8286
t.blockStatement([
@@ -91,11 +95,17 @@ function extractJSXExpressionFromRef(
9195
t.callExpression(unwrappedIdentifier, [arg]),
9296
),
9397
]),
94-
t.blockStatement([
95-
t.expressionStatement(
96-
t.assignmentExpression('=', unwrappedIdentifier, arg),
97-
),
98-
]),
98+
// fix the new usage of `ref` attribute,
99+
// if use `Signals as refs`, the `else` branch will throw an errow with `Cannot assign to "setter" because it is a constant` message
100+
// issue: https://github.com/solidjs/solid-refresh/issues/66
101+
// docs: https://docs.solidjs.com/concepts/refs#signals-as-refs
102+
isConst
103+
? null
104+
: t.blockStatement([
105+
t.expressionStatement(
106+
t.assignmentExpression('=', unwrappedIdentifier, arg),
107+
),
108+
]),
99109
),
100110
]),
101111
);

tests/client/__snapshots__/esm.test.ts.snap

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,6 +1130,116 @@ if (import.meta.hot) {
11301130
}"
11311131
`;
11321132
1133+
exports[`esm (client, non-hydratable) > fix build > refs > should work with a function 1`] = `
1134+
"import { template as _$template } from "solid-js/web";
1135+
import { createComponent as _$createComponent } from "solid-js/web";
1136+
import { use as _$use } from "solid-js/web";
1137+
var _tmpl$ = /*#__PURE__*/_$template(\`<div>Comp\`);
1138+
import { $$component as _$$component } from "solid-refresh";
1139+
import { $$refresh as _$$refresh } from "solid-refresh";
1140+
import { $$registry as _$$registry } from "solid-refresh";
1141+
const _REGISTRY = _$$registry();
1142+
const Comp_1 = _$$component(_REGISTRY, "Comp_1", _props => /*@refresh jsx-skip*/(() => {
1143+
var _el$ = _tmpl$();
1144+
var _ref$ = _props.v0;
1145+
typeof _ref$ === "function" ? _$use(_ref$, _el$) : _props.v0 = _el$;
1146+
return _el$;
1147+
})(), {
1148+
location: "example.jsx:4:19",
1149+
signature: "6f76290"
1150+
});
1151+
const Comp = _$$component(_REGISTRY, "Comp", () => {
1152+
let el;
1153+
return /*@refresh jsx-skip*/_$createComponent(Comp_1, {
1154+
v0: _el => el = _el
1155+
});
1156+
}, {
1157+
location: "example.jsx:2:23",
1158+
signature: "726057ca"
1159+
});
1160+
if (import.meta.hot) {
1161+
_$$refresh("esm", import.meta.hot, _REGISTRY);
1162+
}"
1163+
`;
1164+
1165+
exports[`esm (client, non-hydratable) > fix build > refs > should work with a mutable variable 1`] = `
1166+
"import { template as _$template } from "solid-js/web";
1167+
import { createComponent as _$createComponent } from "solid-js/web";
1168+
import { use as _$use } from "solid-js/web";
1169+
var _tmpl$ = /*#__PURE__*/_$template(\`<div>Comp\`);
1170+
import { $$component as _$$component } from "solid-refresh";
1171+
import { $$refresh as _$$refresh } from "solid-refresh";
1172+
import { $$registry as _$$registry } from "solid-refresh";
1173+
const _REGISTRY = _$$registry();
1174+
const Comp_1 = _$$component(_REGISTRY, "Comp_1", _props => /*@refresh jsx-skip*/(() => {
1175+
var _el$ = _tmpl$();
1176+
var _ref$ = _props.v0;
1177+
typeof _ref$ === "function" ? _$use(_ref$, _el$) : _props.v0 = _el$;
1178+
return _el$;
1179+
})(), {
1180+
location: "example.jsx:4:19",
1181+
signature: "6f76290"
1182+
});
1183+
const Comp = _$$component(_REGISTRY, "Comp", () => {
1184+
let el;
1185+
return /*@refresh jsx-skip*/_$createComponent(Comp_1, {
1186+
v0: _arg => {
1187+
if (typeof el === "function") {
1188+
el(_arg);
1189+
} else {
1190+
el = _arg;
1191+
}
1192+
}
1193+
});
1194+
}, {
1195+
location: "example.jsx:2:23",
1196+
signature: "d3db0f89"
1197+
});
1198+
if (import.meta.hot) {
1199+
_$$refresh("esm", import.meta.hot, _REGISTRY);
1200+
}"
1201+
`;
1202+
1203+
exports[`esm (client, non-hydratable) > fix build > signals as refs > should work 1`] = `
1204+
"import { template as _$template } from "solid-js/web";
1205+
import { createComponent as _$createComponent } from "solid-js/web";
1206+
import { use as _$use } from "solid-js/web";
1207+
var _tmpl$ = /*#__PURE__*/_$template(\`<div>Comp\`);
1208+
import { $$component as _$$component } from "solid-refresh";
1209+
import { $$refresh as _$$refresh } from "solid-refresh";
1210+
import { $$registry as _$$registry } from "solid-refresh";
1211+
import { createSignal } from 'solid-js';
1212+
const _REGISTRY = _$$registry();
1213+
const Comp_1 = _$$component(_REGISTRY, "Comp_1", _props => /*@refresh jsx-skip*/(() => {
1214+
var _el$ = _tmpl$();
1215+
var _ref$ = _props.v0;
1216+
typeof _ref$ === "function" ? _$use(_ref$, _el$) : _props.v0 = _el$;
1217+
return _el$;
1218+
})(), {
1219+
location: "example.jsx:6:19",
1220+
signature: "6f76290"
1221+
});
1222+
const Comp = _$$component(_REGISTRY, "Comp", () => {
1223+
const [el, setEl] = createSignal();
1224+
return /*@refresh jsx-skip*/_$createComponent(Comp_1, {
1225+
v0: _arg => {
1226+
if (typeof setEl === "function") {
1227+
setEl(_arg);
1228+
}
1229+
}
1230+
});
1231+
}, {
1232+
location: "example.jsx:4:23",
1233+
signature: "57db44c6",
1234+
dependencies: () => ({
1235+
createSignal
1236+
})
1237+
});
1238+
if (import.meta.hot) {
1239+
_$$refresh("esm", import.meta.hot, _REGISTRY);
1240+
}"
1241+
`;
1242+
11331243
exports[`esm (client, non-hydratable) > fix render > @refresh reload > should work 1`] = `
11341244
"import { createComponent as _$createComponent } from "solid-js/web";
11351245
import { $$decline as _$$decline } from "solid-refresh";

tests/client/esm.test.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,4 +810,57 @@ describe('esm (client, non-hydratable)', () => {
810810
});
811811
});
812812
});
813+
describe('fix build', () => {
814+
describe('refs', () => {
815+
it('should work with a mutable variable', async () => {
816+
expect(
817+
await transform(
818+
`
819+
const Comp = () => {
820+
let el;
821+
return <div ref={el}>Comp</div>;
822+
}
823+
`,
824+
'esm',
825+
'client',
826+
false,
827+
),
828+
).toMatchSnapshot();
829+
});
830+
it('should work with a function', async () => {
831+
expect(
832+
await transform(
833+
`
834+
const Comp = () => {
835+
let el;
836+
return <div ref={(_el) => el = _el}>Comp</div>;
837+
}
838+
`,
839+
'esm',
840+
'client',
841+
false,
842+
),
843+
).toMatchSnapshot();
844+
});
845+
});
846+
describe('signals as refs', () => {
847+
it('should work', async () => {
848+
expect(
849+
await transform(
850+
`
851+
import { createSignal } from 'solid-js';
852+
853+
const Comp = () => {
854+
const [el, setEl] = createSignal();
855+
return <div ref={setEl}>Comp</div>;
856+
}
857+
`,
858+
'esm',
859+
'client',
860+
false,
861+
),
862+
).toMatchSnapshot();
863+
});
864+
});
865+
});
813866
});

0 commit comments

Comments
 (0)