What kind of issue is this?
Bug — @quasar/app-vite (Vite/rolldown build).
Versions
@quasar/app-vite: 3.0.1
quasar: 2.21.1
- vite (rolldown-vite): 8.1.3
- rolldown: 1.1.4
- Node: 24
What happens
quasar build aborts while compiling quasar.config.js with:
App • Compiling quasar.config.js (no env prefix; no dotenv files)
Error: Build failed with 1 error:
[INVALID_DEFINE_CONFIG] Invalid characters after number
at .../node_modules/rolldown/dist/shared/error-*.mjs
at #build (.../@quasar/app-vite/lib/quasar-config-file.js:641:7)
App • ⚠️ FAIL Could not compile the quasar.config file because it has errors.
The failure depends only on the values present in process.env at build time, not on any user code. It surfaced for us in CI because GitLab sets CI_COMMIT_SHORT_SHA, and for one commit its value was 024766e0 — which is why it was intermittent and never reproduced locally.
Minimal reproduction
Any project, no dotenv files, default (empty) quasarConfEnv prefix:
FOO=024766e0 quasar build # 024766e0 -> Number() === 24766 (an 'e0' exponent), but not a valid bare literal
# or, even simpler:
FOO=08 quasar build # Number('08') === 8, but `08` is an invalid numeric literal in strict/module code
FOO=0755 quasar build # Number('0755') === 755, but `0755` is a legacy octal literal (SyntaxError in ESM)
All fail with [INVALID_DEFINE_CONFIG] Invalid characters after number. A "normal" string value (e.g. FOO=abc123, Number() → NaN) builds fine because it gets quoted.
Root cause
When compiling quasar.config.js, the define map is built from env vars. With the default empty prefix, all of process.env is included (lib/utils/env.js → getFileEnvResult returns { ...processEnv } when there are no dotenv files; the empty-prefix regex matches every key). Each value is then stringified by getStrDefineValue (lib/utils/env.js):
function getStrDefineValue(value) {
if (asIsList.includes(value)) return value
const trimmed = value.trim()
return trimmed !== '' && !Number.isNaN(Number(trimmed))
? value // <-- emitted RAW / unquoted
: JSON.stringify(value)
}
Number() is far more permissive than JavaScript's numeric-literal grammar. Values like 024766e0, 08, 0755, 0x-less hex-ish strings, whitespace-padded numbers, etc. are not NaN under Number(), so they are spliced into the rolldown define map unquoted, producing an invalid expression that the bundler correctly rejects.
Two smaller points in the same function:
- It returns the untrimmed
value in the numeric branch, so " 3000 " would also be emitted raw.
- Emitting numeric env values as unquoted number literals also diverges from Vite semantics, where
import.meta.env.* values are strings.
Expected
A valid string env var should never break the build. Env var values are always strings and should be quoted.
Suggested fix
Either:
-
Always JSON.stringify env values (simplest, matches Vite's string semantics), or
-
If numeric passthrough is intentional, gate it on a strict numeric-literal check instead of Number(), e.g. a canonical-number regex, and use trimmed rather than value:
const NUMERIC_LITERAL_RE = /^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$/
return NUMERIC_LITERAL_RE.test(trimmed) ? trimmed : JSON.stringify(value)
Separately, consider whether injecting all of process.env (empty default prefix) into the quasar.config compile is desirable, since it can leak unrelated/sensitive CI variables into build-time defines.
Workaround
Set a non-empty config-env prefix so only intended vars reach the config compile (package.json):
{
"quasarCli": {
"quasarConfEnv": { "prefix": "MYAPP_CONF_" }
}
}
What kind of issue is this?
Bug —
@quasar/app-vite(Vite/rolldown build).Versions
@quasar/app-vite: 3.0.1quasar: 2.21.1What happens
quasar buildaborts while compilingquasar.config.jswith:The failure depends only on the values present in
process.envat build time, not on any user code. It surfaced for us in CI because GitLab setsCI_COMMIT_SHORT_SHA, and for one commit its value was024766e0— which is why it was intermittent and never reproduced locally.Minimal reproduction
Any project, no dotenv files, default (empty)
quasarConfEnvprefix:All fail with
[INVALID_DEFINE_CONFIG] Invalid characters after number. A "normal" string value (e.g.FOO=abc123,Number()→NaN) builds fine because it gets quoted.Root cause
When compiling
quasar.config.js, the define map is built from env vars. With the default empty prefix, all ofprocess.envis included (lib/utils/env.js→getFileEnvResultreturns{ ...processEnv }when there are no dotenv files; the empty-prefix regex matches every key). Each value is then stringified bygetStrDefineValue(lib/utils/env.js):Number()is far more permissive than JavaScript's numeric-literal grammar. Values like024766e0,08,0755,0x-less hex-ish strings, whitespace-padded numbers, etc. are notNaNunderNumber(), so they are spliced into the rolldowndefinemap unquoted, producing an invalid expression that the bundler correctly rejects.Two smaller points in the same function:
valuein the numeric branch, so" 3000 "would also be emitted raw.import.meta.env.*values are strings.Expected
A valid string env var should never break the build. Env var values are always strings and should be quoted.
Suggested fix
Either:
Always
JSON.stringifyenv values (simplest, matches Vite's string semantics), orIf numeric passthrough is intentional, gate it on a strict numeric-literal check instead of
Number(), e.g. a canonical-number regex, and usetrimmedrather thanvalue:Separately, consider whether injecting all of
process.env(empty default prefix) into thequasar.configcompile is desirable, since it can leak unrelated/sensitive CI variables into build-time defines.Workaround
Set a non-empty config-env prefix so only intended vars reach the config compile (
package.json):{ "quasarCli": { "quasarConfEnv": { "prefix": "MYAPP_CONF_" } } }