Skip to content

Commit

Permalink
Updrade to be able to handle svelte 5 features
Browse files Browse the repository at this point in the history
Add module js and ts support
Update tests for new warnings
Add tests for module js and ts support
Update dependency to svelte 5
  • Loading branch information
ElijahJohnson5 committed Oct 27, 2024
1 parent 4cf2f6b commit deafc73
Show file tree
Hide file tree
Showing 23 changed files with 287 additions and 116 deletions.
9 changes: 5 additions & 4 deletions dist/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
/// <reference types="svelte" />
import type { CompileOptions, Warning } from "svelte/types/compiler/interfaces";
import type { PreprocessorGroup } from "svelte/types/compiler/preprocess";
import type { CompileOptions, ModuleCompileOptions, CompileResult } from "svelte/compiler";
import type { PreprocessorGroup } from "svelte/compiler";
import type { Plugin } from "esbuild";
type Warning = CompileResult["warnings"][number];
interface esbuildSvelteOptions {
/**
* Svelte compiler options
*/
compilerOptions?: CompileOptions;
moduleCompilerOptions?: ModuleCompileOptions;
/**
* The preprocessor(s) to run the Svelte code through before compiling
*/
Expand All @@ -25,7 +26,7 @@ interface esbuildSvelteOptions {
* A function to filter out warnings
* Defaults to a constant function that returns `true`
*/
filterWarnings?: (warning: Warning) => boolean;
filterWarnings?: (warning: Warning) => warning is Warning;
}
export default function sveltePlugin(options?: esbuildSvelteOptions): Plugin;
export {};
5 changes: 2 additions & 3 deletions example-js/entry.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { mount } from "svelte";
import Test from "./index.svelte";

new Test({
target: document.body,
});
mount(Test, { target: document.body });
9 changes: 8 additions & 1 deletion example-js/index.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
<script>
import Second from "./second.svelte";
import Counter from "./test.svelte";
let inputBinding;
const counter = new Counter();
function change() {
inputBinding.value = "testing" + Math.round(Math.random() * 100);
}
Expand All @@ -26,7 +30,10 @@
</div>

<div class="secondStyle">
<button on:click={change}>Click this button!</button>
<button onclick={change}>Click this button!</button>
<button onclick={() => counter.value++}>Increment rune counter</button>

{counter.value}

<Second />
</div>
2 changes: 1 addition & 1 deletion example-js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"dependencies": {
"esbuild": "^0.20.1",
"esbuild-svelte": "^0.8.0",
"svelte": "^4.2.11"
"svelte": "^5.1.3"
},
"private": true
}
3 changes: 3 additions & 0 deletions example-js/test.svelte.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default class Counter {
value = $state(0);
}
2 changes: 1 addition & 1 deletion example-ts/buildscript.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import fs from "fs";
import esbuild from "esbuild";
import esbuildSvelte from "esbuild-svelte";
import sveltePreprocess from "svelte-preprocess";
import { sveltePreprocess } from "svelte-preprocess";

//make sure the directoy exists before stuff gets put into it
if (!fs.existsSync("./dist/")) {
Expand Down
3 changes: 2 additions & 1 deletion example-ts/entry.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Test from "./index.svelte";
import { haha } from "./fun";
import { mount } from "svelte";

new Test({ target: document.body });
mount(Test, { target: document.body });
console.log(haha());
8 changes: 7 additions & 1 deletion example-ts/index.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
import {haha} from "./fun";
import type {Joke} from "./fun";
import Second from "./second.svelte";
import Counter from "./test.svelte";
let inputBinding : HTMLInputElement;
const counter: Counter = new Counter();
const jo : Joke = {
rating: 2, joke: "123",
}
Expand Down Expand Up @@ -36,7 +39,10 @@
</div>

<div class="secondStyle">
<button on:click={change}>Click this button!</button>
<button onclick={change}>Click this button!</button>
<button onclick={() => counter.value++}>Increment rune counter</button>

{counter.value}
<p>{haha()}</p>
<p>{add(1,4)}</p>
<p>{JSON.stringify(jo)}</p>
Expand Down
6 changes: 3 additions & 3 deletions example-ts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
"@tsconfig/svelte": "^5.0.2",
"esbuild": "^0.20.1",
"esbuild-svelte": "^0.8.0",
"svelte": "^4.2.11",
"svelte-check": "^3.6.4",
"svelte-preprocess": "^5.1.3",
"svelte": "^5.1.3",
"svelte-check": "^4.0.5",
"svelte-preprocess": "^6.0.3",
"typescript": "^5.3.3"
},
"private": true
Expand Down
3 changes: 3 additions & 0 deletions example-ts/test.svelte.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default class Counter {
value: number = $state(0);
}
122 changes: 102 additions & 20 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
//original version from https://github.com/evanw/esbuild/blob/plugins/docs/plugin-examples.md
import { preprocess, compile, VERSION } from "svelte/compiler";
import { preprocess, compile, VERSION, compileModule } from "svelte/compiler";
import { dirname, basename, relative } from "path";
import { promisify } from "util";
import { readFile, statSync } from "fs";
import { originalPositionFor, TraceMap } from "@jridgewell/trace-mapping";

