`aio app build` generates `jsxDEV` for Admin UI V2 even with `NODE_ENV=production`
- Dominant language
- JavaScript
- Stars
- 7
- Forks
- 15
- Avg merge
- 22h 17m
- Merged PRs (30d)
- 1
Description
## Description
When building an Adobe Commerce Admin UI SDK V2 extension using `aio app build`, the generated web bundle is compiled using React's development JSX runtime (`react/jsx-dev-runtime` / `jsxDEV`), even when `NODE_ENV=production` and `--web-optimize` are used.
This causes the deployed Admin UI extension to fail at runtime with:
```text
Uncaught TypeError: (0 , _jsxDevRuntime.jsxDEV) is not a function
```
## Environment
* Node.js: `v24.x`
* npm: `11.x`
* `@adobe/aio-cli`: `11.1.2`
* `@adobe/aio-cli-plugin-app`: `14.8.2`
* `@adobe/aio-commerce-lib-app`: `1.11.0`
* `@adobe/aio-commerce-lib-admin-ui`: `1.0.1`
* `@adobe/aio-commerce-sdk`: `1.4.2`
* React: `19.3.0`
* TypeScript: `6.0.3`
* Parcel: `2.16.4`
* `@adobe/aio-lib-web`: `7.2.0`
The extension uses:
```yaml
commerce/backend-ui/2
```
and the web source is TypeScript/TSX.
## Reproduction
The project is created using the Adobe Commerce Admin UI SDK V2 scaffolding.
The TypeScript configuration contains:
```json
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "react",
"module": "esnext",
"moduleResolution": "bundler",
"noEmit": true
}
}
```
A normal TypeScript compilation correctly produces:
```js
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
```
However, after running:
```bash
NODE_ENV=production aio app build --force-build
```
or:
```bash
NODE_ENV=production aio app build --force-build --web-optimize
```
the generated Admin UI bundle contains:
```text
react/jsx-dev-runtime
```
and calls:
```js
jsxDEV(...)
```
The resulting application fails at runtime:
```text
Uncaught TypeError: (0 , _jsxDevRuntime.jsxDEV) is not a function
```
## Expected behavior
A production App Builder build should compile the React JSX using:
```text
react/jsx-runtime
```
and generate:
```js
jsx(...)
```
rather than:
```js
jsxDEV(...)
```
when building for production.
## Investigation
I traced the build process to `@adobe/aio-lib-web`.
The relevant Parcel options are constructed approximately as follows:
```js
const parcelBundleOptions = {
entries,
defaultConfig: require.resolve('@parcel/config-default'),
shouldDisableCache: false,
targets: {
webassets: {
includeNodeModules: true,
distDir: dest
}
},
defaultTargetOptions: {
distDir: dest,
shouldOptimize: options.shouldOptimize
},
shouldPatchConsole: false,
shouldContentHash: true,
logLevel: 'error',
...options
}
```
The important observation is that `mode` is not explicitly provided.
Parcel defaults:
```js
mode = initialOptions.mode ?? 'development';
```
Therefore, even when:
```bash
NODE_ENV=production
```
is set, Parcel's own `options.mode` remains:
```text
development
```
The Parcel JavaScript transformer then uses the development mode when configuring the React JSX transform, resulting in:
```text
react/jsx-dev-runtime
jsxDEV()
```
I also verified that React itself is functioning correctly:
```text
react/jsx-runtime.jsx -> function
react/jsx-dev-runtime.jsxDEV -> function
```
A standalone TypeScript compilation also correctly generates `react/jsx-runtime`.
Therefore, this appears to be related to the Parcel build mode rather than React or TypeScript.
## Additional testing
The following were tested:
### 1. `NODE_ENV=production`
```bash
NODE_ENV=production aio app build --force-build
```
Still produces `jsxDEV`.
### 2. `--web-optimize`
```bash
aio app build --force-build --web-optimize
```
Still produces `jsxDEV`.
### 3. `NODE_ENV=production` + `--web-optimize`
```bash
NODE_ENV=production aio app build --force-build --web-optimize
```
Still produces `jsxDEV`.
### 4. Parcel production mode
Parcel's API supports explicitly passing:
```js
mode: "production"
```
When Parcel receives `mode: "production"`, the React JSX transformation correctly uses the production JSX runtime.
## Question
Is there currently a supported way to pass:
```js
mode: "production"
```
to the Parcel instance used by `aio app build`?
For example, something equivalent to:
```bash
aio app build --mode production
```
or a supported App Builder/package configuration that causes `@adobe/aio-lib-web` to pass:
```js
{
mode: "production"
}
```
to Parcel?
If there is no supported configuration mechanism, could the build pipeline be updated so that production builds explicitly pass:
```js
mode: "production"
```
to Parcel?
For example:
```js
mode: options.mode || (options.shouldOptimize ? "production" : "development")
```
or an equivalent implementation.
## Why this matters
`NODE_ENV=production` is currently insufficient because the JSX transformation appears to depend on Parcel's `mode`, not only the runtime `NODE_ENV`.
This means an Admin UI V2 extension can successfully build and deploy but fail immediately in the browser because the production React runtime is incompatible with the generated `jsxDEV()` calls.
Any guidance on the officially supported way to force Parcel into production mode during `aio app build` would be appreciated.
Thank you!
Contributor guide
Research direction
Start at the Parcel options construction in @adobe/aio-lib-web and reproduce the issue through the `aio app build` entry point with `NODE_ENV=production` and `--web-optimize`. Check how Parcel receives its mode, then verify that a production build uses `react/jsx-runtime` and `jsx(...)` rather than `react/jsx-dev-runtime` and `jsxDEV(...)`.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, nodejs, react, typescript
- Domain
- build-system, frontend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100