Skip to content

Commit 95eb45b

Browse files
authoredMay 5, 2022
feat: allow any JS identifier in define, not ASCII-only (#5972)
1 parent 0e67fe8 commit 95eb45b

File tree

5 files changed

+33
-8
lines changed

5 files changed

+33
-8
lines changed
 

‎docs/config/index.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ export default defineConfig(({ command, mode }) => {
164164

165165
- 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.
166166

167-
- Replacements are performed only when the match is surrounded by word boundaries (`\b`).
167+
- Replacements are performed only when the match isn't surrounded by other letters, numbers, `_` or `$`.
168168

169169
::: warning
170170
Because it's implemented as straightforward text replacements without any syntax analysis, we recommend using `define` for CONSTANTS only.

‎packages/playground/define/__tests__/define.spec.ts

+8
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ test('string', async () => {
2020
expect(await page.textContent('.spread-array')).toBe(
2121
JSON.stringify([...defines.__STRING__])
2222
)
23+
expect(await page.textContent('.dollar-identifier')).toBe(
24+
String(defines.$DOLLAR)
25+
)
26+
expect(await page.textContent('.unicode-identifier')).toBe(
27+
String(defines.ÖUNICODE_LETTERɵ)
28+
)
29+
expect(await page.textContent('.no-identifier-substring')).toBe(String(true))
30+
expect(await page.textContent('.no-property')).toBe(String(true))
2331
// html would't need to define replacement
2432
expect(await page.textContent('.exp-define')).toBe('__EXP__')
2533
expect(await page.textContent('.import-json')).toBe('__EXP__')

‎packages/playground/define/index.html

+13
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ <h1>Define</h1>
99
<p>process as property: <code class="process-as-property"></code></p>
1010
<p>spread object: <code class="spread-object"></code></p>
1111
<p>spread array: <code class="spread-array"></code></p>
12+
<p>dollar identifier: <code class="dollar-identifier"></code></p>
13+
<p>unicode identifier: <code class="unicode-identifier"></code></p>
14+
<p>no property: <code class="no-property"></code></p>
15+
<p>no identifier substring: <span class="no-identifier-substring"></span></p>
1216
<p>define variable in html: <code class="exp-define">__EXP__</code></p>
1317
<p>import json: <code class="import-json"></code></p>
1418

@@ -28,6 +32,15 @@ <h1>Define</h1>
2832
})
2933
)
3034
text('.spread-array', JSON.stringify([...`"${__STRING__}"`]))
35+
text('.dollar-identifier', $DOLLAR)
36+
text('.unicode-identifier', ÖUNICODE_LETTERɵ)
37+
38+
// make sure these kinds of use are NOT replaced:
39+
const obj = { [`${'_'}_EXP__`]: true }
40+
text('.no-property', obj.__EXP__)
41+
42+
window[`${'_'}_EXP__SUBSTR__`] = true
43+
text('.no-identifier-substring', __EXP__SUBSTR__)
3144

3245
import dataJson from './data.json'
3346
text('.import-json', dataJson.foo)

‎packages/playground/define/vite.config.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ module.exports = {
1515
}
1616
}
1717
},
18-
__VAR_NAME__: false,
19-
'process.env.SOMEVAR': '"SOMEVAR"'
18+
'process.env.SOMEVAR': '"SOMEVAR"',
19+
$DOLLAR: 456,
20+
ÖUNICODE_LETTERɵ: 789,
21+
__VAR_NAME__: false
2022
}
2123
}

‎packages/vite/src/node/plugins/define.ts

+7-5
Original file line numberDiff line numberDiff line change
@@ -68,16 +68,18 @@ export function definePlugin(config: ResolvedConfig): Plugin {
6868
const replacementsKeys = Object.keys(replacements)
6969
const pattern = replacementsKeys.length
7070
? new RegExp(
71-
// Do not allow preceding '.', but do allow preceding '...' for spread operations
72-
'(?<!(?<!\\.\\.)\\.)\\b(' +
71+
// Mustn't be preceded by a char that can be part of an identifier
72+
// or a '.' that isn't part of a spread operator
73+
'(?<![\\p{L}\\p{N}_$]|(?<!\\.\\.)\\.)(' +
7374
replacementsKeys
7475
.map((str) => {
7576
return str.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&')
7677
})
7778
.join('|') +
78-
// prevent trailing assignments
79-
')\\b(?!\\s*?=[^=])',
80-
'g'
79+
// Mustn't be followed by a char that can be part of an identifier
80+
// or an assignment (but allow equality operators)
81+
')(?![\\p{L}\\p{N}_$]|\\s*?=[^=])',
82+
'gu'
8183
)
8284
: null
8385

0 commit comments

Comments
 (0)