feat(solid): initial draft implementation
Motivation
This PR introduces an initial implementation of linaria processor for solid.
Summary
The idea is to completely eliminate any extra runtime components and transpile the code into intermediate representation suitable for further transpilation with solid (this means, the processor doesn't transpile the code down to solid's output, it should be the responsibility of the end developer to pipe transformations correctly: first goes @linaria/solid, then the code must be transformed by solid with either babel plugin, vite plugin etc.)
Test plan
The tests are not working at the moment as it turns out it's quite hard to write any meaningful tests without the actual transpilation step. Testing snapshots seems too fragile and unmaintainable.
Instead I tried to take an approach on transpiling the code of tests with linaria+solid in a custom jest transform. It works but I'd still like to avoid testing stringified (or jsonified) output. Instead, it would be really cool to make use of JSDom to run the output, render generated components and test interaction with them. E.g. a reactive prop on a component must update components runtime structure etc.
At the moment I'm able to transpile the code with both jest transform (seamlessly transpiles the whole test and we can use regular TSX to write the code - huge win) and with a custom transpile step (takes a stringified input and transpiles down to solid's output - not so good as we lose TSX and still need to eval the code somehow).
Another thing to consider is that jest transform throws away generated css and I'd like to render it with JSDom so that interactions with components can be fully tested (e.g. when we set a prop on a component, component's color turns blue).
But this would require adding a build step with esbuild/vite/etc and somehow integrate it into jest+jsdom - the first thing that comes to mind is a custom jest environment based on jest-environment-jsdom, this might work. Also we could take a look at @testing-library/react and see what they are doing and try to implement the same things in the jest environment.
All these turned out to be much more work, so I stopped on that as unfortunately I don't have enough time at the moment.
Still, I'm opening the PR to demonstrate possible implementation of processor, as @Anber suggested in DM 👌
⚠️ No Changeset found
Latest commit: b03f7338bf739d5d32b90a43f1fd76e06ffda81b
Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.
This PR includes no changesets
When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types
Click here to learn what changesets are, and how to add one.
Click here if you're a maintainer who wants to add a changeset to this PR
Our implementation
Work in progress on this thread?
@usmanyunusov yeah, in progress but I have very little time now to work on it.
@Anber smth weird is happening to test snapshots in interop package, I have newlines removed in my output but they are expected in snapshots. This is weird since the repo is using pnpm and there should be no package version collisions.

What's interesting is that it's fine on master branch 🤔
I don't know why, but adding "@babel/core": "7.18.9" (which is the same exact version as in the repo root) to devDependencies in /packages/solid/package.json updates babel's transitive dependencies 🤷♂️

@Anber https://github.com/pnpm/pnpm/issues/4868
Ok I was finally able to fix this.
Seems running pnpm i with manually added dependencies in package.json is quite different from running pnpm add -D in the package directory. So, pnpm add -D @babel/[email protected] solid-js@^1.6.2 fixes the issue (note there're no ~/^ on @babel/types dependency). But this breaks syncpack, so I had to tweak pnpm-lockfile.yml manually and add ^ there and in package.json.
I also dropped all tests in favor of adding a real solid example in /examples directory. This way we could combine tests with examples and not mess a lot with jsdom.
ok, I finished the basic example built with solid-js, vite, @linaria/vite, and vite-plugin-solid, it's available at /examples/solid, the command to run is the regular pnpm start
@Anber ready for review
@Anber thanks for enabling the CI on this PR 🙏 ~there's something weird, I'm also on Node v16.16.0, but CI says it can't install node typings https://github.com/callstack/linaria/actions/runs/3554400920/jobs/5970646566#step:7:369 But they are there, and locally everything is fine 🤷♂️~ No, they are missing, adding them in a moment
🙏
when can i expect this feature release?
I just tested it quickly and don't fully understand solid, please correct me if I'm wrong.
This seems to lose reactivity on props in some cases:
const HelloWorldSolid = () => {
const [count, setCount] = createSignal(0);
return (
<div>
<Heading style={{"margin-top": `${count()}px`}}>
count: {count()}
</Heading>
<button onClick={() => setCount((c) => c + 1)}> increment</button>
</div>
);
};
const Heading = styled.h1`
background: red;
`;
The text in the heading updates correctly, but the margin is not applied.
If you replace Heading with h1 it works.
edit:
By quickly checking the transform, it looks like getStyleConstantValueExpression does unwrap props.style which leads to loss of reactivity. Perhaps wrapping the declaration in createMemo would propagate reactivity, but there might be more performant ways to handle it.
Is this PR abandoned?
What's up with this PR?
just use tw/unocss + attributify much better dx: framework/language agnostic, shorter then inlining css, no need to write style merging logic for every component, just spread props.
just use tw/unocss + attributify much better dx: framework/language agnostic, shorter then inlining css, no need to write style merging logic for every component, just spread props.
This is just another DSL. I am looking for a way to write actual CSS, not tailwind shorthands in made up attributes that may or may not clash with actual JSX props or HTML attributes
just use tw/unocss + attributify much better dx: framework/language agnostic, shorter then inlining css, no need to write style merging logic for every component, just spread props.
This is just another DSL. I am looking for a way to write actual CSS, not tailwind shorthands in made up attributes that may or may not clash with actual JSX props or HTML attributes
There are some drawbacks, but I think it's much better then using linaria. You don't need this rocket-science euristic compilier that slows down dev builds and potentially breaks your code.
You can start with simple pure class="". Or you can even try web components, so you will also co-locate your css with components. These are much better options for any projects in long-term run, because that tools are much easier to work with and maintain, also they're language-agnostic.
Linaria, on the other hand, has strong legacy vibes.
I spent year with unocss after linaria and it feels so much better to work with.
@MrFoxPro let's keep this PR focused on linaria and solid. This is not the right place to promote failwind or any other framework.
@Tetrax-10 @NightmanCZ90 @ivancuric I see all your comments here but unfortunately I don't have spare time to work on this. Your are kindly welcome to take on the initiative here 🙏