Skip to content

Commit 7d71211

Browse files
whitphxCopilot
andauthored
Create @stlite/react and import it from @stlite/browser (#1696)
* Create @stlite/react and import it from @stlite/browser * Fix eslint.config.mjs * Make @stlite/browser use @stlite/react * Make @stlite/sharing use @stlite/react * Fix @stlite/react * Fix @stlite/sharing * Make @stlite/desktop use @stlite/react * Build vite-plugin to isolate the dependencies * fix Makefile * Add separate vitest.config.ts * Rename StreamlitApp -> StliteApp * Encapsulate toast callbacks into StliteAppWithToast and make browser/desktop/sharing use it * Fix root tsconfig.json * Move toastify components into @stlite/react and remove common-react * Export stlite.css from @stlite/react and import it in browser/desktop/sharing * Explicitly pass the wheel urls * Make browser/desktop/sharing independent from @stlite/kernel * Update react make rule * Fix browser * Set workerType * Set kernel exports and update electron tsconfig * Remove worker config * Configure react/.prettierignore * Fix * Set assetFileNames in react/vite-plugin and update vite configs * Separate @stlite/react/wheels for tree shaking * Update AGENTS.md * Fix * Experimentally introduce vite-plugin-lib-assets to @stlite/react * Emit wasm files separately * fix react/vite.config.ts * Add CI/CD pipeline for react package * fix * Fix dependencies * Fix * fix * Fix react/.gitignore * Set files field in react/package.json * Add changeset * Add react/README.md * Fix dev server setting in react/vite.config.ts * fix * fix * Mount ToastContainer * fix * comment * Update .github/workflows/postbuild.yml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Fix dep * Remove define in react/vite.config.ts because process.env is ignored in lib build: https://github.com/vitejs/vite/blob/ab0c3b26533ebe48c9db3f7238938cec665f64ef/packages/vite/src/node/plugins/define.ts#L19 * Remove process.env.NODE_ENV definition from vite-plugin-stlite-react * Fix wheel URL import utility * Rename packages/react/src/wheels.ts -> packages/react/src/vite-utils/wheels.ts * Stop using path.join to construct the assetFileName pattern because its path separator is OS-dependent * Instantiate worker from data url directly * Update react/README.md * fix * fix * Run smoke test on @stlite/react * Make test-react runnable * Set kernel's development exports * fix * Return a new object instead of mutating a passed object in vite-plugin * tmp: skip test react * Add changeset * Add dependencies of testing-library/react * Run react test --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent b094043 commit 7d71211

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+1543
-1018
lines changed

.changeset/flat-doodles-tap.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@stlite/kernel": minor
3+
---
4+
5+
Add ESM exports, `worker` and `worker-runtime`

.changeset/grumpy-ducks-cross.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@stlite/react": minor
3+
---
4+
5+
Create @stlite/react package that provides Stlite as React components
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@stlite/browser": minor
3+
"@stlite/desktop": minor
4+
"@stlite/sharing": minor
5+
---
6+
7+
Use @stlite/react as the foundation instead of depending on @stlite/kernel directly

.changeset/slick-lions-wave.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@stlite/browser": minor
3+
---
4+
5+
Remove `workerType` option from `mount()`

.github/workflows/postbuild.yml

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ jobs:
5555
runs-on: ubuntu-latest
5656
outputs:
5757
browser: ${{ steps.parse-packages.outputs.browser }}
58+
react: ${{ steps.parse-packages.outputs.react }}
5859
desktop: ${{ steps.parse-packages.outputs.desktop }}
5960
steps:
6061
- name: Download published packages info
@@ -72,12 +73,15 @@ jobs:
7273
PACKAGES=$(cat changesets-published-packages)
7374
if [ -z "$PACKAGES" ] || [ "$PACKAGES" = "[]" ]; then
7475
echo "browser=" >> $GITHUB_OUTPUT
76+
echo "react=" >> $GITHUB_OUTPUT
7577
echo "desktop=" >> $GITHUB_OUTPUT
7678
else
7779
BROWSER_VERSION=$(echo "$PACKAGES" | jq -r '.[] | select(.name == "@stlite/browser") | .version // ""')
80+
REACT_VERSION=$(echo "$PACKAGES" | jq -r '.[] | select(.name == "@stlite/react") | .version // ""')
7881
DESKTOP_VERSION=$(echo "$PACKAGES" | jq -r '.[] | select(.name == "@stlite/desktop") | .version // ""')
7982
8083
echo "browser=$BROWSER_VERSION" >> $GITHUB_OUTPUT
84+
echo "react=$REACT_VERSION" >> $GITHUB_OUTPUT
8185
echo "desktop=$DESKTOP_VERSION" >> $GITHUB_OUTPUT
8286
fi
8387
@@ -142,6 +146,7 @@ jobs:
142146
143147
const labels = {
144148
"visualizer-browser": "@stlite/browser",
149+
"visualizer-react": "@stlite/react",
145150
"visualizer-sharing": "@stlite/sharing",
146151
"visualizer-sharing-editor": "@stlite/sharing-editor",
147152
"visualizer-desktop": "@stlite/desktop",
@@ -516,6 +521,95 @@ jobs:
516521
`
517522
});
518523
524+
deploy-react-preview:
525+
needs: [get-build-info]
526+
if: ${{ needs.get-build-info.result == 'success' && ( needs.get-build-info.outputs.pr-number != '' || success() ) }}
527+
runs-on: ubuntu-latest
528+
permissions:
529+
contents: read
530+
deployments: write
531+
name: Deploy @stlite/react to Cloudflare Pages for preview
532+
outputs:
533+
url: ${{ steps.deploy.outputs.deployment-url }}
534+
valid: 'true'
535+
steps:
536+
# Checkout for local actions (`uses ./*`).
537+
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
538+
with:
539+
persist-credentials: false
540+
sparse-checkout: .github
541+
sparse-checkout-cone-mode: false
542+
543+
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
544+
with:
545+
name: stlite-react
546+
path: ${{ runner.temp }}/artifacts/react
547+
run-id: ${{ github.event.workflow_run.id }}
548+
github-token: ${{ secrets.GITHUB_TOKEN }}
549+
550+
- name: Verify artifact contents
551+
uses: ./.github/actions/verify-only-file
552+
with:
553+
directory: ${{ runner.temp }}/artifacts/react
554+
filename: package.tgz
555+
556+
- name: Verify artifact attestation
557+
uses: ./.github/actions/verify-artifact-attestation
558+
with:
559+
filepath: ${{ runner.temp }}/artifacts/react/package.tgz
560+
expected-workflow-file: .github/workflows/test-build.yml
561+
expected-ref: ${{ needs.get-build-info.outputs.pr-number && format('refs/pull/{0}/merge', needs.get-build-info.outputs.pr-number) || format('refs/heads/{0}', needs.get-build-info.outputs.branch) }}
562+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
563+
564+
- run: tar xzvf package.tgz
565+
working-directory: ${{ runner.temp }}/artifacts/react
566+
567+
- name: Deploy
568+
uses: cloudflare/wrangler-action@da0e0dfe58b7a431659754fdf3f186c529afbe65 # v3.14.1
569+
id: deploy
570+
with:
571+
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
572+
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
573+
command: |
574+
pages deploy ${{ runner.temp }}/artifacts/react/package/build --project-name=stlite-react-preview --branch=${{ needs.get-build-info.outputs.branch }} --commit-hash=${{ needs.get-build-info.outputs.trigger-sha }}
575+
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
576+
577+
notify-react-preview-deployments:
578+
needs: [get-build-info, deploy-react-preview]
579+
if: ${{ needs.get-build-info.outputs.pr-number != '' && always() }}
580+
581+
runs-on: ubuntu-latest
582+
permissions:
583+
pull-requests: write
584+
585+
steps:
586+
- name: Comment on PR
587+
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
588+
env:
589+
PR_NUMBER: ${{ needs.get-build-info.outputs.pr-number }}
590+
with:
591+
script: |
592+
const prNumber = process.env.PR_NUMBER;
593+
const previewUrl = '${{ needs.deploy-react-preview.outputs.url }}';
594+
const logUrl = 'https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}';
595+
596+
await github.rest.issues.createComment({
597+
owner: context.repo.owner,
598+
repo: context.repo.repo,
599+
issue_number: prNumber,
600+
body: `Deployment completed successfully ([log](${logUrl})).
601+
602+
Importable URLs:
603+
- \`${previewUrl}/stlite.js\`
604+
- \`${previewUrl}/stlite.css\`
605+
606+
\`\`\`tsx
607+
import { StliteApp, createKernel } from "${previewUrl}/stlite.js";
608+
import "${previewUrl}/stlite.css";
609+
\`\`\`
610+
`
611+
});
612+
519613
deploy-sharing:
520614
needs: get-build-info
521615
if: ${{ needs.get-build-info.outputs.branch }}
@@ -667,6 +761,66 @@ jobs:
667761
generate_release_notes: true
668762
tag_name: "@stlite/browser@${{ needs.get-changesets-publish-targets.outputs.browser }}"
669763

764+
publish-react:
765+
needs: [get-build-info, get-changesets-publish-targets]
766+
if: ${{ needs.get-changesets-publish-targets.outputs.react != '' }}
767+
768+
permissions:
769+
contents: write # Necessary for creating releases: https://github.com/softprops/action-gh-release#permissions
770+
id-token: write # Necessary for NPM trusted publishing: https://docs.npmjs.com/trusted-publishers#step-2-configure-your-cicd-workflow
771+
attestations: read # Necessary for verifying artifact attestations
772+
773+
runs-on: ubuntu-latest
774+
775+
steps:
776+
# Checkout for local actions (`uses ./*`).
777+
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
778+
with:
779+
persist-credentials: false
780+
sparse-checkout: .github
781+
sparse-checkout-cone-mode: false
782+
783+
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
784+
with:
785+
node-version: 22
786+
registry-url: 'https://registry.npmjs.org'
787+
scope: '@stlite'
788+
789+
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
790+
with:
791+
name: stlite-react
792+
path: ${{ runner.temp }}/stlite-react
793+
run-id: ${{ github.event.workflow_run.id }}
794+
github-token: ${{ secrets.GITHUB_TOKEN }}
795+
796+
- name: Verify artifact contents
797+
uses: ./.github/actions/verify-only-file
798+
with:
799+
directory: ${{ runner.temp }}/stlite-react
800+
filename: package.tgz
801+
802+
- name: Verify artifact attestation
803+
uses: ./.github/actions/verify-artifact-attestation
804+
with:
805+
filepath: ${{ runner.temp }}/stlite-react/package.tgz
806+
expected-workflow-file: .github/workflows/test-build.yml
807+
expected-ref: refs/heads/main
808+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
809+
810+
# Ensure npm 11.5.1 or later is installed
811+
- name: Update npm
812+
run: npm install -g npm@latest
813+
814+
- name: Publish validated package
815+
run: npm publish ${{ runner.temp }}/stlite-react/package.tgz --access public
816+
817+
- name: Create a new release
818+
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
819+
with:
820+
files: ${{ runner.temp }}/stlite-react/package.tgz
821+
generate_release_notes: true
822+
tag_name: "@stlite/react@${{ needs.get-changesets-publish-targets.outputs.react }}"
823+
670824
publish-desktop:
671825
needs: [get-build-info, get-changesets-publish-targets]
672826
if: ${{ needs.get-changesets-publish-targets.outputs.desktop != '' }}

.github/workflows/test-build.yml

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ jobs:
119119
kernel: ${{ steps.filter.outputs.kernel == 'true' || steps.filter.outputs.gha == 'true' || env.RUN_ALL_TESTS == 'true' }}
120120
# stlite-lib: ${{ steps.filter.outputs.stlite-lib == 'true' || steps.filter.outputs.gha == 'true' || env.RUN_ALL_TESTS == 'true' }}
121121
stlite-lib: 'true' # This step does not detect changes in the `streamlit` submodule that is needed to trigger the test-stlite-lib job (https://github.com/dorny/paths-filter/issues/143), so skip checking and make it always return true as a workaround.
122+
react: ${{ steps.filter.outputs.react == 'true' || steps.filter.outputs.gha == 'true' || env.RUN_ALL_TESTS == 'true' }}
122123
browser: ${{ steps.filter.outputs.browser == 'true' || steps.filter.outputs.gha == 'true' || env.RUN_ALL_TESTS == 'true' }}
123124
sharing: ${{ steps.filter.outputs.sharing == 'true' || steps.filter.outputs.gha == 'true' || env.RUN_ALL_TESTS == 'true' }}
124125
sharing-editor: ${{ steps.filter.outputs.sharing-editor == 'true' || steps.filter.outputs.gha == 'true' || env.RUN_ALL_TESTS == 'true' }}
@@ -143,6 +144,8 @@ jobs:
143144
# stlite-lib: # We run this job anytime. See above.
144145
# - 'packages/kernel/py/stlite-lib/**/*'
145146
# - 'streamlit/**/*'
147+
react:
148+
- 'packages/react/**/*'
146149
browser:
147150
- 'packages/browser/**/*'
148151
sharing:
@@ -284,6 +287,32 @@ jobs:
284287
yarn check:prettier
285288
- run: yarn test
286289

290+
test-react:
291+
needs: changes
292+
if: ${{ needs.changes.outputs.react == 'true' }}
293+
294+
runs-on: ubuntu-latest
295+
296+
defaults:
297+
run:
298+
working-directory: packages/react
299+
300+
steps:
301+
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
302+
with:
303+
submodules: true
304+
persist-credentials: false
305+
- uses: ./.github/actions/init-all
306+
with:
307+
python-version-file: ${{ env.python-version-file }}
308+
node-version-file: ${{ env.node-version-file }}
309+
310+
- name: Lint
311+
run: |
312+
yarn check:eslint
313+
yarn check:prettier
314+
- run: yarn test
315+
287316
test-sharing:
288317
needs: changes
289318
if: ${{ needs.changes.outputs.sharing == 'true' }}
@@ -486,6 +515,56 @@ jobs:
486515
name: "streamlit wheel (built as a part of @stlite/browser)"
487516
input-path: ${{ steps.get-wheel-file-path.outputs.STREAMLIT_WHEEL_FILEPATH }}
488517

518+
build-react:
519+
if: ${{ ! failure() }} # This job should run even if the depending jobs are skipped, but not when those jobs failed.
520+
needs: [set-build-info, test-kernel, test-stlite-lib, test-build-common, test-react]
521+
522+
runs-on: ubuntu-latest
523+
524+
permissions:
525+
pull-requests: write
526+
id-token: write
527+
attestations: write
528+
529+
steps:
530+
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
531+
with:
532+
submodules: true
533+
persist-credentials: false
534+
- uses: ./.github/actions/init-all
535+
with:
536+
python-version-file: ${{ env.python-version-file }}
537+
node-version-file: ${{ env.node-version-file }}
538+
539+
- name: Build @stlite/react
540+
run: |
541+
. .venv/bin/activate
542+
make react
543+
544+
- name: Package
545+
working-directory: packages/react
546+
run: yarn pack
547+
548+
- name: Upload the built tar ball as an artifact
549+
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
550+
with:
551+
path: packages/react/package.tgz
552+
name: stlite-react
553+
554+
- name: Generate artifact attestation
555+
uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0
556+
with:
557+
subject-path: packages/react/package.tgz
558+
continue-on-error: true
559+
560+
- name: "Inform the package stats of @stlite/react"
561+
uses: ./.github/actions/set-package-stats
562+
continue-on-error: true
563+
with:
564+
key: react
565+
name: "@stlite/react"
566+
input-path: packages/react/package.tgz
567+
489568
build-sharing:
490569
if: ${{ ! failure() }} # This job should run even if the depending jobs are skipped, but not when those jobs failed: https://qiita.com/abetomo/items/d9ede7dbeeb24f723fc5#%E8%A8%AD%E5%AE%9A%E4%BE%8B4
491570
needs: [set-build-info, test-kernel, test-stlite-lib, test-sharing-common, test-sharing]

AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Project Structure & Module Organization
44

5-
- `packages/` hosts the Yarn workspaces: `browser`, `sharing`, and `desktop` are user apps; `kernel` is the Pyodide core; `sharing-editor` is the editor client for `sharing`, and the rest (`common`, `common-react`, devutils) are support utilities.
5+
- `packages/` hosts the Yarn workspaces: `browser`, `sharing`, and `desktop` are user apps; `react` is a React library that the apps depend on; `kernel` is the Pyodide core that `react` depends on; `sharing-editor` is the editor client for `sharing`, and the rest (`common`, `sharing-common`, `devutils`) are support utilities.
66
- `streamlit/` mirrors upstream Streamlit; `streamlit/frontend/app` is the upstream UI we reference (not build) when customizing `browser`, `sharing`, and `desktop`, while other `streamlit/frontend/*` packages (`lib`, `connection`, etc.) are consumed directly by our workspaces.
77
- Supporting assets sit in `assets/`; Makefile orchestrates builds, and browser E2E specs live in `packages/browser/e2e-tests`.
88

Makefile

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ STREAMLIT_COMPILED_WHEEL_FILE_NAME := $(shell yarn workspace @stlite/devutils ge
4343
node_modules := $(BUILD_STATE_DIR)/node_modules/.built
4444
venv := $(BUILD_STATE_DIR)/venv/.built
4545
common := $(BUILD_STATE_DIR)/common/.built
46-
common-react := $(BUILD_STATE_DIR)/common-react/.built
46+
react := $(BUILD_STATE_DIR)/react/.built
4747
browser := $(BUILD_STATE_DIR)/browser/.built
4848
sharing := $(BUILD_STATE_DIR)/sharing/.built
4949
sharing-common := $(BUILD_STATE_DIR)/sharing-common/.built
@@ -117,13 +117,14 @@ $(common): $(shell \
117117
@mkdir -p $(dir $@)
118118
@touch $@
119119

120-
.PHONY: common-react
121-
common-react: $(common-react)
122-
$(common-react): $(shell \
123-
find packages/common-react/src -type f \( -name "*.ts" -o -name "*.tsx" \); \
124-
find packages/common-react -maxdepth 1 -type f \( -name "package.json" -o -name "tsconfig*.json" \); \
125-
) $(node_modules) $(kernel) $(streamlit-frontend-lib)
126-
cd packages/common-react && yarn build
120+
.PHONY: react
121+
react: $(react)
122+
$(react): $(shell \
123+
find packages/react/src -type f \( -name "*.ts" -o -name "*.tsx" \); \
124+
find packages/react/vite-plugin/src -type f -name "*.ts"; \
125+
find packages/react -maxdepth 1 -type f \( -name "package.json" -o -name "tsconfig*.json" -o -name "vite.config.ts" \); \
126+
) $(node_modules) $(kernel) $(common) $(streamlit-frontend-lib)
127+
cd packages/react && yarn build
127128
@mkdir -p $(dir $@)
128129
@touch $@
129130

@@ -132,7 +133,7 @@ browser: $(browser)
132133
$(browser): $(shell \
133134
find packages/browser/src -type f \( -name "*.ts" -o -name "*.tsx" \); \
134135
find packages/browser -maxdepth 1 -type f \( -name "package.json" -o -name "tsconfig*.json" -o -name "vite.config.ts" \); \
135-
) $(node_modules) $(kernel) $(common) $(common-react) $(streamlit-frontend-lib)
136+
) $(node_modules) $(common) $(react)
136137
cd packages/browser && yarn build
137138
@mkdir -p $(dir $@)
138139
@touch $@
@@ -143,7 +144,7 @@ $(sharing): $(shell \
143144
find packages/sharing/src -type f \( -name "*.ts" -o -name "*.tsx" \); \
144145
find packages/sharing/public -type f; \
145146
find packages/sharing -maxdepth 1 -type f \( -name "package.json" -o -name "tsconfig*.json" -o -name "vite.config.ts" \); \
146-
) $(node_modules) $(kernel) $(sharing-common) $(common-react) $(streamlit-frontend-lib)
147+
) $(node_modules) $(sharing-common) $(react)
147148
cd packages/sharing && yarn build
148149
@mkdir -p $(dir $@)
149150
@touch $@
@@ -174,7 +175,7 @@ $(desktop): $(shell \
174175
find packages/desktop/src -type f \( -name "*.ts" -o -name "*.tsx" \); \
175176
find packages/desktop/electron -type f -name "*.ts"; \
176177
find packages/desktop -maxdepth 1 -type f \( -name "package.json" -o -name "tsconfig*.json" -o -name "vite.config.ts" \); \
177-
) $(node_modules) $(kernel) $(common) $(common-react) $(streamlit-frontend-lib)
178+
) $(node_modules) $(common) $(react)
178179
cd packages/desktop && yarn build
179180
@mkdir -p $(dir $@)
180181
@touch $@

0 commit comments

Comments
 (0)