diff --git a/docs/config/index.md b/docs/config/index.md index db2dc932efbf30..5862419405aa89 100644 --- a/docs/config/index.md +++ b/docs/config/index.md @@ -164,7 +164,7 @@ export default defineConfig(({ command, mode }) => { - To be consistent with [esbuild behavior](https://esbuild.github.io/api/#define), expressions must either be a JSON object (null, boolean, number, string, array, or object) or a single identifier. - - Replacements are performed only when the match is surrounded by word boundaries (`\b`). + - Replacements are performed only when the match isn't surrounded by other letters, numbers, `_` or `$`. ::: warning Because it's implemented as straightforward text replacements without any syntax analysis, we recommend using `define` for CONSTANTS only. diff --git a/packages/playground/define/__tests__/define.spec.ts b/packages/playground/define/__tests__/define.spec.ts index 709f7a935dc8c1..5d9707e70b47ba 100644 --- a/packages/playground/define/__tests__/define.spec.ts +++ b/packages/playground/define/__tests__/define.spec.ts @@ -20,6 +20,14 @@ test('string', async () => { expect(await page.textContent('.spread-array')).toBe( JSON.stringify([...defines.__STRING__]) ) + expect(await page.textContent('.dollar-identifier')).toBe( + String(defines.$DOLLAR) + ) + expect(await page.textContent('.unicode-identifier')).toBe( + String(defines.ÖUNICODE_LETTERɵ) + ) + expect(await page.textContent('.no-identifier-substring')).toBe(String(true)) + expect(await page.textContent('.no-property')).toBe(String(true)) // html would't need to define replacement expect(await page.textContent('.exp-define')).toBe('__EXP__') expect(await page.textContent('.import-json')).toBe('__EXP__') diff --git a/packages/playground/define/index.html b/packages/playground/define/index.html index da78d192216b11..c89a3fe02218ff 100644 --- a/packages/playground/define/index.html +++ b/packages/playground/define/index.html @@ -9,6 +9,10 @@

Define

process as property:

spread object:

spread array:

+

dollar identifier:

+

unicode identifier:

+

no property:

+

no identifier substring:

define variable in html: __EXP__

import json:

@@ -28,6 +32,15 @@

Define

}) ) text('.spread-array', JSON.stringify([...`"${__STRING__}"`])) + text('.dollar-identifier', $DOLLAR) + text('.unicode-identifier', ÖUNICODE_LETTERɵ) + + // make sure these kinds of use are NOT replaced: + const obj = { [`${'_'}_EXP__`]: true } + text('.no-property', obj.__EXP__) + + window[`${'_'}_EXP__SUBSTR__`] = true + text('.no-identifier-substring', __EXP__SUBSTR__) import dataJson from './data.json' text('.import-json', dataJson.foo) diff --git a/packages/playground/define/vite.config.js b/packages/playground/define/vite.config.js index 848abd09322df6..88173fe654b58d 100644 --- a/packages/playground/define/vite.config.js +++ b/packages/playground/define/vite.config.js @@ -15,7 +15,9 @@ module.exports = { } } }, - __VAR_NAME__: false, - 'process.env.SOMEVAR': '"SOMEVAR"' + 'process.env.SOMEVAR': '"SOMEVAR"', + $DOLLAR: 456, + ÖUNICODE_LETTERɵ: 789, + __VAR_NAME__: false } } diff --git a/packages/vite/src/node/plugins/define.ts b/packages/vite/src/node/plugins/define.ts index 19ca28b34433a0..ca0f446cc1f58e 100644 --- a/packages/vite/src/node/plugins/define.ts +++ b/packages/vite/src/node/plugins/define.ts @@ -68,16 +68,18 @@ export function definePlugin(config: ResolvedConfig): Plugin { const replacementsKeys = Object.keys(replacements) const pattern = replacementsKeys.length ? new RegExp( - // Do not allow preceding '.', but do allow preceding '...' for spread operations - '(? { return str.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&') }) .join('|') + - // prevent trailing assignments - ')\\b(?!\\s*?=[^=])', - 'g' + // Mustn't be followed by a char that can be part of an identifier + // or an assignment (but allow equality operators) + ')(?![\\p{L}\\p{N}_$]|\\s*?=[^=])', + 'gu' ) : null