S
SolidJS5mo ago
lars

SolidJS UI library + Astro

Hey, would anyone happen to have experience using a UI library together with Astro? I can get it working if I just export some simple components, but if I then add an import to another SolidJS library (eg. @kobalte/core or @ark-ui/solid to help build my primitives), then I run into:
The requested module 'solid-js/web' does not provide an export named 'effect'
The requested module 'solid-js/web' does not provide an export named 'effect'
At first I was using tsup with tsup-preset-solid, but at this point I’ve tried almost everything I can think of: rollup, vite, esbuild, or just plain tsc. On the other hand, tried a bunch of different Astro configs, but no matter what I do I can’t get past this error. Are there any example projects with such a setup somewhere?
25 Replies
bigmistqke
bigmistqke5mo ago
not an astro expert, but from what i have seen on this discord, i think u have to add @kobalte/core to noExternal https://vitejs.dev/config/ssr-options.html#ssr-noexternal
lars
lars5mo ago
i came across that bit of info as well, but it unfortunately didn't seem to have an effect with my setup what i'm a little afraid of is that adding @kobalte/core to noExternal might only get things working if you were using astro + solid + kobalte all in a single Astro app
bigmistqke
bigmistqke5mo ago
if you were using astro + solid + kobalte all in a single Astro app
that's not what you want? i might not understand the question then 🙂
Brendonovich
Brendonovich5mo ago
I assume your UI library is in a separate package to your Astro app? I'm not sure if it'l solve it but make sure that the solid export condition in your package.json is pointing to jsx/tsx, not pre-built js
lars
lars5mo ago
it is, I just mean that noExternal might be the workaround if you directly consume astro + solid + kobalte in an astro app, rather than importing a library that uses solid + kobalte my vague impression is that tsup-preset-solid is the most up to date way to set up UI libraries with solid right now. the config I ran looked like this:
import { defineConfig } from 'tsup';
import * as preset from 'tsup-preset-solid';

const presetOptions: preset.PresetOptions = {
entries: [
{
// Entries with a '.tsx' extension will have a generated `solid` export
// condition.
entry: 'src/index.tsx',
},
],
};

export default defineConfig(config => {
const parsedOptions = preset.parsePresetOptions(
presetOptions,
!!config.watch,
);

const packageFields = preset.generatePackageExports(parsedOptions);
preset.writePackageJson(packageFields);

return preset.generateTsupOptions(parsedOptions);
});
import { defineConfig } from 'tsup';
import * as preset from 'tsup-preset-solid';

const presetOptions: preset.PresetOptions = {
entries: [
{
// Entries with a '.tsx' extension will have a generated `solid` export
// condition.
entry: 'src/index.tsx',
},
],
};

export default defineConfig(config => {
const parsedOptions = preset.parsePresetOptions(
presetOptions,
!!config.watch,
);

const packageFields = preset.generatePackageExports(parsedOptions);
preset.writePackageJson(packageFields);

return preset.generateTsupOptions(parsedOptions);
});
this automatically writes these properties to the package.json (including a condition for solid - but it'd still end up with the export error above)
"main": "./dist/index.js",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
"solid": "./dist/index.jsx",
"import": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
},
"type": "module",
"browser": {},
"typesVersions": {}
"main": "./dist/index.js",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
"solid": "./dist/index.jsx",
"import": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
},
"type": "module",
"browser": {},
"typesVersions": {}
Brendonovich
Brendonovich5mo ago
Are you planning on actually publishing your library to npm?
lars
lars5mo ago
Yeah, but it’s part of a closed source monorepo for now. Are you thinking of instead eg linking the unbuilt TS via pnpm? I tried that thinking it’d for sure resolve the issue, but weirdly enough I still encountered the exports error
Brendonovich
Brendonovich5mo ago
yeah letting astro take care of the ts has worked for me before
lars
lars5mo ago
like the i way i did it was adding this to the lib's package.json
"main": "./src/index.tsx",
"module": "./src/index.tsx"
"main": "./src/index.tsx",
"module": "./src/index.tsx"
together with noExternal: ['@kobalte/core'] in the astro config (and also a workspace dep for the ui lib in the package.json)
Brendonovich
Brendonovich5mo ago
not sure what the exact structure of your monorepo is like but here's mine using astro before i converted to solidstart https://github.com/Brendonovich/macrograph/tree/9a37129a2d063442ee0261479e46b6ea42f6a669 @macrograph/web imports @macrograph/interface which imports @kobalte/core
Brendonovich
Brendonovich5mo ago
didn't need noExternal but do have a solid export condition in @macrograph/interface
No description
lars
lars5mo ago
were you using the same package.json before converting to solid start? I get an error when importing the ui lib
The path "." is not currently exported by package "@org/ui":
The path "." is not currently exported by package "@org/ui":
if i then add a condition for import, it goes away but i then get the original error message The requested module 'solid-js/web' blah blah
"main": "./src/index.tsx",
"exports": {
".": {
"solid": "./src/index.tsx",
"import": "./src/index.tsx",
"types": "./src/index.tsx"
}
},
"type": "module"
"main": "./src/index.tsx",
"exports": {
".": {
"solid": "./src/index.tsx",
"import": "./src/index.tsx",
"types": "./src/index.tsx"
}
},
"type": "module"
Brendonovich
Brendonovich5mo ago
that screenshot is the package.json at the time of using astro not sure if it makes a difference, but i consume @macrograph/interface in a dedicated tsx file in astro, then import that into the actual page
lars
lars5mo ago
damn it just does not want to work. i think i'll clone down your repo at your astro commit and gradually replace it with my own code 🥲 at least i now know that it should be possible, unless this is some regressive change in one of my deps. i'm sure you've saved me a ton of time here either way, so thank you
Brendonovich
Brendonovich5mo ago
no worries, hope you get it working
bigmistqke
bigmistqke5mo ago
@𝕒𝕣𝕤𝕙 would u mb know the answer to this one?
lars
lars5mo ago
@Brendonovich @bigmistqke finally got it working, but anticlimactically, i can't track down what actually got it working. i have an earlier commit where i'm running the same configs, so i'm leaning towards something weird being stuck in the dist or node_modules dirs the final working config (package.json in the ui lib):
"scripts": {
"build": "tsup",
},
"type": "module",
"main": "./dist/index.js",
"exports": {
".": {
"solid": "./dist/index.jsx",
"import": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
},
"./styles": "./dist/index.css"
},
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"browser": {},
"typesVersions": {}
"scripts": {
"build": "tsup",
},
"type": "module",
"main": "./dist/index.js",
"exports": {
".": {
"solid": "./dist/index.jsx",
"import": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
},
"./styles": "./dist/index.css"
},
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"browser": {},
"typesVersions": {}
tsup config:
import { defineConfig } from 'tsup';
import * as preset from 'tsup-preset-solid';

const presetOptions: preset.PresetOptions = {
entries: [
{
// Entries with a '.tsx' extension will have a generated `solid` export
// condition.
entry: 'src/index.tsx',
},
],
};

export default defineConfig(config => {
const parsedOptions = preset.parsePresetOptions(
presetOptions,
!!config.watch,
);

return preset.generateTsupOptions(parsedOptions);
});
import { defineConfig } from 'tsup';
import * as preset from 'tsup-preset-solid';

const presetOptions: preset.PresetOptions = {
entries: [
{
// Entries with a '.tsx' extension will have a generated `solid` export
// condition.
entry: 'src/index.tsx',
},
],
};

export default defineConfig(config => {
const parsedOptions = preset.parsePresetOptions(
presetOptions,
!!config.watch,
);

return preset.generateTsupOptions(parsedOptions);
});
astro config is completely stock (no noExternal or anything like that) thanks again for the help 🙏
Brendonovich
Brendonovich5mo ago
weird, at least it works now haha
lars
lars5mo ago
well shit, turns out it wasn't working at all. the issue happens when importing the UI library (that is using kobalte) in a .ts file that is then imported by a .astro file. any imports directly in the .astro file work fine even if all the exports from the UI library are hardcoded to point to the .jsx output, it still errors with No matching export in "../../node_modules/.pnpm/solid-js@1.8.7/node_modules/solid-js/web/dist/server.js" for import "effect" it's strange how the file type has an effect on how the import behaves. you wouldn't happen to know anything about this @Brendonovich? i'll likely end up refactoring the ui library to export the unbuilt TS, but it's a shame that it's such a pain to get a library working if you want the build process encapsulated within the lib
𝕒𝕣𝕤𝕙
... when importing the UI library (that is using kobalte) in a .ts file that is ...
.ts or .tsx?
lars
lars5mo ago
unfortunately seeing the same behavior with both extensions
Brendonovich
Brendonovich5mo ago
is your project open source? i'd be happy to take a look
lars
lars5mo ago
it's not at the moment. i could add you as a collaborator though?
Brendonovich
Brendonovich5mo ago
yeah sure
lars
lars5mo ago
gimme like 10min. need to clean up a couple things first