Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/babel/core/checks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,15 @@ export function getImportSpecifierName(specifier: t.ImportSpecifier): string {
}
return specifier.imported.value;
}

// A component receives at most one argument (its props), so a
// function with more than one parameter isn't a component.
// A rest parameter accepts any number of arguments, so a function
// declaring one isn't a component either: it's a plain function
// that happens to have a Pascal-cased name, and wrapping it in the
// HMR proxy would drop every argument after the first.
export function isComponentishParams(
params: (t.Identifier | t.Pattern | t.RestElement)[],
): boolean {
return params.length < 2 && !params.some(param => t.isRestElement(param));
}
8 changes: 4 additions & 4 deletions src/babel/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type * as babel from '@babel/core';
import * as t from '@babel/types';
import path from 'path';
import { isComponentishName } from './core/checks';
import { isComponentishName, isComponentishParams } from './core/checks';
import {
IMPORT_COMPONENT,
IMPORT_CONTEXT,
Expand Down Expand Up @@ -238,7 +238,7 @@ function transformVariableDeclarator(
!(trueFuncExpr.async || trueFuncExpr.generator) &&
// Might be component-like, but the only valid components
// have zero or one parameter
trueFuncExpr.params.length < 2
isComponentishParams(trueFuncExpr.params)
) {
path.node.init = wrapComponent(state, path, identifier, trueFuncExpr);
}
Expand Down Expand Up @@ -269,7 +269,7 @@ function transformFunctionDeclaration(
!(decl.generator || decl.async) &&
// Might be component-like, but the only valid components
// have zero or one parameter
decl.params.length < 2
isComponentishParams(decl.params)
) {
path.scope.registerDeclaration(
path.replaceWith(
Expand Down Expand Up @@ -307,7 +307,7 @@ function bubbleFunctionDeclaration(
!(decl.generator || decl.async) &&
// Might be component-like, but the only valid components
// have zero or one parameter
decl.params.length < 2
isComponentishParams(decl.params)
) {
if (path.parentPath.isExportNamedDeclaration()) {
path.parentPath.replaceWith(
Expand Down
105 changes: 105 additions & 0 deletions tests/client-hydratable/__snapshots__/esm.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,27 @@ if (import.meta.hot) {
}"
`;

exports[`esm (client, hydratable) > ExportDefaultDeclaration w/ FunctionExpression > should skip ExportDefaultDeclaration w/ FunctionExpression with valid Component name and a rest parameter 1`] = `
"import { template as _$template } from "solid-js/web";
import { createComponent as _$createComponent } from "solid-js/web";
import { getNextElement as _$getNextElement } from "solid-js/web";
var _tmpl$ = /*#__PURE__*/_$template(\`<h1>Foo\`);
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 Foo_1 = _$$component(_REGISTRY, "Foo_1", _props => /*@refresh jsx-skip*/_$getNextElement(_tmpl$), {
location: "example.jsx:3:15",
signature: "4b145a58"
});
export default function Foo(...args) {
return /*@refresh jsx-skip*/_$createComponent(Foo_1, {});
}
if (import.meta.hot) {
_$$refresh("esm", import.meta.hot, _REGISTRY);
}"
`;

exports[`esm (client, hydratable) > ExportDefaultDeclaration w/ FunctionExpression > should transform ExportDefaultDeclaration w/ FunctionExpression with valid Component name and params 1`] = `
"import { template as _$template } from "solid-js/web";
import { createComponent as _$createComponent } from "solid-js/web";
Expand Down Expand Up @@ -329,6 +350,27 @@ if (import.meta.hot) {
}"
`;

exports[`esm (client, hydratable) > ExportNamedDeclaration w/ FunctionExpression > should skip ExportNamedDeclaration w/ FunctionExpression with valid Component name and a rest parameter 1`] = `
"import { template as _$template } from "solid-js/web";
import { createComponent as _$createComponent } from "solid-js/web";
import { getNextElement as _$getNextElement } from "solid-js/web";
var _tmpl$ = /*#__PURE__*/_$template(\`<h1>Foo\`);
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 Foo_1 = _$$component(_REGISTRY, "Foo_1", _props => /*@refresh jsx-skip*/_$getNextElement(_tmpl$), {
location: "example.jsx:3:15",
signature: "4b145a58"
});
export function Foo(...args) {
return /*@refresh jsx-skip*/_$createComponent(Foo_1, {});
}
if (import.meta.hot) {
_$$refresh("esm", import.meta.hot, _REGISTRY);
}"
`;

exports[`esm (client, hydratable) > ExportNamedDeclaration w/ FunctionExpression > should transform ExportNamedDeclaration w/ FunctionExpression with valid Component name and params 1`] = `
"import { template as _$template } from "solid-js/web";
import { createComponent as _$createComponent } from "solid-js/web";
Expand Down Expand Up @@ -558,6 +600,27 @@ if (import.meta.hot) {
}"
`;

exports[`esm (client, hydratable) > FunctionDeclaration > should skip FunctionDeclaration with valid Component name and a rest parameter 1`] = `
"import { template as _$template } from "solid-js/web";
import { createComponent as _$createComponent } from "solid-js/web";
import { getNextElement as _$getNextElement } from "solid-js/web";
var _tmpl$ = /*#__PURE__*/_$template(\`<h1>Foo\`);
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 Foo_1 = _$$component(_REGISTRY, "Foo_1", _props => /*@refresh jsx-skip*/_$getNextElement(_tmpl$), {
location: "example.jsx:3:15",
signature: "4b145a58"
});
function Foo(...args) {
return /*@refresh jsx-skip*/_$createComponent(Foo_1, {});
}
if (import.meta.hot) {
_$$refresh("esm", import.meta.hot, _REGISTRY);
}"
`;

exports[`esm (client, hydratable) > FunctionDeclaration > should transform FunctionDeclaration with valid Component name and params 1`] = `
"import { template as _$template } from "solid-js/web";
import { createComponent as _$createComponent } from "solid-js/web";
Expand Down Expand Up @@ -781,6 +844,27 @@ if (import.meta.hot) {
}"
`;

exports[`esm (client, hydratable) > VariableDeclarator > ArrowFunctionExpression > should skip VariableDeclarator w/ ArrowFunctionExpression with valid Component name and a rest parameter 1`] = `
"import { template as _$template } from "solid-js/web";
import { createComponent as _$createComponent } from "solid-js/web";
import { getNextElement as _$getNextElement } from "solid-js/web";
var _tmpl$ = /*#__PURE__*/_$template(\`<h1>Foo\`);
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 Foo_1 = _$$component(_REGISTRY, "Foo_1", _props => /*@refresh jsx-skip*/_$getNextElement(_tmpl$), {
location: "example.jsx:3:17",
signature: "4b145a58"
});
const Foo = (...args) => {
return /*@refresh jsx-skip*/_$createComponent(Foo_1, {});
};
if (import.meta.hot) {
_$$refresh("esm", import.meta.hot, _REGISTRY);
}"
`;

exports[`esm (client, hydratable) > VariableDeclarator > ArrowFunctionExpression > should transform VariableDeclarator w/ ArrowFunctionExpression with valid Component name and params 1`] = `
"import { template as _$template } from "solid-js/web";
import { createComponent as _$createComponent } from "solid-js/web";
Expand Down Expand Up @@ -1004,6 +1088,27 @@ if (import.meta.hot) {
}"
`;

exports[`esm (client, hydratable) > VariableDeclarator > FunctionExpression > should skip VariableDeclarator w/ FunctionExpression with valid Component name and a rest parameter 1`] = `
"import { template as _$template } from "solid-js/web";
import { createComponent as _$createComponent } from "solid-js/web";
import { getNextElement as _$getNextElement } from "solid-js/web";
var _tmpl$ = /*#__PURE__*/_$template(\`<h1>Foo\`);
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 Foo_1 = _$$component(_REGISTRY, "Foo_1", _props => /*@refresh jsx-skip*/_$getNextElement(_tmpl$), {
location: "example.jsx:3:17",
signature: "4b145a58"
});
const Foo = function (...args) {
return /*@refresh jsx-skip*/_$createComponent(Foo_1, {});
};
if (import.meta.hot) {
_$$refresh("esm", import.meta.hot, _REGISTRY);
}"
`;

exports[`esm (client, hydratable) > VariableDeclarator > FunctionExpression > should transform VariableDeclarator w/ FunctionExpression with valid Component name and params 1`] = `
"import { template as _$template } from "solid-js/web";
import { createComponent as _$createComponent } from "solid-js/web";
Expand Down
105 changes: 105 additions & 0 deletions tests/client-hydratable/__snapshots__/rspack-esm.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,27 @@ if (import.meta.webpackHot) {
}"
`;

exports[`rspack-esm (client, hydratable) > ExportDefaultDeclaration w/ FunctionExpression > should skip ExportDefaultDeclaration w/ FunctionExpression with valid Component name and a rest parameter 1`] = `
"import { template as _$template } from "solid-js/web";
import { createComponent as _$createComponent } from "solid-js/web";
import { getNextElement as _$getNextElement } from "solid-js/web";
var _tmpl$ = /*#__PURE__*/_$template(\`<h1>Foo\`);
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 Foo_1 = _$$component(_REGISTRY, "Foo_1", _props => /*@refresh jsx-skip*/_$getNextElement(_tmpl$), {
location: "example.jsx:3:15",
signature: "4b145a58"
});
export default function Foo(...args) {
return /*@refresh jsx-skip*/_$createComponent(Foo_1, {});
}
if (import.meta.webpackHot) {
_$$refresh("rspack-esm", import.meta.webpackHot, _REGISTRY);
}"
`;

exports[`rspack-esm (client, hydratable) > ExportDefaultDeclaration w/ FunctionExpression > should transform ExportDefaultDeclaration w/ FunctionExpression with valid Component name and params 1`] = `
"import { template as _$template } from "solid-js/web";
import { createComponent as _$createComponent } from "solid-js/web";
Expand Down Expand Up @@ -329,6 +350,27 @@ if (import.meta.webpackHot) {
}"
`;

exports[`rspack-esm (client, hydratable) > ExportNamedDeclaration w/ FunctionExpression > should skip ExportNamedDeclaration w/ FunctionExpression with valid Component name and a rest parameter 1`] = `
"import { template as _$template } from "solid-js/web";
import { createComponent as _$createComponent } from "solid-js/web";
import { getNextElement as _$getNextElement } from "solid-js/web";
var _tmpl$ = /*#__PURE__*/_$template(\`<h1>Foo\`);
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 Foo_1 = _$$component(_REGISTRY, "Foo_1", _props => /*@refresh jsx-skip*/_$getNextElement(_tmpl$), {
location: "example.jsx:3:15",
signature: "4b145a58"
});
export function Foo(...args) {
return /*@refresh jsx-skip*/_$createComponent(Foo_1, {});
}
if (import.meta.webpackHot) {
_$$refresh("rspack-esm", import.meta.webpackHot, _REGISTRY);
}"
`;

exports[`rspack-esm (client, hydratable) > ExportNamedDeclaration w/ FunctionExpression > should transform ExportNamedDeclaration w/ FunctionExpression with valid Component name and params 1`] = `
"import { template as _$template } from "solid-js/web";
import { createComponent as _$createComponent } from "solid-js/web";
Expand Down Expand Up @@ -558,6 +600,27 @@ if (import.meta.webpackHot) {
}"
`;

exports[`rspack-esm (client, hydratable) > FunctionDeclaration > should skip FunctionDeclaration with valid Component name and a rest parameter 1`] = `
"import { template as _$template } from "solid-js/web";
import { createComponent as _$createComponent } from "solid-js/web";
import { getNextElement as _$getNextElement } from "solid-js/web";
var _tmpl$ = /*#__PURE__*/_$template(\`<h1>Foo\`);
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 Foo_1 = _$$component(_REGISTRY, "Foo_1", _props => /*@refresh jsx-skip*/_$getNextElement(_tmpl$), {
location: "example.jsx:3:15",
signature: "4b145a58"
});
function Foo(...args) {
return /*@refresh jsx-skip*/_$createComponent(Foo_1, {});
}
if (import.meta.webpackHot) {
_$$refresh("rspack-esm", import.meta.webpackHot, _REGISTRY);
}"
`;

exports[`rspack-esm (client, hydratable) > FunctionDeclaration > should transform FunctionDeclaration with valid Component name and params 1`] = `
"import { template as _$template } from "solid-js/web";
import { createComponent as _$createComponent } from "solid-js/web";
Expand Down Expand Up @@ -781,6 +844,27 @@ if (import.meta.webpackHot) {
}"
`;

exports[`rspack-esm (client, hydratable) > VariableDeclarator > ArrowFunctionExpression > should skip VariableDeclarator w/ ArrowFunctionExpression with valid Component name and a rest parameter 1`] = `
"import { template as _$template } from "solid-js/web";
import { createComponent as _$createComponent } from "solid-js/web";
import { getNextElement as _$getNextElement } from "solid-js/web";
var _tmpl$ = /*#__PURE__*/_$template(\`<h1>Foo\`);
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 Foo_1 = _$$component(_REGISTRY, "Foo_1", _props => /*@refresh jsx-skip*/_$getNextElement(_tmpl$), {
location: "example.jsx:3:17",
signature: "4b145a58"
});
const Foo = (...args) => {
return /*@refresh jsx-skip*/_$createComponent(Foo_1, {});
};
if (import.meta.webpackHot) {
_$$refresh("rspack-esm", import.meta.webpackHot, _REGISTRY);
}"
`;

exports[`rspack-esm (client, hydratable) > VariableDeclarator > ArrowFunctionExpression > should transform VariableDeclarator w/ ArrowFunctionExpression with valid Component name and params 1`] = `
"import { template as _$template } from "solid-js/web";
import { createComponent as _$createComponent } from "solid-js/web";
Expand Down Expand Up @@ -1004,6 +1088,27 @@ if (import.meta.webpackHot) {
}"
`;

exports[`rspack-esm (client, hydratable) > VariableDeclarator > FunctionExpression > should skip VariableDeclarator w/ FunctionExpression with valid Component name and a rest parameter 1`] = `
"import { template as _$template } from "solid-js/web";
import { createComponent as _$createComponent } from "solid-js/web";
import { getNextElement as _$getNextElement } from "solid-js/web";
var _tmpl$ = /*#__PURE__*/_$template(\`<h1>Foo\`);
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 Foo_1 = _$$component(_REGISTRY, "Foo_1", _props => /*@refresh jsx-skip*/_$getNextElement(_tmpl$), {
location: "example.jsx:3:17",
signature: "4b145a58"
});
const Foo = function (...args) {
return /*@refresh jsx-skip*/_$createComponent(Foo_1, {});
};
if (import.meta.webpackHot) {
_$$refresh("rspack-esm", import.meta.webpackHot, _REGISTRY);
}"
`;

exports[`rspack-esm (client, hydratable) > VariableDeclarator > FunctionExpression > should transform VariableDeclarator w/ FunctionExpression with valid Component name and params 1`] = `
"import { template as _$template } from "solid-js/web";
import { createComponent as _$createComponent } from "solid-js/web";
Expand Down
Loading
Loading