vite-plugin-solid icon indicating copy to clipboard operation
vite-plugin-solid copied to clipboard

I updated `vite-plugin-solid` and now namespaces merged with components are no longer allowed

Open AFatNiBBa opened this issue 4 months ago • 7 comments

Describe the bug

If I create a .tsx file with this content

function A() {
    return <>1</>
}

namespace A {
    export const a = 1;
}

console.log(A);

It throws this error when I load the page (Running vite dev)

Transform failed with 1 error:
ERROR: The symbol "A" has already been declared

I tried downgrading vite-plugin-solid and it worked

npm i [email protected]

(On the playground it always works)

Your Example Website or App

(localhost)

Steps to Reproduce the Bug or Issue

  1. Put a merged namespace declaration WITH A COMPONENT somewhere
  2. Run vite dev
  3. Go to the web page

Expected behavior

I expected this allowed TS syntax to not stop working

Screenshots or Videos

No response

Platform

  • OS: Windows
  • Browser: Edge
  • Version: 120.0.2210.77

Additional context

No response

AFatNiBBa avatar Feb 05 '24 09:02 AFatNiBBa

Okay so it seems that namespace A is actually A = {...} (an assignment, rather than a declaration).

It's a very weird edge case honestly, although I would've expected it to raise an error too if not for functions to be re-assignable, and if namespaces transformed into variable declarations. Not sure if this should be fixed.

Besides assignment to function A was there any other case where a namespace of similar name is desirable?

lxsmnsyc avatar Feb 14 '24 06:02 lxsmnsyc

update:

Upon checking, since we convert every function component into a HOC (declared via a variable), it seems that TS compiles weirdly for it.

Example:

const A = () => {

};

namespace A {
  export const hello = 'world';
}
const A = () => {
};
var A;
(function (A) {
    A.hello = 'world';
})(A || (A = {}));

and since we rely on HOC to apply HMR, this is most likely a wontfix. However, I would recommend just assigning to the function directly.

related: https://github.com/microsoft/TypeScript/issues/51417

lxsmnsyc avatar Feb 14 '24 06:02 lxsmnsyc

Isn't it possible to use var?

var A = () => {
};
var A;
(function (A) {
    A.hello = 'world';
})(A || (A = {}));

AFatNiBBa avatar Feb 19 '24 09:02 AFatNiBBa

@AFatNiBBa your example code shows why it won't work.

lxsmnsyc avatar Feb 20 '24 02:02 lxsmnsyc

Do you transform the function to make HMR work BEFORE or AFTER transpiling typescript? Because if you were to do it after you could declare the function with var

//     ↓
export var A = _$$component(_REGISTRY, "A", function A() {
    // ...
}, {
    location: "..."
});

And if you're doing it before the transpiling because if you were to do it after you would not know where the JSX was, then you could mark the function in some way (Maybe with a comment?) in order to still find it at the end

AFatNiBBa avatar Feb 20 '24 14:02 AFatNiBBa

@AFatNiBBa

Do you transform the function to make HMR work BEFORE or AFTER transpiling typescript?

there's no TypeScript transpilation happening, as it is deferred to ESBuild.

And if you're doing it before the transpiling because if you were to do it after you would not know where the JSX was, then you could mark the function in some way (Maybe with a comment?) in order to still find it at the end

I'm not sure I understood the suggestion.

lxsmnsyc avatar Feb 20 '24 17:02 lxsmnsyc

I'm not sure I understood the suggestion

Don't worry, if the transformation must happen at the TypeScript level, the suggestion doesn't apply anyway

AFatNiBBa avatar Feb 20 '24 17:02 AFatNiBBa

Isn't it possible to change

export var A = _$$component(_REGISTRY, "A", function A() {
    // ...
}, {
    location: "..."
});

Into

import { createComponent } from "solid-js";

const RANDOM_NAME = _$$component(_REGISTRY, "A", function A() {
    // ...
}, {
    location: "..."
});

// Wrapper
export function A(x) {
    return createComponent(RANDOM_NAME, x);
}

// Now this is allowed
export namespace A {
    export const value = 56;
}

AFatNiBBa avatar May 11 '24 02:05 AFatNiBBa

No, that would introduce some new layer of issues. I'm sorry, this might be a no-fix as TS is to be blamed here for this inconsistency. I could recommend you dropping the namespace usage (since it's not even recommended anymore by majority) but that's just one workaround.

lxsmnsyc avatar May 11 '24 08:05 lxsmnsyc

TypeScript is not to blame this time in my opinion, because functions have always behaved differently from lambdas, It is the plugin's responsability to ensure that if I write a function then a function will come out instead of a lambda expression.

I think you shouldn't give priority to this issue, but it's something that has to be done eventually

AFatNiBBa avatar May 11 '24 12:05 AFatNiBBa

I'm sorry but something about the current transform is never going to be touched, we haven't even solved the SSR problem with the current transform, we'll be digging a whole new level of complexity if we do this "component in a component" kind of thing (which btw, also ruins the dev experience at some point).

lxsmnsyc avatar May 11 '24 16:05 lxsmnsyc