Add a Vite plugin to auto-prefix -webkit-user-select so it's not so often forgotten (#4288)

* Add a Vite plugin to auto-prefix -webkit-user-select so it's not so often forgotten

* Enforce a property boundary on the left
This commit is contained in:
Keavon Chambers
2026-06-28 00:20:26 -07:00
committed by GitHub
parent cc465d6f2a
commit fa27d53b98
5 changed files with 26 additions and 5 deletions
+26 -1
View File
@@ -11,7 +11,7 @@ const projectRootDir = path.resolve(__dirname);
// https://vitejs.dev/config/
export default defineConfig(({ mode }) => {
return {
plugins: [svelteGlobalStyles(), svelte(), staticAssets(), mode !== "native" && thirdPartyLicenses(), mode !== "native" && serviceWorker()],
plugins: [svelteGlobalStyles(), webkitUserSelectPrefix(), svelte(), staticAssets(), mode !== "native" && thirdPartyLicenses(), mode !== "native" && serviceWorker()],
resolve: {
alias: [{ find: /\/..\/branding\/(.*\.svg)/, replacement: path.resolve(projectRootDir, "../branding", "$1?raw") }],
},
@@ -35,6 +35,31 @@ function svelteGlobalStyles(): PluginOption {
};
}
// Adds the `-webkit-user-select` prefix alongside every `user-select` declaration in Svelte component styles (still required by Safari). Remove when Safari ships the unprefixed version.
// WebKit tracking issue:
// https://bugs.webkit.org/show_bug.cgi?id=208677
// Included in Interop 2026:
// https://webkit.org/blog/17818/announcing-interop-2026/#web-compat
// https://github.com/web-platform-tests/interop/issues/1000#issuecomment-3892214470
// Web platform test for WebKit implementation status:
// https://wpt.fyi/results/css/css-ui/parsing/user-select-computed.html?label=master&label=experimental&aligned&view=interop&q=label%3Ainterop-2026-webcompat
function webkitUserSelectPrefix(): PluginOption {
return {
name: "webkit-user-select-prefix",
enforce: "pre",
transform(code, id) {
if (!id.endsWith(".svelte")) return;
return code.replace(/<style(?=\s|>)([^>]*)>(.*?)<\/style>/gs, (_, attrs, content) => {
// The lookbehind requires a property boundary on the left, so it skips `-webkit-`/`-moz-` prefixes, `--custom` properties, and `$scss-variables`.
// Excluding newlines/braces from the value stops a `user-select` mentioned in a comment from swallowing the following declarations.
const prefixed = content.replace(/(?<![\w$-])user-select\s*:\s*([^;{}\r\n]+);/g, "-webkit-user-select: $1; user-select: $1;");
return `<style${attrs}>${prefixed}</style>`;
});
},
};
}
function staticAssets(): PluginOption {
const STATIC_ASSET_DIRS: { source: string; urlPrefix: string }[] = [
{ source: "../demo-artwork", urlPrefix: "/demo-artwork" },