diff --git a/examples/svelte-preprocess/package.json b/examples/svelte-preprocess/package.json
new file mode 100644
index 0000000..8e5cb41
--- /dev/null
+++ b/examples/svelte-preprocess/package.json
@@ -0,0 +1,15 @@
+{
+ "private": true,
+ "scripts": {
+ "test": "uvu tests -r esm -r tests/setup/register -i setup"
+ },
+ "devDependencies": {
+ "cosmiconfig": "^7.0.0",
+ "esm": "3.2.25",
+ "jsdom": "16.3.0",
+ "svelte": "3.24.0",
+ "svelte-preprocess": "^4.2.1",
+ "typescript": "^3.9.7",
+ "uvu": "^0.2.0"
+ }
+}
diff --git a/examples/svelte-preprocess/src/Count.svelte b/examples/svelte-preprocess/src/Count.svelte
new file mode 100644
index 0000000..4dad687
--- /dev/null
+++ b/examples/svelte-preprocess/src/Count.svelte
@@ -0,0 +1,16 @@
+
+
+
+{count}
+
diff --git a/examples/svelte-preprocess/svelte.config.js b/examples/svelte-preprocess/svelte.config.js
new file mode 100644
index 0000000..1958389
--- /dev/null
+++ b/examples/svelte-preprocess/svelte.config.js
@@ -0,0 +1,9 @@
+const sveltePreprocess = require("svelte-preprocess");
+
+const defaults = {
+ script: "typescript",
+};
+
+module.exports = {
+ preprocess: sveltePreprocess({ defaults })
+}
\ No newline at end of file
diff --git a/examples/svelte-preprocess/tests/Count.js b/examples/svelte-preprocess/tests/Count.js
new file mode 100644
index 0000000..c99c558
--- /dev/null
+++ b/examples/svelte-preprocess/tests/Count.js
@@ -0,0 +1,67 @@
+import { test } from 'uvu';
+import * as assert from 'uvu/assert';
+import * as ENV from './setup/env';
+
+// Relies on `setup/register`
+import Count from '../src/Count.svelte';
+
+test.before(ENV.setup);
+test.before.each(ENV.reset);
+
+test('should render with "5" by default', () => {
+ const { container } = ENV.render(Count);
+
+ assert.snapshot(
+ container.innerHTML,
+ ` 5 `
+ );
+});
+
+test('should accept custom `count` prop', () => {
+ const { container } = ENV.render(Count, { count: 99 });
+
+ assert.snapshot(
+ container.innerHTML,
+ ` 99 `
+ );
+});
+
+test('should increment count after `button#incr` click', async () => {
+ const { container } = ENV.render(Count);
+
+ assert.snapshot(
+ container.innerHTML,
+ ` 5 `
+ );
+
+ await ENV.fire(
+ container.querySelector('#incr'),
+ 'click'
+ );
+
+ assert.snapshot(
+ container.innerHTML,
+ ` 6 `
+ );
+});
+
+test('should decrement count after `button#decr` click', async () => {
+ const { container } = ENV.render(Count);
+
+ assert.snapshot(
+ container.innerHTML,
+ ` 5 `
+ );
+
+ await ENV.fire(
+ container.querySelector('#decr'),
+ 'click'
+ );
+
+ assert.snapshot(
+ container.innerHTML,
+ ` 4 `
+ );
+});
+
+test.run();
diff --git a/examples/svelte-preprocess/tests/setup/env.js b/examples/svelte-preprocess/tests/setup/env.js
new file mode 100644
index 0000000..00fac9c
--- /dev/null
+++ b/examples/svelte-preprocess/tests/setup/env.js
@@ -0,0 +1,47 @@
+import { JSDOM } from 'jsdom';
+import { tick } from 'svelte';
+
+const { window } = new JSDOM('');
+
+export function setup() {
+ // @ts-ignore
+ global.window = window;
+ global.document = window.document;
+ global.navigator = window.navigator;
+ global.getComputedStyle = window.getComputedStyle;
+ global.requestAnimationFrame = null;
+}
+
+export function reset() {
+ window.document.title = '';
+ window.document.head.innerHTML = '';
+ window.document.body.innerHTML = '';
+}
+
+/**
+ * @typedef RenderOutput
+ * @property container {HTMLElement}
+ * @property component {import('svelte').SvelteComponent}
+ */
+
+/**
+ * @return {RenderOutput}
+ */
+export function render(Tag, props = {}) {
+ Tag = Tag.default || Tag;
+ const container = window.document.body;
+ const component = new Tag({ props, target: container });
+ return { container, component };
+}
+
+/**
+ * @param {HTMLElement} elem
+ * @param {String} event
+ * @param {any} [details]
+ * @returns Promise
+ */
+export function fire(elem, event, details) {
+ let evt = new window.Event(event, details);
+ elem.dispatchEvent(evt);
+ return tick();
+}
diff --git a/examples/svelte-preprocess/tests/setup/register.js b/examples/svelte-preprocess/tests/setup/register.js
new file mode 100644
index 0000000..0c724c5
--- /dev/null
+++ b/examples/svelte-preprocess/tests/setup/register.js
@@ -0,0 +1,47 @@
+const { parse } = require('path');
+const { compile, preprocess_sync } = require('svelte/compiler');
+const { getSvelteConfig } = require('./svelteconfig.js');
+const { cosmiconfigSync } = require('cosmiconfig')
+
+const useTransformer = (options = {}) => (source, filename) => {
+ const { preprocess, rootMode } = options;
+ if (preprocess) {
+ const svelteConfig = getSvelteConfig(rootMode, filename);
+ const config = cosmiconfigSync().load(svelteConfig).config
+
+ return preprocess_sync(source, config.preprocess || {}, { filename }).code
+ }
+ else {
+ return source;
+ }
+};
+
+function transform(hook, source, filename) {
+ const { name } = parse(filename);
+
+ const preprocessed = useTransformer({ preprocess: true })(source, filename);
+
+ const {js, warnings} = compile(preprocessed, {
+ name: name[0].toUpperCase() + name.slice(1),
+ format: 'cjs',
+ filename
+ });
+
+ warnings.forEach(warning => {
+ console.warn(`\nSvelte Warning in ${warning.filename}:`);
+ console.warn(warning.message);
+ console.warn(warning.frame);
+ });
+
+ return hook(js.code, filename);
+}
+
+const loadJS = require.extensions['.js'];
+
+// Runtime DOM hook for require("*.svelte") files
+// Note: for SSR/Node.js hook, use `svelte/register`
+require.extensions['.svelte'] = function (mod, filename) {
+ const orig = mod._compile.bind(mod);
+ mod._compile = code => transform(orig, code, filename);
+ loadJS(mod, filename);
+}
diff --git a/examples/svelte-preprocess/tests/setup/svelteconfig.js b/examples/svelte-preprocess/tests/setup/svelteconfig.js
new file mode 100644
index 0000000..5a231e9
--- /dev/null
+++ b/examples/svelte-preprocess/tests/setup/svelteconfig.js
@@ -0,0 +1,28 @@
+const fs = require('fs')
+const path = require('path')
+
+const configFilename = 'svelte.config.js'
+
+exports.getSvelteConfig = (rootMode, filename) => {
+ const configDir = rootMode === 'upward'
+ ? getConfigDir(path.dirname(filename))
+ : process.cwd()
+ const configFile = path.resolve(configDir, configFilename)
+
+ if (!fs.existsSync(configFile)) {
+ throw Error(`Could not find ${configFilename}`)
+ }
+
+ return configFile
+}
+
+const getConfigDir = (searchDir) => {
+ if (fs.existsSync(path.join(searchDir, configFilename))) {
+ return searchDir
+ }
+
+ const parentDir = path.resolve(searchDir, '..')
+ return parentDir !== searchDir
+ ? getConfigDir(parentDir)
+ : searchDir // Stop walking at filesystem root
+}