Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bun.build bundler does not simplify template strings when used with Ts enums #14022

Open
Atulin opened this issue Sep 18, 2024 · 0 comments
Open
Labels
bug Something isn't working needs triage

Comments

@Atulin
Copy link

Atulin commented Sep 18, 2024

What version of Bun is running?

1.1.28+cf4e9cb69

What platform is your computer?

Microsoft Windows NT 10.0.19045.0 x64

What steps can reproduce the bug?

Build the following code:

Show code
enum Action {
	bold = "bold",
	italic = "italic",
	underline = "underline",
	spoiler = "spoiler",
	link = "link",
}

interface PrefixSuffix {
	prefix: string;
	suffix: string;
}

const tpl = `
		<nav class="button-group toolbar">
		  <button type="button" class="btn" data-action="${Action.bold}" title="${Action.bold}">
		    <span class="material-icons-outlined">format_bold</span>
		  </button>
		  <button type="button" class="btn" data-action="${Action.italic}" title="${Action.italic}">
		    <span class="material-icons-outlined">format_italic</span>
		  </button>
		  <button type="button" class="btn" data-action="${Action.underline}" title="${Action.underline}">
		    <span class="material-icons-outlined">format_underlined</span>
		  </button>
		  <button type="button" class="btn" data-action="${Action.spoiler}" title="${Action.spoiler}">
		    <span class="material-icons-outlined">visibility</span>
		  </button>
		  <button type="button" class="btn" data-action="${Action.link}" title="${Action.link}">
		    <span class="material-icons-outlined">link</span>
		  </button>
		</nav>`;

const map: Record<Action, PrefixSuffix> = {
	bold: { prefix: "**", suffix: "**" },
	italic: { prefix: "*", suffix: "*" },
	underline: { prefix: "_", suffix: "_" },
	spoiler: { prefix: "||", suffix: "||" },
	link: { prefix: "[", suffix: "]()" },
};

const areas = [...document.querySelectorAll("[data-md=true]")] as (HTMLTextAreaElement | HTMLInputElement)[];

for (const area of areas) {
	const vDom = new DOMParser().parseFromString(tpl, "text/html").body.childNodes[0] as HTMLElement;

	for (const btn of [...vDom.querySelectorAll("button.btn[data-action]")] as HTMLElement[]) {
		const action: Action = Action[btn.dataset.action];
		btn.addEventListener("click", (_) => {
			const { prefix, suffix } = map[action];
			const start = area.selectionStart;
			const end = area.selectionEnd;

			const text = area.value.substring(start, end);

			area.setRangeText(`${prefix}${text}${suffix}`, start, end, "preserve");
			area.selectionStart = area.selectionEnd = end + prefix.length;
			area.focus();
		});
	}

	area.before(vDom);
}

using the following settings:

const result = await Bun.build({
	entrypoints: files,
	outdir: dest,
	root: source,
	minify: true,
	sourcemap: "linked",
	splitting: false,
});

What is the expected behavior?

With the following settings:

await esbuild.build({
	outdir: '.',
	minify: true,
	sourcemap: true,
	tsconfig: `${roots.js}/tsconfig.json`,
	bundle: true,
}),

ESBuild outputs the following code:

Show code
(()=>{var l=(n=>(n.bold="bold",n.italic="italic",n.underline="underline",n.spoiler="spoiler",n.link="link",n))(l||{}),d=`
		<nav class="button-group toolbar">
		  <button type="button" class="btn" data-action="bold" title="bold">
		    <span class="material-icons-outlined">format_bold</span>
		  </button>
		  <button type="button" class="btn" data-action="italic" title="italic">
		    <span class="material-icons-outlined">format_italic</span>
		  </button>
		  <button type="button" class="btn" data-action="underline" title="underline">
		    <span class="material-icons-outlined">format_underlined</span>
		  </button>
		  <button type="button" class="btn" data-action="spoiler" title="spoiler">
		    <span class="material-icons-outlined">visibility</span>
		  </button>
		  <button type="button" class="btn" data-action="link" title="link">
		    <span class="material-icons-outlined">link</span>
		  </button>
		</nav>`,f=[...document.querySelectorAll("[data-md=true]")];for(let t of f){let i=new DOMParser().parseFromString(d,"text/html").body.childNodes[0];for(let o of[...i.querySelectorAll("button.btn[data-action]")])o.addEventListener("click",b=>{let c=l[o.dataset.action],n={bold:{prefix:"**",suffix:"**"},italic:{prefix:"*",suffix:"*"},underline:{prefix:"_",suffix:"_"},spoiler:{prefix:"||",suffix:"||"},link:{prefix:"[",suffix:"]()"}},{prefix:a,suffix:r}=n[c],s=t.selectionStart,e=t.selectionEnd,u=t.value.substring(s,e);t.setRangeText(`${a}${u}${r}`,s,e,"preserve"),t.selectionStart=t.selectionEnd=e+a.length,t.focus()});t.before(i)}})();
//# sourceMappingURL=markdown-toolbar.js.map

and, as you can see, the enum values are inlined into the template string just fine.

What do you see instead?

Bun outputs the following:

Show code
var s;((n)=>{n.bold="bold";n.italic="italic";n.underline="underline";n.spoiler="spoiler";n.link="link"})(s||={});var u=`
		<nav class="button-group toolbar">
		  <button type="button" class="btn" data-action="${"bold"}" title="${"bold"}">
		    <span class="material-icons-outlined">format_bold</span>
		  </button>
		  <button type="button" class="btn" data-action="${"italic"}" title="${"italic"}">
		    <span class="material-icons-outlined">format_italic</span>
		  </button>
		  <button type="button" class="btn" data-action="${"underline"}" title="${"underline"}">
		    <span class="material-icons-outlined">format_underlined</span>
		  </button>
		  <button type="button" class="btn" data-action="${"spoiler"}" title="${"spoiler"}">
		    <span class="material-icons-outlined">visibility</span>
		  </button>
		  <button type="button" class="btn" data-action="${"link"}" title="${"link"}">
		    <span class="material-icons-outlined">link</span>
		  </button>
		</nav>`,d={bold:{prefix:"**",suffix:"**"},italic:{prefix:"*",suffix:"*"},underline:{prefix:"_",suffix:"_"},spoiler:{prefix:"||",suffix:"||"},link:{prefix:"[",suffix:"]()"}},f=[...document.querySelectorAll("[data-md=true]")];for(let t of f){const i=new DOMParser().parseFromString(u,"text/html").body.childNodes[0];for(let o of[...i.querySelectorAll("button.btn[data-action]")]){const l=s[o.dataset.action];o.addEventListener("click",(b)=>{const{prefix:n,suffix:c}=d[l],a=t.selectionStart,e=t.selectionEnd,r=t.value.substring(a,e);t.setRangeText(`${n}${r}${c}`,a,e,"preserve"),t.selectionStart=t.selectionEnd=e+n.length,t.focus()})}t.before(i)}

//# debugId=C1CF57C826E1467164756E2164756E21
//# sourceMappingURL=markdown-toolbar.js.map

where the enum values are embedded in a non-optimal way

Additional information

tl;dr of the issue:

ESbuild produces

`foo bar baz`

while Bun produces

`foo ${"bar"} baz`

at the same time, trying to create a simple reproduction always results with Bun producing the same code, for example trying to build

enum Foo {
    bar = "bar",
}
const s = `Hello ${Foo.bar}`;
console.log(s);

produces

console.log("Hello bar");

in either case, ESBuild and Bun.

@Atulin Atulin added bug Something isn't working needs triage labels Sep 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working needs triage
Projects
None yet
Development

No branches or pull requests

1 participant