Skip to content

Improve escape_html_attr performance - #4024

Merged
Rich-Harris merged 1 commit into
sveltejs:masterfrom
mrkishi:attr-escape-perf
Feb 21, 2022
Merged

Improve escape_html_attr performance#4024
Rich-Harris merged 1 commit into
sveltejs:masterfrom
mrkishi:attr-escape-perf

Conversation

@mrkishi

@mrkishi mrkishi commented Feb 20, 2022

Copy link
Copy Markdown
Member

Closes #4016.
Depends on #4015.

Replaces the character-by-character loop with a regex-based str.replace call.

Please don't delete this checklist! Before submitting the PR, please make sure you do the following:

  • It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
  • This message body should clearly illustrate what problems it solves.
  • Ideally, include a test that fails without this PR but passes with it.

Tests

  • Run the tests with pnpm test and lint the project with pnpm lint and pnpm check

Changesets

  • If your PR makes a change that should be noted in one or more packages' changelogs, generate a changeset by running pnpx changeset and following the prompts. All changesets should be patch until SvelteKit 1.0

'"': '"'
};

const escape_html_attr_regex = new RegExp(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we add a comment about why this is needed?

@PH4NTOMiki PH4NTOMiki Feb 20, 2022

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why delete < and >
they break HTML if not escaped
we had issue #3773

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and we fixed it with #3798 and #3804

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PH4NTOMiki That was about escape_json_in_html, this is about escape_html_attr.

@benmccann Sorry about the comments, the previous code didn't have them and I thought they weren't necessary. I'll add some.

@changeset-bot

changeset-bot Bot commented Feb 20, 2022

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 4d146d0

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@Rich-Harris

Copy link
Copy Markdown
Member

Nice, I did a naive benchmark locally and this is way faster

@Rich-Harris
Rich-Harris merged commit a9daeec into sveltejs:master Feb 21, 2022
@mrkishi
mrkishi deleted the attr-escape-perf branch February 21, 2022 20:20
Rich-Harris pushed a commit that referenced this pull request Jul 18, 2026
Resolves the TODO in `escape.js` from #4024, which planned to simplify
the surrogate pattern with lookbehind assertions once widely supported.
Lookbehind has been safe everywhere relevant since Safari 16.4, but
`\p{Surrogate}` with the `u` flag is simpler still and supported even
longer (ES2018). Under the `u` flag a valid surrogate pair forms a
single astral code point, so `\p{Surrogate}` matches only unpaired
surrogates and the pattern's other two branches disappear, including the
branch that existed only to match valid pairs so the replace callback
could return them unchanged.

That branch is also why this is a perf change rather than a cleanup.
Every valid pair in rendered content currently invokes the replace
callback just to pass through. With the new pattern pairs never match,
so `escape_html` measures about 2x faster on emoji-heavy content in a
quick microbench, with plain ASCII at parity.

Output is unchanged. I diffed the old and new implementations over 200k
fuzzed strings built from surrogate halves, dict characters and astral
pairs, plus curated edge cases, in both modes, all byte-identical.
`escape.spec.js` passes as-is.

---

### Please don't delete this checklist! Before submitting the PR, please
make sure you do the following:
- [x] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it
solves.
- [ ] Ideally, include a test that fails without this PR but passes with
it.

### Tests
- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets
- [x] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. Changesets that add features should be
`minor` and those that fix bugs should be `patch`. Please prefix
changeset messages with `feat:`, `fix:`, or `chore:`.

### Edits

- [x] Please ensure that 'Allow edits from maintainers' is checked. PRs
without this option may be closed.
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

Successfully merging this pull request may close these issues.

Utf16 handling in html attributes and text

4 participants