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

\x3c within strings is replaced with <, causing script tags to be closed preemptively by the browser #1322

Closed
DerGernTod opened this issue May 27, 2021 · 4 comments

Comments

@DerGernTod
Copy link

DerGernTod commented May 27, 2021

I have some code that renders a popup window including script tags, somewhat like this:

const POPUP_CONTENT = `<html><body><script>var foo = "bar"\x3c/script><div>something</div></body>`;

The \x3c is required because otherwise, when the browser parses the script that contains this string, it will close the script tag and the rest of the script will simply be rendered (in this case, <div>something</div></body>).

Unfortunately esbuild replaces \x3c with <:

echo "var foo = \"\x3c\";" | npx esbuild // outputs 'var foo = "<";';

This of course breaks everything for us since all code that comes after \x3c/script> is simply not executed. I also tried to split the string into a concatenated version that the browser doesn't recognize, but of course esbuild optimizes this and transforms it back into a single string.

It seems like this can be worked around by building a string array and joining it, but since this has to be done during runtime it's rather uncanny:

const POPUP_CONTENT = [`<html><body><script>var foo = "bar"<`, `/script><div>something</div></body>`].join("");

Is this expected or just an unhandled problem?

@jridgewell
Copy link
Contributor

jridgewell commented May 27, 2021

Parsing of <script> node contents, and parsing of JS files are different. I don't believe it's possible to just inject a JS file into a <script> node and have it behave the same.

I think whatever system you're using to inject the <script> node contents should be fixed to scan for </script and correct it back to \x3c.

@evanw
Copy link
Owner

evanw commented May 27, 2021

Is this expected or just an unhandled problem?

This is just unhandled. I'm actually surprised I haven't handled it yet since I'm already aware of the problem.

I think whatever system you're using to inject the <script> node contents should be fixed to scan for </script and correct it back to \x3c.

I think it's reasonable for esbuild to handle this case. Other JavaScript tools such as Terser already handle this.

@evanw evanw closed this as completed in 5e749a2 May 27, 2021
@jridgewell
Copy link
Contributor

I think it's reasonable for esbuild to handle this case. Other JavaScript tools such as Terser already handle this.

This leaves a weird edge case with tagged template literals:

function printRaw(strings) {
  console.log(strings.raw);
}

printRaw`</script>`;

It's not possible to transform the </script in a way that will preserve the runtime meaning without down leveling the entire expression.

@evanw
Copy link
Owner

evanw commented May 28, 2021

It's not possible to transform the </script in a way that will preserve the runtime meaning without down leveling the entire expression.

Good point. I just added down-leveling for tagged template literals in this case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants