This is an automated email from the ASF dual-hosted git repository. rusackas pushed a commit to branch change/33615-chart-data-query-context in repository https://gitbox.apache.org/repos/asf/superset.git
commit b92270e3d43628f8a6e827c34bcb7c255c895d6a Author: Eugene Olkhovski <[email protected]> AuthorDate: Fri Aug 28 07:14:18 2026 -0400 fix(charts): wire query_context parity bundle into build + registry smoke check (#33615) Make exact frontend-parity query_context synthesis the default in deployments and guard the generated registry (addresses review): - build-backend-querycontext: bundle non-JS assets (fonts/CSS/SVG/images) with the esbuild `empty` loader so the buildQuery bundle builds cleanly even as the registry broadens (backend runs only generateQueryContext in V8, never renders) - package.json: run the bundle build in the supported flow via a `postbuild` hook, and add gen/check scripts for the registry - gen-qc-registry: add `--check` mode; CI (lint-frontend) now regenerates the registry and rebuilds the bundle so a plugin added/removed without regenerating fails the build (smoke check requested in review) - MANIFEST.in: ship superset/commands/chart/_bundles/*.js so packaged distributions carry the bundle instead of silently falling back - pyproject: add optional `querycontext` extra (py-mini-racer) for the V8 runtime - docs: README + generator docstring describe the wired build/package flow Co-Authored-By: Claude Opus 4.8 <[email protected]> --- .github/workflows/superset-frontend.yml | 5 +++++ .gitignore | 5 +++-- MANIFEST.in | 4 ++++ pyproject.toml | 5 +++++ superset-frontend/package.json | 3 +++ .../scripts/build-backend-querycontext.mjs | 20 ++++++++++++++++-- superset-frontend/scripts/gen-qc-registry.mjs | 19 ++++++++++++++++- superset/commands/chart/_bundles/README.md | 24 +++++++++++++++++----- superset/commands/chart/query_context_generator.py | 9 +++++--- 9 files changed, 81 insertions(+), 13 deletions(-) diff --git a/.github/workflows/superset-frontend.yml b/.github/workflows/superset-frontend.yml index 9b7896c1176..dfdac041c2b 100644 --- a/.github/workflows/superset-frontend.yml +++ b/.github/workflows/superset-frontend.yml @@ -163,6 +163,11 @@ jobs: docker run --rm $TAG bash -c \ "npm i && npm run plugins:build && npm run type" + - name: backend query_context registry + bundle (superset #33615) + run: | + docker run --rm $TAG bash -c \ + "npm i && npm run check:backend-querycontext-registry && npm run build:backend-querycontext" + validate-frontend: needs: frontend-build if: needs.frontend-build.outputs.should-run == 'true' diff --git a/.gitignore b/.gitignore index 9c17c161824..9e930be34a0 100644 --- a/.gitignore +++ b/.gitignore @@ -128,8 +128,9 @@ docker-compose.override.yml .temp_cache -# Generated backend query_context bundle (built via -# `npm run build:backend-querycontext`; see superset/commands/chart/_bundles/README.md) +# Generated backend query_context bundle (built by `npm run build` via its +# postbuild hook; shipped in packages through MANIFEST.in even though it stays +# untracked here — see superset/commands/chart/_bundles/README.md) superset/commands/chart/_bundles/*.js # Jest test report diff --git a/MANIFEST.in b/MANIFEST.in index 4d7a98b2a7a..66efe22c3af 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -24,4 +24,8 @@ recursive-include superset/migrations * recursive-include superset/templates * recursive-include superset/translations * recursive-include superset/static * +# Backend query_context parity bundle (#33615): a build artifact produced by +# `npm run build` (postbuild). Ship it so deployments get exact frontend parity +# by default instead of silently falling back to the generic derivation. +recursive-include superset/commands/chart/_bundles *.js recursive-exclude tests * diff --git a/pyproject.toml b/pyproject.toml index 79ed07cbbfb..32aae99c2a6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -254,6 +254,11 @@ postgres = ["psycopg2-binary==2.9.13"] presto = ["pyhive[presto]>=0.7.0"] trino = ["trino>=0.339.0"] prophet = ["prophet>=1.4.0, <2"] +# Exact frontend-parity query_context synthesis for chart import (#33615): runs +# the real `buildQuery` bundle in V8 via py_mini_racer. Optional — without it the +# importer falls back to the pure-Python generic derivation. Install this extra +# (and ship the bundle, built by `npm run build`) to make exact parity the default. +querycontext = ["py-mini-racer>=0.12.4, <1.0"] # sqlalchemy-redshift cuts hard from SQLAlchemy 1.4-only (0.8.x) to 2.0-only # (>=1.0.0) with no dual-compat release. Bumped now that Superset's own # SQLAlchemy 2.0 core bump has landed (discussion #40273). diff --git a/superset-frontend/package.json b/superset-frontend/package.json index 827d8a179ab..922327a95d7 100644 --- a/superset-frontend/package.json +++ b/superset-frontend/package.json @@ -41,6 +41,9 @@ "_format": "oxfmt './{src,spec,cypress-base,plugins,packages,.storybook}/**/*{.js,.jsx,.ts,.tsx,.css,.scss,.sass,.json}'", "build": "cross-env NODE_OPTIONS=--max_old_space_size=8192 NODE_ENV=production BABEL_ENV=\"${BABEL_ENV:=production}\" webpack --color --mode production", "build:backend-querycontext": "node scripts/build-backend-querycontext.mjs", + "postbuild": "npm run build:backend-querycontext", + "gen:backend-querycontext-registry": "node scripts/gen-qc-registry.mjs", + "check:backend-querycontext-registry": "node scripts/gen-qc-registry.mjs --check", "build-dev": "cross-env NODE_OPTIONS=--max_old_space_size=8192 NODE_ENV=development webpack --mode=development --color", "build-instrumented": "cross-env NODE_ENV=production BABEL_ENV=instrumented webpack --mode=production --color", "build-storybook": "storybook build", diff --git a/superset-frontend/scripts/build-backend-querycontext.mjs b/superset-frontend/scripts/build-backend-querycontext.mjs index 67a3adba680..3d811e14d2d 100644 --- a/superset-frontend/scripts/build-backend-querycontext.mjs +++ b/superset-frontend/scripts/build-backend-querycontext.mjs @@ -58,8 +58,24 @@ build({ target: 'es2020', legalComments: 'none', logLevel: 'info', - // esbuild infers the `ts` loader from the .ts extension; keep JSX off (these - // buildQuery modules are pure TS, no React). + // `buildQuery` modules are pure query logic, but they are reached through + // barrel imports that transitively pull in non-JS assets (fonts, CSS, SVGs, + // images) from the theme/UI layer. The backend runs only `generateQueryContext` + // in V8 and never renders any of that, so drop those assets with the `empty` + // loader instead of failing to bundle. (esbuild infers the `ts` loader from the + // .ts extension; these modules are pure TS, no JSX.) + loader: { + '.css': 'empty', + '.svg': 'empty', + '.png': 'empty', + '.jpg': 'empty', + '.jpeg': 'empty', + '.gif': 'empty', + '.woff': 'empty', + '.woff2': 'empty', + '.ttf': 'empty', + '.eot': 'empty', + }, }) .then(() => { // eslint-disable-next-line no-console diff --git a/superset-frontend/scripts/gen-qc-registry.mjs b/superset-frontend/scripts/gen-qc-registry.mjs index 5a6e5bd4364..3c798c5ace2 100644 --- a/superset-frontend/scripts/gen-qc-registry.mjs +++ b/superset-frontend/scripts/gen-qc-registry.mjs @@ -206,7 +206,24 @@ const header = `// Licensed to the Apache Software Foundation (ASF) under one // GENERATED by superset-frontend/scripts/gen-qc-registry.mjs — DO NOT EDIT. // Re-run: node scripts/gen-qc-registry.mjs `; -writeFileSync(OUT, `${header}\n${imports}\n${body}`, 'utf8'); +const generated = `${header}\n${imports}\n${body}`; + +// `--check` (smoke check): fail instead of writing if the committed registry is +// stale, so CI catches a plugin added/removed without regenerating. +if (process.argv.includes('--check')) { + const current = existsSync(OUT) ? readFileSync(OUT, 'utf8') : ''; + if (current !== generated) { + console.error( + `${path.relative(FE, OUT)} is out of date. ` + + 'Run `npm run gen:backend-querycontext-registry` and commit the result.', + ); + process.exit(1); + } + console.log(`${path.relative(FE, OUT)} is up to date.`); + process.exit(0); +} + +writeFileSync(OUT, generated, 'utf8'); console.log(`buildQuery modules: ${buildQueryFiles.length}`); console.log(`viz keys mapped: ${entries.length}`); diff --git a/superset/commands/chart/_bundles/README.md b/superset/commands/chart/_bundles/README.md index d27797fcfa2..3ebff76af53 100644 --- a/superset/commands/chart/_bundles/README.md +++ b/superset/commands/chart/_bundles/README.md @@ -23,17 +23,31 @@ This directory holds the bundled frontend `buildQuery` code that the backend runs in V8 (`py_mini_racer`) to synthesize a faithful `query_context` for imported charts (Apache Superset #33615). -**`query_context_bundle.js` is generated, not committed.** Build it with: +**`query_context_bundle.js` is a generated build artifact, not committed.** It is +produced automatically as part of the standard frontend build: ```bash cd superset-frontend -npm run build:backend-querycontext +npm run build # runs build:backend-querycontext via the postbuild hook ``` +or on its own with `npm run build:backend-querycontext`. + +Because the supported build produces it and `MANIFEST.in` ships +`superset/commands/chart/_bundles/*.js`, packaged Superset distributions carry the +bundle by default (it is `.gitignore`d in the working tree but included at build +time). + Source entry: `superset-frontend/src/backend-querycontext/entry.ts`. Consumer: `superset/commands/chart/query_context_generator.py`. -When the bundle is absent the generator degrades gracefully and the importer -falls back to the pure-Python generic derivation in +To enable exact parity at runtime, install the V8 runtime extra: + +```bash +pip install "apache-superset[querycontext]" # pulls py-mini-racer +``` + +When the bundle or `py_mini_racer` is absent the generator degrades gracefully and +the importer falls back to the pure-Python generic derivation in `superset/commands/chart/query_context_builder.py` — nothing breaks; parity just -isn't available until the bundle is built (a packaging/CI step). +isn't available until both are present. diff --git a/superset/commands/chart/query_context_generator.py b/superset/commands/chart/query_context_generator.py index 9635d3409fc..4f31420e5a0 100644 --- a/superset/commands/chart/query_context_generator.py +++ b/superset/commands/chart/query_context_generator.py @@ -29,9 +29,12 @@ not been built, or evaluation fails, :meth:`QueryContextGenerator.generate` returns ``None`` and the caller falls back to the pure-Python generic derivation (:func:`superset.commands.chart.query_context_builder.build_query_context_config`). -Build the bundle with ``npm run build:backend-querycontext`` (from -``superset-frontend/``); the artifact lands at -``superset/commands/chart/_bundles/query_context_bundle.js``. +The bundle is produced by the standard frontend build (``npm run build`` runs it +via a ``postbuild`` hook; or ``npm run build:backend-querycontext`` alone) and +lands at ``superset/commands/chart/_bundles/query_context_bundle.js``, shipped in +packaged distributions via ``MANIFEST.in``. Install the V8 runtime with the +``querycontext`` extra (``pip install "apache-superset[querycontext]"``) to make +exact parity the default rather than the fallback. """ from __future__ import annotations
