diff --git a/index.ts b/index.ts
index 40e51dc..40fa74d 100644
--- a/index.ts
+++ b/index.ts
@@ -129,11 +129,14 @@ export default function sveltePlugin(options?: esbuildSvelteOptions): Plugin {
//main loader
build.onLoad({ filter: svelteFilter }, async (args) => {
+ let cachedFile = null;
+ let previousWatchFiles: string[] = [];
+
// if told to use the cache, check if it contains the file,
// and if the modified time is not greater than the time when it was cached
// if so, return the cached data
if (options?.cache === true && fileCache.has(args.path)) {
- const cachedFile = fileCache.get(args.path) || {
+ cachedFile = fileCache.get(args.path) || {
dependencies: new Map(),
data: null,
}; // should never hit the null b/c of has check
@@ -177,13 +180,25 @@ export default function sveltePlugin(options?: esbuildSvelteOptions): Plugin {
//do preprocessor stuff if it exists
if (options?.preprocess) {
- let preprocessResult = await preprocess(
- originalSource,
- options.preprocess,
- {
- filename,
+ let preprocessResult = null;
+
+ try {
+ preprocessResult = await preprocess(
+ originalSource,
+ options.preprocess,
+ {
+ filename,
+ }
+ );
+ } catch (e: any) {
+ // if preprocess failed there are chances that an external dependency caused exception
+ // to avoid stop watching those files, we keep the previous dependencies if available
+ if (build.initialOptions.watch && cachedFile) {
+ previousWatchFiles = Array.from(cachedFile.dependencies.keys());
}
- );
+ throw e;
+ }
+
if (preprocessResult.map) {
// normalize the sourcemap 'source' entrys to all match if they are the same file
// needed because of differing handling of file names in preprocessors
@@ -262,7 +277,7 @@ export default function sveltePlugin(options?: esbuildSvelteOptions): Plugin {
return result;
} catch (e: any) {
- return { errors: [convertMessage(e)] };
+ return { errors: [convertMessage(e)], watchFiles: previousWatchFiles };
}
});
diff --git a/test/fixtures/watch-preprocessing/entry.js b/test/fixtures/watch-preprocessing/entry.js
new file mode 100644
index 0000000..bbe8c80
--- /dev/null
+++ b/test/fixtures/watch-preprocessing/entry.js
@@ -0,0 +1,5 @@
+import Test from "./external-styles.svelte";
+
+new Test({
+ target: document.body,
+});
diff --git a/test/fixtures/watch-preprocessing/external-styles.svelte b/test/fixtures/watch-preprocessing/external-styles.svelte
new file mode 100644
index 0000000..08995e7
--- /dev/null
+++ b/test/fixtures/watch-preprocessing/external-styles.svelte
@@ -0,0 +1,7 @@
+
+
+
+
Hello World
+
diff --git a/test/fixtures/watch-preprocessing/external.scss b/test/fixtures/watch-preprocessing/external.scss
new file mode 100644
index 0000000..3d9a2b2
--- /dev/null
+++ b/test/fixtures/watch-preprocessing/external.scss
@@ -0,0 +1,3 @@
+p {
+ color: red;
+}
diff --git a/test/watchPreprocessingTest.mjs b/test/watchPreprocessingTest.mjs
new file mode 100644
index 0000000..818f0ae
--- /dev/null
+++ b/test/watchPreprocessingTest.mjs
@@ -0,0 +1,76 @@
+import { test } from "uvu";
+import * as assert from "uvu/assert";
+import { writeFileSync } from "fs";
+import { fileURLToPath } from "url";
+import { dirname } from "path";
+import { build as _build } from "esbuild";
+import { sass } from "svelte-preprocess-sass";
+import sveltePlugin from "../dist/index.mjs";
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = dirname(__filename);
+
+test("Watch and build while preprocess of external dependency succeed and fails", async () => {
+ function _createDeferred() {
+ let resolve = null;
+ let reject = null;
+ const promise = new Promise((_resolve, _reject) => {
+ resolve = _resolve;
+ reject = _reject;
+ });
+ promise.forceResolve = resolve;
+ promise.forceReject = reject;
+ return promise;
+ }
+
+ let count = 0;
+ const firstRebuild = _createDeferred();
+ const secondRebuild = _createDeferred();
+
+ //more advanced
+ const results = await _build({
+ entryPoints: ["./test/fixtures/watch-preprocessing/entry.js"],
+ outdir: "../example/dist",
+ format: "esm",
+ minify: true,
+ bundle: true,
+ splitting: true,
+ write: false, //Don't write anywhere
+ sourcemap: "inline",
+ plugins: [
+ sveltePlugin({
+ preprocess: {
+ style: sass(),
+ },
+ }),
+ ],
+ watch: {
+ onRebuild(err, result) {
+ count++;
+ if (count === 1) {
+ firstRebuild.forceResolve(err);
+ } else if (count === 2) {
+ secondRebuild.forceResolve(result);
+ }
+ },
+ },
+ });
+
+ // write external scss with invalid syntax
+ writeFileSync(
+ `${__dirname}/fixtures/watch-preprocessing/external.scss`,
+ "p { color: red; }!$%^&*()@$%^@@"
+ );
+ const firstRebuildResult = await firstRebuild;
+ assert.ok(firstRebuildResult instanceof Error, "First build did not fail");
+
+ // write external scss with valid syntax again
+ writeFileSync(`${__dirname}/fixtures/watch-preprocessing/external.scss`, "p { color: red; }");
+ const secondRebuildResult = await secondRebuild;
+ assert.ok(secondRebuildResult.errors.length === 0, "Second build fail");
+
+ // stop watching
+ results.stop();
+});
+
+test.run();