mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
fix(bun-plugin-svelte): handle "svelte" export conditions (#18150)
This commit is contained in:
@@ -24,7 +24,8 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"bun-types": "canary",
|
||||
"svelte": "^5.20.4"
|
||||
"svelte": "^5.20.4",
|
||||
"@threlte/core": "8.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"svelte": "^5"
|
||||
|
||||
@@ -29,6 +29,20 @@ function SveltePlugin(options: SvelteOptions = kEmptyObject as SvelteOptions): B
|
||||
return {
|
||||
name: "bun-plugin-svelte",
|
||||
setup(builder) {
|
||||
// resolve "svelte" export conditions
|
||||
//
|
||||
// FIXME: the dev server does not currently respect bundler configs; it
|
||||
// just passes a fake one to plugins and then never uses it. we need to to
|
||||
// update it to ~not~ do this.
|
||||
if (builder?.config) {
|
||||
var conditions = builder.config.conditions ?? [];
|
||||
if (typeof conditions === "string") {
|
||||
conditions = [conditions];
|
||||
}
|
||||
conditions.push("svelte");
|
||||
builder.config.conditions = conditions;
|
||||
}
|
||||
|
||||
const { config = kEmptyObject as Partial<BuildConfig> } = builder;
|
||||
const baseCompileOptions = getBaseCompileOptions(options ?? (kEmptyObject as Partial<SvelteOptions>), config);
|
||||
const baseModuleCompileOptions = getBaseModuleCompileOptions(
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
import { basename } from "node:path";
|
||||
import type { BuildConfig, Transpiler } from "bun";
|
||||
import { getBaseCompileOptions, getBaseModuleCompileOptions, hash, type SvelteOptions } from "./options";
|
||||
import { compile, type CompileOptions, type CompileResult, type ModuleCompileOptions } from "svelte/compiler";
|
||||
|
||||
const virtualNamespace = "bun-svelte";
|
||||
|
||||
export class SveltePluginService {
|
||||
private compileOptions: CompileOptions;
|
||||
private compileModuleOptions: ModuleCompileOptions;
|
||||
|
||||
private ts: Transpiler;
|
||||
/** Virtual CSS modules created by Svelte components. Keys are import specifiers. */
|
||||
private css: Map<string, VirtualCSSModule>;
|
||||
|
||||
constructor(options: SvelteOptions, config: Partial<BuildConfig>) {
|
||||
this.compileOptions = getBaseCompileOptions(options, config);
|
||||
this.compileModuleOptions = getBaseModuleCompileOptions(options, config);
|
||||
|
||||
this.ts = new Bun.Transpiler({ loader: "ts" });
|
||||
this.css = new Map();
|
||||
}
|
||||
|
||||
public compileComponent(source: string, filename: string, hmr: boolean, side?: "client" | "server"): CompileResult {
|
||||
const generate = this.compileOptions.generate ?? side;
|
||||
const result = compile(source, {
|
||||
...this.compileOptions,
|
||||
generate,
|
||||
filename,
|
||||
hmr,
|
||||
});
|
||||
|
||||
var { js, css } = result;
|
||||
if (css?.code && generate != "server") {
|
||||
const uid = `${basename(filename)}-${hash(filename)}-style`.replaceAll(`"`, `'`);
|
||||
const virtualName = virtualNamespace + ":" + uid + ".css";
|
||||
this.css.set(virtualName, { sourcePath: filename, source: css.code });
|
||||
js.code += `\nimport "${virtualName}";`;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async compileModule(source: string, filename: string, side?: "client" | "server"): Promise<CompileResult> {
|
||||
const generate = this.compileModuleOptions.generate ?? side;
|
||||
if (filename.endsWith("ts")) {
|
||||
source = await this.ts.transform(source);
|
||||
}
|
||||
|
||||
// NOTE: we assume js/ts modules won't have CSS blocks in them, so no
|
||||
// virtual modules get created.
|
||||
return compile(source, {
|
||||
...this.compileModuleOptions,
|
||||
generate,
|
||||
filename,
|
||||
});
|
||||
}
|
||||
|
||||
public takeVirtualCSSModule(path: string): VirtualCSSModule {
|
||||
const mod = this.css.get(path);
|
||||
if (!mod) throw new Error("Virtual CSS module not found: " + path);
|
||||
this.css.delete(path);
|
||||
return mod;
|
||||
}
|
||||
}
|
||||
|
||||
type VirtualCSSModule = {
|
||||
/** Path to the svelte file whose css this is for */
|
||||
sourcePath: string;
|
||||
/** Source code */
|
||||
source: string;
|
||||
};
|
||||
17
packages/bun-plugin-svelte/test/fixtures/svelte-export-condition.svelte
vendored
Normal file
17
packages/bun-plugin-svelte/test/fixtures/svelte-export-condition.svelte
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
<script>
|
||||
import { Canvas } from "@threlte/core";
|
||||
let name = "Bun";
|
||||
</script>
|
||||
|
||||
<main class="app">
|
||||
<h1>Cookin up apps with {name}</h1>
|
||||
<Canvas />
|
||||
</main>
|
||||
|
||||
<style>
|
||||
h1 {
|
||||
color: #ff3e00;
|
||||
text-align: center;
|
||||
font-size: 2em;
|
||||
}
|
||||
</style>
|
||||
@@ -47,6 +47,15 @@ describe("when importing `.svelte.ts` files with ESM", () => {
|
||||
it("builds successfully", () => {
|
||||
expect(res.success).toBeTrue();
|
||||
});
|
||||
|
||||
it(`handles "svelte" export condition`, async () => {
|
||||
const res = await Bun.build({
|
||||
entrypoints: [fixturePath("svelte-export-condition.svelte")],
|
||||
outdir,
|
||||
plugins: [SveltePlugin()],
|
||||
});
|
||||
expect(res.success).toBeTrue();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when importing `.svelte.ts` files with CJS", () => {
|
||||
|
||||
Reference in New Issue
Block a user