Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recipe: Compiling a sveltekit library project directly to web components js output #10320

Closed
jnehlmeier opened this issue Jul 5, 2023 · 5 comments
Labels
pkg:svelte-package Issues related to svelte-package

Comments

@jnehlmeier
Copy link

jnehlmeier commented Jul 5, 2023

Describe the problem

Sveltekit allows creating a library project which is great since you can use the routes folder to play with your library directly in the same project.

Svelte allows compiling components to web components.

It should be possible to have a sveltekit library project that directly compiles to web components JS output and you only have to adjust how the JS output should be generated via rollup/vite config (one file per web component + vendor.js, everything in a single file, iife vs. module output).

Describe the proposed solution

Ideally npm create svelte@latest my-app should ask for such a project type (maybe named "web components library" in addition to "library") and set-up the build correctly.

Alternatives considered

Currently the only solution I found using some google-fu was to create a second vite config that takes the output of the sveltekit build and compiles it again to web components js.

This works but feels super strange since I believe this should be possible in a single sveltekit library build using some sveltekit option.

svelte.config.js

import adapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/kit/vite';

/** @type {import('@sveltejs/kit').Config} */
const config = {
	preprocess: vitePreprocess(),

	kit: {
		adapter: adapter()
	},

	compilerOptions: {
		customElement: true
	}
};

export default config;

vite.config.js

import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';

export default defineConfig({
	plugins: [sveltekit()]
});

This produces a svelte js library in dist folder containing index.js that exports components, svelte components (*.svelte) and *.d.ts files.

Then I use vite.webcomponents.config.js for a second build step:

import { svelte } from '@sveltejs/vite-plugin-svelte';
import { defineConfig } from 'vite';
import { resolve } from 'path';

export default defineConfig({
	build: {
		lib: {
			entry: resolve(__dirname, 'dist/index.js'),
			name: 'Components',
			fileName: 'components',
			formats: ['iife']
		},
		outDir: 'dist-js'
	},
	plugins: [svelte()]
});

The second file uses the output in the dist folder and uses svelte again to produce web components js output in iife format.

Compilation then happens with vite build && vite -c vite.webcomponents.config.js build

Importance

would make my life easier

Additional Information

No response

@dummdidumm dummdidumm added the pkg:svelte-package Issues related to svelte-package label Jul 5, 2023
@dummdidumm
Copy link
Member

Closing as duplicate of #2572 and #10073 . Your workaround looks good in the meantime 👍

@matths
Copy link
Contributor

matths commented Sep 15, 2023

I don't see that this is a duplicate of the other two issues and I do not see a solution in sight as well.
I think, it is a valid use case to have a single project / repository with a shared code base (maybe even a Sveltekit one) and then to have multiple build targets / entry points to compile Svelte components and/or custom-elements to use in other projects.
I know how to do this using the "old" way using Rollup, but what's really missing is some documentation how things work out with Vite, which seems to be the preferred bundler nowadays.

@henryjameslau
Copy link

henryjameslau commented Jan 19, 2024

import { vitePreprocess } from '@sveltejs/kit/vite'; in svelte.config.js has now changed to import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' for anyone else trying to follow along.

@add-n2x
Copy link

add-n2x commented Jul 26, 2024

@dummdidumm since there are quite a few up-votes, is there a chance this gets re-opened?

@arcadeJHS
Copy link

@jnehlmeier I'm also working on a library of web components compiled with Sveltekit.
The solution I've found so far is satisfactory for me, and it's very similar to yours.

In my case too, I created a second Vite config file, but without the need to go through the Sveltekit build output.

For reference, the versions of the main packages I'm using are:

"@rollup/plugin-replace": "^5.0.7",
"@sveltejs/adapter-auto": "^3.0.0",
"@sveltejs/kit": "^2.0.0",
"@sveltejs/package": "^2.0.0",
"@sveltejs/vite-plugin-svelte": "^3.0.0",
"svelte": "^4.2.7",
"typescript": "^5.0.0",
"vite": "^5.0.11",

svelte.config.js and vite.config.ts are almost identical.

svelte.config.js

import adapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';

const config = {
	preprocess: vitePreprocess(),

	kit: {
		adapter: adapter()
	},

	compilerOptions: {
		customElement: false
	}
};

export default config;

vite.config.ts

import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vitest/config';

export default defineConfig({
	plugins: [
		sveltekit()
	],
	test: {
		include: ['src/**/*.{test,spec}.{js,ts}']
	}
});

And then I have vite.webcomponents.config.js:

import { svelte } from '@sveltejs/vite-plugin-svelte';
import { defineConfig } from 'vite';
import { resolve } from 'path';
import replace from '@rollup/plugin-replace';

const LIBRARY_PREFIX = 'stg';

export default defineConfig({
	build: {
		lib: {
			entry: resolve(__dirname, 'src/lib/index.ts'),
			name: 'AiSearchWebComponents',
			fileName: (format) => `ai.search.web.components.${format}.js`,
			formats: ['es', 'umd']
		},
		outDir: 'dist-web-components'
	},
	plugins: [
		replace({
			preventAssignment: true,
			'PREFIX': LIBRARY_PREFIX ?? 'stg',
		}),
		svelte({ 
			compilerOptions: { 
				customElement: true 
			} 
		})
	]
});

I am re-exporting the components from src/lib/index.ts:

export { default as ChatSearch } from './components/ChatSearch.svelte';
export { default as Counter } from './components/Counter.svelte';

LIBRARY_PREFIX is used just to prefix the custom elements.

For instance, where I define <svelte:options customElement="PREFIX-chat-search" />, the build creates <stg-chat-search>. But that's just marginal.

Then in my package.json I have:

"build:webcomponents": "vite -c vite.webcomponents.config.js build"

invoking the build with:

npm run build:webcomponents

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pkg:svelte-package Issues related to svelte-package
Projects
None yet
Development

No branches or pull requests

6 participants