Skip to main content
The preprocess() function provides hooks for transforming component source code before compilation. Use it to add support for TypeScript, PostCSS, SCSS, and other preprocessors.

Signature

function preprocess(
  source: string,
  preprocessor: PreprocessorGroup | PreprocessorGroup[],
  options?: { filename?: string }
): Promise<Processed>

Parameters

source
string
required
The component source code to preprocess
preprocessor
PreprocessorGroup | PreprocessorGroup[]
required
A preprocessor group or array of preprocessor groups. Each group can have markup, script, and style hooks.
options.filename
string
The filename of the component (used for debugging and source maps)

Return Value

Returns a Promise<Processed> with:
code
string
The transformed source code
map
string | object
A source map mapping back to the original code
dependencies
string[]
Array of additional files to watch for changes

Preprocessor Hooks

markup

Processes the entire component source.
markup
MarkupPreprocessor
type MarkupPreprocessor = (options: {
  content: string;  // The whole Svelte file content
  filename?: string; // The filename of the Svelte file
}) => Processed | void | Promise<Processed | void>

script

Processes the content of <script> tags.
script
Preprocessor
type Preprocessor = (options: {
  content: string;  // The script tag content
  attributes: Record<string, string | boolean>; // Tag attributes
  markup: string;   // The whole Svelte file content
  filename?: string; // The filename of the Svelte file
}) => Processed | void | Promise<Processed | void>

style

Processes the content of <style> tags.
style
Preprocessor
Same signature as script preprocessor

Processed Return Type

Each preprocessor hook can return:
code
string
required
The transformed code
map
string | object
A source map
dependencies
string[]
Files to watch for changes
attributes
Record<string, string | boolean>
(script/style only) Updated attributes for the tag

Usage Examples

TypeScript Preprocessor

import { preprocess } from 'svelte/compiler';
import ts from 'typescript';

const preprocessor = {
  script({ content, attributes, filename }) {
    if (attributes.lang !== 'ts') return;

    const result = ts.transpileModule(content, {
      compilerOptions: { 
        target: ts.ScriptTarget.ES2020,
        module: ts.ModuleKind.ESNext
      },
      fileName: filename
    });

    return {
      code: result.outputText,
      map: result.sourceMapText
    };
  }
};

const result = await preprocess(source, preprocessor, {
  filename: 'App.svelte'
});

SCSS Preprocessor

import { preprocess } from 'svelte/compiler';
import * as sass from 'sass';

const preprocessor = {
  style({ content, attributes, filename }) {
    if (attributes.lang !== 'scss') return;

    const result = sass.compileString(content, {
      sourceMap: true,
      loadPaths: ['node_modules']
    });

    return {
      code: result.css,
      map: result.sourceMap,
      dependencies: result.loadedUrls
        .map(url => url.pathname)
        .filter(path => path !== filename)
    };
  }
};

Multiple Preprocessors

import { preprocess } from 'svelte/compiler';
import { typescript } from 'svelte-preprocess-typescript';
import { scss } from 'svelte-preprocess-scss';
import autoprefixer from 'autoprefixer';
import postcss from 'postcss';

const result = await preprocess(source, [
  // Run TypeScript first
  {
    script: typescript()
  },
  // Then SCSS
  {
    style: scss()
  },
  // Then PostCSS
  {
    async style({ content }) {
      const result = await postcss([autoprefixer]).process(content);
      return {
        code: result.css,
        map: result.map.toString()
      };
    }
  }
], { filename: 'App.svelte' });

Markup Preprocessor

import { preprocess } from 'svelte/compiler';
import { marked } from 'marked';

const preprocessor = {
  markup({ content, filename }) {
    // Transform markdown blocks
    const transformed = content.replace(
      /<markdown>([\s\S]*?)<\/markdown>/g,
      (_, markdown) => marked(markdown)
    );

    return {
      code: transformed
    };
  }
};

Using svelte-preprocess

import { preprocess } from 'svelte/compiler';
import sveltePreprocess from 'svelte-preprocess';

const result = await preprocess(
  source,
  sveltePreprocess({
    typescript: {
      tsconfigFile: './tsconfig.json'
    },
    scss: {
      includePaths: ['src', 'node_modules']
    },
    postcss: {
      plugins: [autoprefixer]
    }
  }),
  { filename: 'App.svelte' }
);

With Vite

// vite.config.js
import { defineConfig } from 'vite';
import { svelte } from '@sveltejs/vite-plugin-svelte';
import sveltePreprocess from 'svelte-preprocess';

export default defineConfig({
  plugins: [
    svelte({
      preprocess: sveltePreprocess({
        typescript: true,
        postcss: true
      })
    })
  ]
});

Watching Dependencies

import { preprocess } from 'svelte/compiler';
import fs from 'fs';
import path from 'path';

const preprocessor = {
  async style({ content, filename }) {
    const dependencies = [];
    
    // Process @import statements
    const processed = content.replace(
      /@import ['"]([^'"]+)['"];/g,
      (match, importPath) => {
        const fullPath = path.resolve(
          path.dirname(filename),
          importPath
        );
        dependencies.push(fullPath);
        return fs.readFileSync(fullPath, 'utf-8');
      }
    );

    return {
      code: processed,
      dependencies
    };
  }
};