I'm updating a Svelte component/framework library (using Vite / Sveltekit) that was created using npm create svelte
. I'm using the default compilation setup.
The library must be able to render internally a Svelte component. However Svelte 5 changed the way this happen and I want to preserve compatibility no matter if the application using the library uses Svelte 4 or 5.
I added in the library a condition around the version. It gives something like this:
import { VERSION } from 'svelte/compiler';
const SVELTE_MAJOR_VERSION = parseInt(VERSION.split('.')[0]);
const { html, head } = await (async () => {
if (SVELTE_MAJOR_VERSION < 5) {
return SSR.render({ id, initialPage });
}
else {
const { render } = await import('svelte/server');
return render(SSR, { props: { id, initialPage } });
}
})();
return {
body: html,
head: [head],
};
The package import('svelte/server')
doesn't exist under Svelte 4 which is why I must somehow import it conditionally/dynamically. It seems that I can build successfully if I use Svelte 5 as a dependency, however I can't build it using Svelte 4. Also, the dist
files generated when using Svelte 5 are not usable under a Svelte 4 application either.
In case this is of any help, here is the output of the failed build using Svelte 4 as a dependency.
vite v5.2.11 building for production...
ā 16 modules transformed.
x Build failed in 199ms
error during build:
Error: [commonjs--resolver] Missing "./server" specifier in "svelte" package
at e (file:///Users/james/Projects/inertia/node_modules/.pnpm/vite@5.2.11_@types+node@20.12.11/node_modules/vite/dist/node/chunks/dep-cNe07EU9.js:47597:25)
at n (file:///Users/james/Projects/inertia/node_modules/.pnpm/vite@5.2.11_@types+node@20.12.11/node_modules/vite/dist/node/chunks/dep-cNe07EU9.js:47597:627)
at o (file:///Users/james/Projects/inertia/node_modules/.pnpm/vite@5.2.11_@types+node@20.12.11/node_modules/vite/dist/node/chunks/dep-cNe07EU9.js:47597:1297)
at resolveExportsOrImports (file:///Users/james/Projects/inertia/node_modules/.pnpm/vite@5.2.11_@types+node@20.12.11/node_modules/vite/dist/node/chunks/dep-cNe07EU9.js:48287:20)
at resolveDeepImport (file:///Users/james/Projects/inertia/node_modules/.pnpm/vite@5.2.11_@types+node@20.12.11/node_modules/vite/dist/node/chunks/dep-cNe07EU9.js:48306:31)
at tryNodeResolve (file:///Users/james/Projects/inertia/node_modules/.pnpm/vite@5.2.11_@types+node@20.12.11/node_modules/vite/dist/node/chunks/dep-cNe07EU9.js:48031:20)
at Object.resolveId (file:///Users/james/Projects/inertia/node_modules/.pnpm/vite@5.2.11_@types+node@20.12.11/node_modules/vite/dist/node/chunks/dep-cNe07EU9.js:47781:28)
at file:///Users/james/Projects/inertia/node_modules/.pnpm/rollup@4.17.2/node_modules/rollup/dist/es/shared/node-entry.js:19778:40
at async PluginDriver.hookFirstAndGetPlugin (file:///Users/james/Projects/inertia/node_modules/.pnpm/rollup@4.17.2/node_modules/rollup/dist/es/shared/node-entry.js:19678:28)
at async resolveId (file:///Users/james/Projects/inertia/node_modules/.pnpm/rollup@4.17.2/node_modules/rollup/dist/es/shared/node-entry.js:18359:26)
It appears doing this will work
async function dynamicImport(modulePath: string) {
try {
return await import(/* @vite-ignore */ modulePath)
} catch {
return null
}
}
// Somewhere
const { render } = await dynamicImport('svelte/server');
But this wouldn't
async function dynamicImport() {
try {
return await import(/* @vite-ignore */ 'svelte/server')
} catch {
return null
}
}
// Somewhere
const { render } = await dynamicImport();
My guess is because vite can't guess the import before it actually happens if we use a function without dynamic parameter