Skip to content

Minor issues with preprocessed TypeScript #665

@nstuyvesant

Description

@nstuyvesant

Describe the design limitations

  1. svelte-preprocess does not remove lang="ts" from generated files - only lang="typescript". This differs from vitePreprocess as it expects lang="ts" and is confusing for users who might need svelte-preprocess after starting with vitePreprocess.
  2. Generated svelte components do not have a line break following the opening <script> tag.
  3. Generated svelte components do not have the generics attribute removed from <script> tags.
  4. Generated svelte components do not apply prettier configuration. While we can manually run prettier on the dist folder but it would be nice if svelte-preprocess followed the configured rules.

To Reproduce

  1. Create a Svelte component with the following code:
<script lang="typescript" generics="T extends BaseChartOptions">
	import { onMount, afterUpdate, onDestroy, createEventDispatcher } from 'svelte'
	import type { Charts, ChartConfig, BaseChartOptions, ChartTabularData } from '@carbon/charts'

	interface DispatchedEvents {
		load: null
		update: { data: ChartTabularData; options: T }
		destroy: null
	}

	type CoreChartClass = new (holder: HTMLDivElement, chartConfigs: ChartConfig<T>) => Charts

	const chartHolderCssClass = 'cds--chart-holder' // Used by Carbon Charts CSS
	export let data: ChartTabularData = [] // Chart data, default is empty
	export let options: T = {} as T // Specific chart option type, default is empty
	export let Chart: CoreChartClass // Used to instantiate next property
	export let chart: Charts | undefined // Instance of the chart class
	export let ref: HTMLDivElement | undefined // Binding to chart 'holder' in template below
	export let id = `chart-${Math.random().toString(36)}` // id for chart holder element

	const dispatch = createEventDispatcher<DispatchedEvents>()

	onMount(() => {
		try {
			chart = new Chart(ref as HTMLDivElement, { data, options })
			dispatch('load')
		} catch (error) {
			console.error('Failed to initialize chart:', error)
		}
	})

	afterUpdate(() => {
		if (chart) {
			try {
				chart.model.setData(data)
				chart.model.setOptions(options)
				dispatch('update', { data, options })
			} catch (error) {
				console.error('Failed to update chart:', error)
			}
		}
	})

	onDestroy(() => {
		if (chart) {
			dispatch('destroy')
			// Like core's Chart.destroy() but keeps div chart holder bound to ref as it's part of this template
			chart.components.forEach(component => component.destroy())
			chart.model.set({ destroyed: true }, { skipUpdate: true })
			chart = undefined
		}
	})
</script>

<div {id} bind:this={ref} class={chartHolderCssClass} {...$$restProps}></div>
  1. Build with svelte-preprocess.
  2. Look at output...
<script generics="T extends BaseChartOptions">import { onMount, afterUpdate, onDestroy, createEventDispatcher } from 'svelte';
const chartHolderCssClass = 'cds--chart-holder'; // Used by Carbon Charts CSS
export let data = []; // Chart data, default is empty
export let options = {}; // Specific chart option type, default is empty
export let Chart; // Used to instantiate next property
export let chart; // Instance of the chart class
export let ref; // Binding to chart 'holder' in template below
export let id = `chart-${Math.random().toString(36)}`; // id for chart holder element
const dispatch = createEventDispatcher();
onMount(() => {
    try {
        chart = new Chart(ref, { data, options });
        dispatch('load');
    }
    catch (error) {
        console.error('Failed to initialize chart:', error);
    }
});
afterUpdate(() => {
    if (chart) {
        try {
            chart.model.setData(data);
            chart.model.setOptions(options);
            dispatch('update', { data, options });
        }
        catch (error) {
            console.error('Failed to update chart:', error);
        }
    }
});
onDestroy(() => {
    if (chart) {
        dispatch('destroy');
        // Like core's Chart.destroy() but keeps div chart holder bound to ref as it's part of this template
        chart.components.forEach(component => component.destroy());
        chart.model.set({ destroyed: true }, { skipUpdate: true });
        chart = undefined;
    }
});
</script>

<div {id} bind:this={ref} class={chartHolderCssClass} {...$$restProps}></div>

Expected behavior

  1. Expected generics="T extends BaseChartOptions" to be removed from line 1.
  2. Expected there to be a line break before the first import statement.
  3. Expected lang="ts" would be removed (my example uses lang="typescript" which is removed)
  4. Expected formatting to use prettier

Information about your project:

  • Your browser and the version: Google Chrome 133

  • Your operating system: macOS 15.3.1

  • svelte-preprocess version: 6.0.3

  • Svelte 5.20.1 (compatibility mode), SvelteKit 2.17.2 (building with svelte-package)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions