From 9ec1e567add87186e859aaf719991ad5e554e03f Mon Sep 17 00:00:00 2001 From: Maximiliano Ruani Date: Wed, 1 Jun 2022 11:32:21 -0300 Subject: [PATCH 1/2] Watch previous files if preprocessing failed --- index.ts | 32 ++++++-- test/fixtures/watch-preprocessing/entry.js | 5 ++ .../external-styles.svelte | 7 ++ .../watch-preprocessing/external.scss | 1 + test/watchPreprocessingTest.mjs | 75 +++++++++++++++++++ 5 files changed, 112 insertions(+), 8 deletions(-) create mode 100644 test/fixtures/watch-preprocessing/entry.js create mode 100644 test/fixtures/watch-preprocessing/external-styles.svelte create mode 100644 test/fixtures/watch-preprocessing/external.scss create mode 100644 test/watchPreprocessingTest.mjs diff --git a/index.ts b/index.ts index 40e51dc..fd7c118 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,26 @@ 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 +278,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..5b4c482 --- /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..7cd741e --- /dev/null +++ b/test/fixtures/watch-preprocessing/external.scss @@ -0,0 +1 @@ +p { color: red; } \ No newline at end of file diff --git a/test/watchPreprocessingTest.mjs b/test/watchPreprocessingTest.mjs new file mode 100644 index 0000000..e4ada32 --- /dev/null +++ b/test/watchPreprocessingTest.mjs @@ -0,0 +1,75 @@ +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(); From bad10e331f567fd99d1f9716650872b975956aa8 Mon Sep 17 00:00:00 2001 From: Maximiliano Ruani Date: Wed, 1 Jun 2022 21:59:32 -0300 Subject: [PATCH 2/2] - Fixed lint errors --- index.ts | 13 +-- test/fixtures/watch-preprocessing/entry.js | 2 +- .../watch-preprocessing/external.scss | 4 +- test/watchPreprocessingTest.mjs | 107 +++++++++--------- 4 files changed, 64 insertions(+), 62 deletions(-) diff --git a/index.ts b/index.ts index fd7c118..40fa74d 100644 --- a/index.ts +++ b/index.ts @@ -184,14 +184,13 @@ export default function sveltePlugin(options?: esbuildSvelteOptions): Plugin { try { preprocessResult = await preprocess( - originalSource, - options.preprocess, - { - filename, - } + originalSource, + options.preprocess, + { + filename, + } ); - } - catch(e: any) { + } 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) { diff --git a/test/fixtures/watch-preprocessing/entry.js b/test/fixtures/watch-preprocessing/entry.js index 5b4c482..bbe8c80 100644 --- a/test/fixtures/watch-preprocessing/entry.js +++ b/test/fixtures/watch-preprocessing/entry.js @@ -1,5 +1,5 @@ import Test from "./external-styles.svelte"; new Test({ - target: document.body, + target: document.body, }); diff --git a/test/fixtures/watch-preprocessing/external.scss b/test/fixtures/watch-preprocessing/external.scss index 7cd741e..3d9a2b2 100644 --- a/test/fixtures/watch-preprocessing/external.scss +++ b/test/fixtures/watch-preprocessing/external.scss @@ -1 +1,3 @@ -p { color: red; } \ No newline at end of file +p { + color: red; +} diff --git a/test/watchPreprocessingTest.mjs b/test/watchPreprocessingTest.mjs index e4ada32..818f0ae 100644 --- a/test/watchPreprocessingTest.mjs +++ b/test/watchPreprocessingTest.mjs @@ -11,65 +11,66 @@ 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; + } - 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(); + 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(), + //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); + } + }, }, - }), - ], - 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 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"); + // 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(); + // stop watching + results.stop(); }); test.run();