sveltejs/svelte

Add component name to function or function prototype

webJose opened this issue · 4 comments

Describe the problem

When creating demos for component libraries, it would be handy if we could write generalized code that receives a component by arguments/properties and can extract the component name out of it.

Pardon me if this is already possible. I don't recall ever reading about this, if it exists today.

Describe the proposed solution

Have the Svelte compiler add the componentName property to the function or function's prototype. The name would come from... ? See options.

Simple Option

Use the file's name.

Not-So-Simple Option

Because the component is a default export, it really can be named anything. Furthermore, if it ever becomes possible to export components grouped in POJO objects (I opened an issue for this a long time ago), for documentation/demo purposes it could be a compound name like Card.Header.

Because of this, maybe the best option would be to add a per-component compiler option to set the desired name. If the option is not specified, then it would default to the simple option above.

Importance

nice to have

This is a great proposal, I agree it would be very useful for component libraries.

I am very interested in working on this. If the maintainers approve the direction of this feature, could you(@webJose ) please assign this issue to me?

I'd be happy to start working on the implementation.

This is trivial to do with a Vite plugin. It's probably not something that should live in Svelte.

The shape of component output is fairly stable. You can use a regex to find export default function MyComponent( and magic-string to append MyComponent.name = 'MyComponent' and whatever meta-data you desire for your demos while preserving source maps.

It should be a 5 minute job w/ ChatGPT to get a workable draft. Happy to help if you get stuck or have questions.

Good point @kwangure , this is a working example using a vite plugin. Hope it helps :)

import path from 'node:path';

export default function svelteComponentName() {
	return {
		name: 'svelte-component-name',

		transform(code, id) {
			if (!id.endsWith('.svelte')) return;

			const filename = path.basename(id, '.svelte');

			const match = code.match(/export\s+default\s+function\s+([A-Za-z0-9_]+)\s*\(/);

			if (!match) return;

			const fnName = match[1];

			const inject = `\n${fnName}.componentName = "${filename}";\n`;

			return {
				code: code + inject,
				map: null
			};
		}
	};
}

While using Vite for this is nice, there's the matter of the TypeScript. Component<> should disclose the presence of componentName, which is not something achievable via Vite alone.