import type { CompileOptions, Warning } from "svelte/types/compiler/interfaces";
import type { PreprocessorGroup } from "svelte/types/compiler/preprocess";
import type { CompileOptions, ModuleCompileOptions, CompileResult } from "svelte/compiler";
import type { PreprocessorGroup } from "svelte/compiler";
import type { OnLoadResult, Plugin, PluginBuild, Location, PartialMessage } from "esbuild";

type Warning = CompileResult["warnings"][number];

interface esbuildSvelteOptions {
/**
* Svelte compiler options
*/
compilerOptions?: CompileOptions;

/**
* Svelte compiler options for module files (*.svelte.js and *.svelte.ts)
*/

moduleCompilerOptions?: ModuleCompileOptions;

/**
* The preprocessor(s) to run the Svelte code through before compiling
*/
Expand All @@ -36,7 +44,7 @@ interface esbuildSvelteOptions {
* A function to filter out warnings
* Defaults to a constant function that returns `true`
*/
filterWarnings?: (warning: Warning) => boolean;
filterWarnings?: (warning: Warning) => warning is Warning;
}

interface CacheData {
Expand Down Expand Up @@ -90,7 +98,7 @@ const shouldCache = (
},
) => build.initialOptions?.incremental || build.initialOptions?.watch;

const SVELTE_FILTER = /\.svelte$/;
const SVELTE_FILTER = /(\.svelte$)|(\.svelte.js$)|(\.svelte.ts$)/;
const FAKE_CSS_FILTER = /\.esbuild-svelte-fake-css$/;

export default function sveltePlugin(options?: esbuildSvelteOptions): Plugin {
Expand All @@ -110,7 +118,7 @@ export default function sveltePlugin(options?: esbuildSvelteOptions): Plugin {

// by default all warnings are enabled
if (options.filterWarnings == undefined) {
options.filterWarnings = () => true;
options.filterWarnings = (_warning: Warning): _warning is Warning => true;
}

//Store generated css code for use in fake import
Expand Down Expand Up @@ -155,6 +163,69 @@ export default function sveltePlugin(options?: esbuildSvelteOptions): Plugin {
let originalSource = await promisify(readFile)(args.path, "utf8");
let filename = relative(process.cwd(), args.path);

let source = originalSource;

if (filename.endsWith(".svelte.ts")) {
let {
banner,
footer,
bundle,
splitting,
preserveSymlinks,
outfile,
metafile,
outdir,
outbase,
external,
packages,
alias,
resolveExtensions,
mainFields,
conditions,
write,
allowOverwrite,
tsconfig,
outExtension,
publicPath,
entryNames,
chunkNames,
assetNames,
inject,
entryPoints,
stdin,
plugins,
absWorkingDir,
nodePaths,
...transformOptions
} = {
...build.initialOptions,
};

try {
const result = await build.esbuild.transform(originalSource, {
...transformOptions,
loader: "ts",
});

source = result.code;
} catch (e: any) {
let result: OnLoadResult = {};
result.errors = [
await convertMessage(
e,
args.path,
originalSource,
options?.compilerOptions?.sourcemap,
),
];
// only provide if context API is supported or we are caching
if (build.esbuild?.context !== undefined || shouldCache(build)) {
result.watchFiles = previousWatchFiles;
}
return result;
}
}

//file modification time storage
const dependencyModifcationTimes = new Map<string, Date>();
dependencyModifcationTimes.set(args.path, statSync(args.path).mtime); // add the target file
Expand All @@ -164,22 +235,20 @@ export default function sveltePlugin(options?: esbuildSvelteOptions): Plugin {
...options?.compilerOptions,
};

let moduleCompilerOptions: ModuleCompileOptions = {
...options?.moduleCompilerOptions,
};

//actually compile file
try {
let source = originalSource;

//do preprocessor stuff if it exists
if (options?.preprocess) {
let preprocessResult = null;

try {
preprocessResult = await preprocess(
originalSource,
options.preprocess,
{
filename,
},
);
preprocessResult = await preprocess(source, 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
Expand Down Expand Up @@ -210,7 +279,23 @@ export default function sveltePlugin(options?: esbuildSvelteOptions): Plugin {
}
}

let { js, css, warnings } = compile(source, { ...compilerOptions, filename });
let { js, css, warnings } = (() => {
if (filename.endsWith(".svelte.js") || filename.endsWith(".svelte.ts")) {
return compileModule(source, {
...moduleCompilerOptions,
filename,
});
}

if (filename.endsWith(".svelte")) {
return compile(source, {
...compilerOptions,
filename,
});
}

throw new Error(`Cannot compile ${filename}`);
})();

//esbuild doesn't seem to like sourcemaps without "sourcesContent" which Svelte doesn't provide
//so attempt to populate that array if we can find filename in sources
Expand All @@ -231,10 +316,7 @@ export default function sveltePlugin(options?: esbuildSvelteOptions): Plugin {
let contents = js.code + `\n//# sourceMappingURL=` + js.map.toUrl();

//if svelte emits css seperately, then store it in a map and import it from the js
if (
(compilerOptions.css === false || compilerOptions.css === "external") &&
css?.code
) {
if (compilerOptions.css === "external" && css?.code) {
let cssPath = args.path
.replace(".svelte", ".esbuild-svelte-fake-css") //TODO append instead of replace to support different svelte filters
.replace(/\\/g, "/");
Expand Down
Loading

0 comments on commit deafc73

Please sign in to comment.