From 1b1429b615fc58410901e97a5e7b7471d474387e Mon Sep 17 00:00:00 2001 From: Shai Reznik Date: Fri, 7 Jun 2024 03:18:11 +0300 Subject: [PATCH 01/28] ci: added ability to publish test packages (#6389) * ci: added ability to publish test packages --- .github/workflows/ci.yml | 56 +++++++++++++++++++++++----------------- pnpm-lock.yaml | 27 ------------------- 2 files changed, 33 insertions(+), 50 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3a15b50d7a24..dd81fcb801c8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,6 +11,11 @@ on: - 'build/**' workflow_dispatch: inputs: + node_version: + description: 'Node version to use for the build' + required: false + type: string + default: '20.x' disttag: description: 'Publish "@builder.io/qwik" to NPM using this dist-tag, push the git-tag to the repo and create a GitHub release. The "latest" and "next" dist-tags will use the version number already committed in package.json.' required: true @@ -97,12 +102,12 @@ jobs: - name: Checkout uses: actions/checkout@v4.1.1 - - uses: pnpm/action-setup@v2.2.4 + - uses: pnpm/action-setup@v4 - name: Setup Node uses: actions/setup-node@v4.0.2 with: - node-version: 18.x + node-version: 20.x cache: 'pnpm' registry-url: https://registry.npmjs.org/ @@ -115,7 +120,7 @@ jobs: pnpm install --frozen-lockfile - name: Build Packages - run: pnpm tsm scripts/index.ts --tsc --build --cli --api --qwiklabs --eslint --platform-binding-wasm-copy --set-dist-tag="${{ github.event.inputs.disttag }}" + run: pnpm tsm scripts/index.ts --tsc --build --cli --api --qwiklabs --qwikcity --eslint --platform-binding-wasm-copy --set-dist-tag="${{ github.event.inputs.disttag }}" - name: Print Qwik Dist Build run: tree packages/qwik/dist/ @@ -150,7 +155,12 @@ jobs: path: packages/eslint-plugin-qwik/dist/ if-no-files-found: error - ############ BUILD WASM ############ + - name: Publish packages for testing + run: pnpm dlx pkg-pr-new@0.0.8 publish --compact --pnpm ./packages/qwik/dist ./packages/qwik-city/lib ./packages/eslint-plugin-qwik/dist ./packages/create-qwik/dist + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + ############ BUILD WASM ############# build-wasm: name: Build WASM runs-on: ubuntu-latest @@ -165,14 +175,14 @@ jobs: if: ${{ needs.changes.outputs.fullbuild == 'true' }} uses: actions/checkout@v4.1.1 - - uses: pnpm/action-setup@v2.2.4 + - uses: pnpm/action-setup@v4 if: ${{ needs.changes.outputs.fullbuild == 'true' }} - name: Setup Node if: ${{ needs.changes.outputs.fullbuild == 'true' }} uses: actions/setup-node@v4.0.2 with: - node-version: 18.x + node-version: 20.x cache: 'pnpm' registry-url: https://registry.npmjs.org/ @@ -258,14 +268,14 @@ jobs: if: ${{ needs.changes.outputs.fullbuild == 'true' }} uses: actions/checkout@v4.1.1 - - uses: pnpm/action-setup@v2.2.4 + - uses: pnpm/action-setup@v4 if: ${{ needs.changes.outputs.fullbuild == 'true' }} - name: Setup Node if: ${{ needs.changes.outputs.fullbuild == 'true' }} uses: actions/setup-node@v4.0.2 with: - node-version: 18.x + node-version: 20.x cache: 'pnpm' registry-url: https://registry.npmjs.org/ @@ -325,14 +335,14 @@ jobs: if: ${{ needs.changes.outputs.insightsbuild == 'true' }} uses: actions/checkout@v4.1.1 - - uses: pnpm/action-setup@v2.2.4 + - uses: pnpm/action-setup@v4 if: ${{ needs.changes.outputs.insightsbuild == 'true' }} - name: Setup Node if: ${{ needs.changes.outputs.insightsbuild == 'true' }} uses: actions/setup-node@v4.0.2 with: - node-version: 18.x + node-version: 20.x cache: 'pnpm' registry-url: https://registry.npmjs.org/ @@ -358,12 +368,12 @@ jobs: - name: Checkout uses: actions/checkout@v4.1.1 - - uses: pnpm/action-setup@v2.2.4 + - uses: pnpm/action-setup@v4 - name: Setup Node uses: actions/setup-node@v4.0.2 with: - node-version: 18.x + node-version: 20.x cache: 'pnpm' registry-url: https://registry.npmjs.org/ @@ -402,14 +412,14 @@ jobs: if: ${{ needs.changes.outputs.fullbuild == 'true' }} uses: actions/checkout@v4.1.1 - - uses: pnpm/action-setup@v2.2.4 + - uses: pnpm/action-setup@v4 if: ${{ needs.changes.outputs.fullbuild == 'true' }} - name: Setup Node if: ${{ needs.changes.outputs.fullbuild == 'true' }} uses: actions/setup-node@v4.0.2 with: - node-version: 18.x + node-version: 20.x cache: 'pnpm' registry-url: https://registry.npmjs.org/ @@ -501,12 +511,12 @@ jobs: - name: Checkout uses: actions/checkout@v4.1.1 - - uses: pnpm/action-setup@v2.2.4 + - uses: pnpm/action-setup@v4 - name: Setup Node uses: actions/setup-node@v4.0.2 with: - node-version: 18.x + node-version: 20.x cache: 'pnpm' registry-url: https://registry.npmjs.org/ @@ -572,10 +582,10 @@ jobs: settings: - host: ubuntu-latest browser: chromium - node: 18.x + node: 20.x - host: macos-latest browser: webkit - node: 18.x + node: 20.x runs-on: ${{ matrix.settings.host }} @@ -584,7 +594,7 @@ jobs: if: ${{ needs.changes.outputs.fullbuild == 'true' }} uses: actions/checkout@v4.1.1 - - uses: pnpm/action-setup@v2.2.4 + - uses: pnpm/action-setup@v4 if: ${{ needs.changes.outputs.fullbuild == 'true' }} - name: Setup Node ${{ matrix.settings.node }} @@ -645,12 +655,12 @@ jobs: - name: Checkout uses: actions/checkout@v4.1.1 - - uses: pnpm/action-setup@v2.2.4 + - uses: pnpm/action-setup@v4 - name: Setup Node uses: actions/setup-node@v4.0.2 with: - node-version: 18.x + node-version: 20.x cache: 'pnpm' registry-url: https://registry.npmjs.org/ @@ -741,12 +751,12 @@ jobs: - name: Checkout uses: actions/checkout@v4.1.1 - - uses: pnpm/action-setup@v2.2.4 + - uses: pnpm/action-setup@v4 - name: Setup Node uses: actions/setup-node@v4.0.2 with: - node-version: 18.x + node-version: 20.x cache: 'pnpm' registry-url: https://registry.npmjs.org/ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d1f93125cb1a..3a99f5d534a2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1905,84 +1905,72 @@ packages: engines: {glibc: '>=2.26', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [arm64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-arm@1.0.1': resolution: {integrity: sha512-FtdMvR4R99FTsD53IA3LxYGghQ82t3yt0ZQ93WMZ2xV3dqrb0E8zq4VHaTOuLEAuA83oDawHV3fd+BsAPadHIQ==} engines: {glibc: '>=2.28', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [arm] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-s390x@1.0.1': resolution: {integrity: sha512-3+rzfAR1YpMOeA2zZNp+aYEzGNWK4zF3+sdMxuCS3ey9HhDbJ66w6hDSHDMoap32DueFwhhs3vwooAB2MaK4XQ==} engines: {glibc: '>=2.28', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [s390x] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-x64@1.0.1': resolution: {integrity: sha512-3NR1mxFsaSgMMzz1bAnnKbSAI+lHXVTqAHgc1bgzjHuXjo4hlscpUxc0vFSAPKI3yuzdzcZOkq7nDPrP2F8Jgw==} engines: {glibc: '>=2.26', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [x64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.0.1': resolution: {integrity: sha512-5aBRcjHDG/T6jwC3Edl3lP8nl9U2Yo8+oTl5drd1dh9Z1EBfzUKAJFUDTDisDjUwc7N4AjnPGfCA3jl3hY8uDg==} engines: {musl: '>=1.2.2', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [arm64] os: [linux] - libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.0.1': resolution: {integrity: sha512-dcT7inI9DBFK6ovfeWRe3hG30h51cBAP5JXlZfx6pzc/Mnf9HFCQDLtYf4MCBjxaaTfjCCjkBxcy3XzOAo5txw==} engines: {musl: '>=1.2.2', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [x64] os: [linux] - libc: [musl] '@img/sharp-linux-arm64@0.33.2': resolution: {integrity: sha512-pz0NNo882vVfqJ0yNInuG9YH71smP4gRSdeL09ukC2YLE6ZyZePAlWKEHgAzJGTiOh8Qkaov6mMIMlEhmLdKew==} engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [arm64] os: [linux] - libc: [glibc] '@img/sharp-linux-arm@0.33.2': resolution: {integrity: sha512-Fndk/4Zq3vAc4G/qyfXASbS3HBZbKrlnKZLEJzPLrXoJuipFNNwTes71+Ki1hwYW5lch26niRYoZFAtZVf3EGA==} engines: {glibc: '>=2.28', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [arm] os: [linux] - libc: [glibc] '@img/sharp-linux-s390x@0.33.2': resolution: {integrity: sha512-MBoInDXDppMfhSzbMmOQtGfloVAflS2rP1qPcUIiITMi36Mm5YR7r0ASND99razjQUpHTzjrU1flO76hKvP5RA==} engines: {glibc: '>=2.28', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [s390x] os: [linux] - libc: [glibc] '@img/sharp-linux-x64@0.33.2': resolution: {integrity: sha512-xUT82H5IbXewKkeF5aiooajoO1tQV4PnKfS/OZtb5DDdxS/FCI/uXTVZ35GQ97RZXsycojz/AJ0asoz6p2/H/A==} engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [x64] os: [linux] - libc: [glibc] '@img/sharp-linuxmusl-arm64@0.33.2': resolution: {integrity: sha512-F+0z8JCu/UnMzg8IYW1TMeiViIWBVg7IWP6nE0p5S5EPQxlLd76c8jYemG21X99UzFwgkRo5yz2DS+zbrnxZeA==} engines: {musl: '>=1.2.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [arm64] os: [linux] - libc: [musl] '@img/sharp-linuxmusl-x64@0.33.2': resolution: {integrity: sha512-+ZLE3SQmSL+Fn1gmSaM8uFusW5Y3J9VOf+wMGNnTtJUMUxFhv+P4UPaYEYT8tqnyYVaOVGgMN/zsOxn9pSsO2A==} engines: {musl: '>=1.2.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [x64] os: [linux] - libc: [musl] '@img/sharp-wasm32@0.33.2': resolution: {integrity: sha512-fLbTaESVKuQcpm8ffgBD7jLb/CQLcATju/jxtTXR1XCLwbOQt+OL5zPHSDMmp2JZIeq82e18yE0Vv7zh6+6BfQ==} @@ -2660,35 +2648,30 @@ packages: engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] - libc: [glibc] '@parcel/watcher-linux-arm64-glibc@2.4.1': resolution: {integrity: sha512-BJ7mH985OADVLpbrzCLgrJ3TOpiZggE9FMblfO65PlOCdG++xJpKUJ0Aol74ZUIYfb8WsRlUdgrZxKkz3zXWYA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] - libc: [glibc] '@parcel/watcher-linux-arm64-musl@2.4.1': resolution: {integrity: sha512-p4Xb7JGq3MLgAfYhslU2SjoV9G0kI0Xry0kuxeG/41UfpjHGOhv7UoUDAz/jb1u2elbhazy4rRBL8PegPJFBhA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] - libc: [musl] '@parcel/watcher-linux-x64-glibc@2.4.1': resolution: {integrity: sha512-s9O3fByZ/2pyYDPoLM6zt92yu6P4E39a03zvO0qCHOTjxmt3GHRMLuRZEWhWLASTMSrrnVNWdVI/+pUElJBBBg==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] - libc: [glibc] '@parcel/watcher-linux-x64-musl@2.4.1': resolution: {integrity: sha512-L2nZTYR1myLNST0O632g0Dx9LyMNHrn6TOt76sYxWLdff3cB22/GZX2UPtJnaqQPdCRoszoY5rcOj4oMTtp5fQ==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] - libc: [musl] '@parcel/watcher-wasm@2.4.0': resolution: {integrity: sha512-MNgQ4WCbBybqQ97KwR/hqJGYTg3+s8qHpgIyFWB2qJOBvoJWbXuJGmm4ZkPLq2bMaANqCZqrXwmKYagZTkMKZA==} @@ -2787,55 +2770,46 @@ packages: resolution: {integrity: sha512-3reX2fUHqN7sffBNqmEyMQVj/CKhIHZd4y631duy0hZqI8Qoqf6lTtmAKvJFYa6bhU95B1D0WgzHkmTg33In0A==} cpu: [arm] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.17.2': resolution: {integrity: sha512-uSqpsp91mheRgw96xtyAGP9FW5ChctTFEoXP0r5FAzj/3ZRv3Uxjtc7taRQSaQM/q85KEKjKsZuiZM3GyUivRg==} cpu: [arm] os: [linux] - libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.17.2': resolution: {integrity: sha512-EMMPHkiCRtE8Wdk3Qhtciq6BndLtstqZIroHiiGzB3C5LDJmIZcSzVtLRbwuXuUft1Cnv+9fxuDtDxz3k3EW2A==} cpu: [arm64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.17.2': resolution: {integrity: sha512-NMPylUUZ1i0z/xJUIx6VUhISZDRT+uTWpBcjdv0/zkp7b/bQDF+NfnfdzuTiB1G6HTodgoFa93hp0O1xl+/UbA==} cpu: [arm64] os: [linux] - libc: [musl] '@rollup/rollup-linux-powerpc64le-gnu@4.17.2': resolution: {integrity: sha512-T19My13y8uYXPw/L/k0JYaX1fJKFT/PWdXiHr8mTbXWxjVF1t+8Xl31DgBBvEKclw+1b00Chg0hxE2O7bTG7GQ==} cpu: [ppc64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.17.2': resolution: {integrity: sha512-BOaNfthf3X3fOWAB+IJ9kxTgPmMqPPH5f5k2DcCsRrBIbWnaJCgX2ll77dV1TdSy9SaXTR5iDXRL8n7AnoP5cg==} cpu: [riscv64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-s390x-gnu@4.17.2': resolution: {integrity: sha512-W0UP/x7bnn3xN2eYMql2T/+wpASLE5SjObXILTMPUBDB/Fg/FxC+gX4nvCfPBCbNhz51C+HcqQp2qQ4u25ok6g==} cpu: [s390x] os: [linux] - libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.17.2': resolution: {integrity: sha512-Hy7pLwByUOuyaFC6mAr7m+oMC+V7qyifzs/nW2OJfC8H4hbCzOX07Ov0VFk/zP3kBsELWNFi7rJtgbKYsav9QQ==} cpu: [x64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-x64-musl@4.17.2': resolution: {integrity: sha512-h1+yTWeYbRdAyJ/jMiVw0l6fOOm/0D1vNLui9iPuqgRGnXA0u21gAqOyB5iHjlM9MMfNOm9RHCQ7zLIzT0x11Q==} cpu: [x64] os: [linux] - libc: [musl] '@rollup/rollup-win32-arm64-msvc@4.17.2': resolution: {integrity: sha512-tmdtXMfKAjy5+IQsVtDiCfqbynAQE/TQRpWdVataHmhMb9DCoJxp9vLcCBjEQWMiUYxO1QprH/HbY9ragCEFLA==} @@ -6503,7 +6477,6 @@ packages: libsql@0.3.18: resolution: {integrity: sha512-lvhKr7WV3NLWRbXkjn/MeKqXOAqWKU0PX9QYrvDh7fneukapj+iUQ4qgJASrQyxcCrEsClXCQiiK5W6OoYPAlA==} - cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] light-my-request@5.11.1: From c89a8f61a0259e978d1d951c0932db51db1aea22 Mon Sep 17 00:00:00 2001 From: thejackshelton-kunaico <167572331+thejackshelton-kunaico@users.noreply.github.com> Date: Fri, 7 Jun 2024 19:05:35 -0500 Subject: [PATCH 02/28] docs: improved clarity in tutorial (#6463) * docs: improved clarity in tutorial * ci: removed codeql workflow --------- Co-authored-by: Shai Reznik --- .github/workflows/codeql-analysis.yml | 70 ------------------- .../docs/(qwik)/getting-started/index.mdx | 2 +- 2 files changed, 1 insertion(+), 71 deletions(-) delete mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index fdd85228aec9..000000000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,70 +0,0 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# -name: 'CodeQL' - -on: - push: - branches: [main] - pull_request: - # The branches below must be a subset of the branches above - branches: [main] - schedule: - - cron: '35 23 * * 4' - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: ['typescript'] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] - # Learn more about CodeQL language support at https://git.io/codeql-language-support - - steps: - - name: Checkout repository - uses: actions/checkout@v4.1.1 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v2 - - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 diff --git a/packages/docs/src/routes/docs/(qwik)/getting-started/index.mdx b/packages/docs/src/routes/docs/(qwik)/getting-started/index.mdx index d4ec2fdc3aeb..4fe002617ad4 100644 --- a/packages/docs/src/routes/docs/(qwik)/getting-started/index.mdx +++ b/packages/docs/src/routes/docs/(qwik)/getting-started/index.mdx @@ -112,7 +112,7 @@ export default component$(() => { ### 2. Loading Data -We will use the external JSON API at https://icanhazdadjoke.com to load random jokes. We will use [route loaders](/docs/route-loader/) to load this data into the server and render it in the component. +Use the external JSON API at https://icanhazdadjoke.com to load random jokes. You can use [route loaders](/docs/route-loader/) to load this data into the server and render it in the component. 1. Open `src/routes/joke/index.tsx` and add this code: From 133ff1b880ee839d510c4f2f2125937bebf42106 Mon Sep 17 00:00:00 2001 From: Cody Roberts Date: Fri, 7 Jun 2024 19:38:29 -0500 Subject: [PATCH 03/28] docs(props): Immutability & Signals explanation and example. (#6460) * Added Immutability and Signals to the explanation and example. The props section now clarifies that props are immutable and cannot be changed, and recommends readers to use signals in situations where the props need to be updated. The example now shows two separate ways to use signals for props. * Added reference props demo Demo for the reference props example in the props section of the component documentation. * Added primitive props demo Added a demo for the primitive props example in the props section of the component documentation. * Made the details properties optional Made the properties on the details object in the example optional to match the primitive props example. * Rewrote the props section Rewrote the props section to clarify shallow immutability, and to give examples of both primitive and reference data types being sent as props with explanations of the difference in immutability. * Linted codebase * Changed to match corresponding example. Considered making the examples use different items, but decided to keep them the same so that changes in code functionality are more clear. Changed data back to match examples in the documentation. --------- Co-authored-by: Shai Reznik --- .../demo/component/primitive-props/index.tsx | 33 +++++++++ .../demo/component/reference-props/index.tsx | 31 +++++++++ .../docs/(qwik)/components/overview/index.mdx | 67 ++++++++++++++++--- 3 files changed, 123 insertions(+), 8 deletions(-) create mode 100644 packages/docs/src/routes/demo/component/primitive-props/index.tsx create mode 100644 packages/docs/src/routes/demo/component/reference-props/index.tsx diff --git a/packages/docs/src/routes/demo/component/primitive-props/index.tsx b/packages/docs/src/routes/demo/component/primitive-props/index.tsx new file mode 100644 index 000000000000..67dc562f34ee --- /dev/null +++ b/packages/docs/src/routes/demo/component/primitive-props/index.tsx @@ -0,0 +1,33 @@ +import { component$, useSignal } from '@builder.io/qwik'; +import type { Signal } from '@builder.io/qwik'; + +interface ItemProps { + name?: string; + quantity?: number; + description?: string; + price?: Signal; +} + +export const Item = component$((props) => { + const localQuantity = useSignal(props.quantity); + + return ( +
    +
  • name: {props.name}
  • +
  • quantity: {localQuantity}
  • +
  • description: {props.description}
  • +
  • price: {props.price}
  • +
+ ); +}); + +export default component$(() => { + const price = useSignal(9.99); + + return ( + <> +

Props

+ + + ); +}); diff --git a/packages/docs/src/routes/demo/component/reference-props/index.tsx b/packages/docs/src/routes/demo/component/reference-props/index.tsx new file mode 100644 index 000000000000..d72716f6858d --- /dev/null +++ b/packages/docs/src/routes/demo/component/reference-props/index.tsx @@ -0,0 +1,31 @@ +import { component$ } from '@builder.io/qwik'; + +interface ItemProps { + details: { + name?: string; + quantity?: number; + description?: string; + price?: number; + }; +} + +export const Item = component$((props: ItemProps) => { + props.details.price = 4.99; + + return ( +
    +
  • name: {props.details.name}
  • +
  • quantity: {props.details.quantity}
  • +
  • description: {props.details.description}
  • +
  • price: {props.details.price}
  • +
+ ); +}); + +export default component$(() => { + return ( + + ); +}); diff --git a/packages/docs/src/routes/docs/(qwik)/components/overview/index.mdx b/packages/docs/src/routes/docs/(qwik)/components/overview/index.mdx index 7df5961c205f..ea18ee4e1e36 100644 --- a/packages/docs/src/routes/docs/(qwik)/components/overview/index.mdx +++ b/packages/docs/src/routes/docs/(qwik)/components/overview/index.mdx @@ -113,26 +113,35 @@ export default component$(() => { ## Props -Props are used to pass data from the parent into the component. Props are accessible via the `props` argument to the component$ function. +Props are used to pass data from the parent into the component. Data passed via props is accessible via the `props` argument to the `component$` function. -In this example a component `Item` declares optional `name`, `quantity`, `description`, and `price`. +Props are shallowly immutable, meaning primitive data types (strings, numbers, booleans) cannot be changed once passed. However, internal elements of reference types (objects, arrays, functions) can be changed despite the reference itself being immutable. - +To change primitive props data in the parent component from the child component, use signals. When updating data locally within the child component a signal is not necessary, destructure the props and use the values to define new local variables. + +The two examples below show a component `Item` that declares optional `name`, `quantity`, `description`, and `price` props. + +In the first example primitive data types are passed via props. The `price` prop is passed as a signal and can be changed from the parent component. `quantity` is passed as a number value that is used to define a new signal in `Item` that can be reactively updated locally. Alternatively, if quantity did not need to be reactive it could be defined as a normal variable instead of a signal. + + ```tsx {3-8, 27} /ItemProps/ -import { component$ } from '@builder.io/qwik'; +import { component$, useSignal } from "@builder.io/qwik"; +import type { Signal } from "@builder.io/qwik"; interface ItemProps { name?: string; quantity?: number; description?: string; - price?: number; + price?: Signal; } export const Item = component$((props) => { + const localQuantity = useSignal(props.quantity); + return (
  • name: {props.name}
  • -
  • quantity: {props.quantity}
  • +
  • quantity: {localQuantity}
  • description: {props.description}
  • price: {props.price}
@@ -140,17 +149,59 @@ export const Item = component$((props) => { }); export default component$(() => { + const price = useSignal(9.99); + return ( <>

Props

- + ); }); + +``` +
+ +In this second example the props are passed as a single `details` object containing the data, instead of individual primitive values. This allows the data inside to be mutated without the use of signals, however the `details` object storing the data is still immutable and cannot be changed once passed. + + +```tsx {3-8, 27} /ItemProps/ +import { component$ } from "@builder.io/qwik"; + +interface ItemProps { + details: { + name?: string; + quantity?: number; + description?: string; + price?: number; + }; +} + +export const Item = component$((props: ItemProps) => { + props.details.price = 4.99; + + return ( +
    +
  • name: {props.details.name}
  • +
  • quantity: {props.details.quantity}
  • +
  • description: {props.details.description}
  • +
  • price: {props.details.price}
  • +
+ ); +}); + +export default component$(() => { + return ( + + ); +}); + ```
-> In the example above we are using `component$` to provide an explicit type for the props. This is optional but it allows the TypeScript compiler to check that the props are used correctly. +> In the examples above we are using `component$` to provide an explicit type for the props. This is optional but it allows the TypeScript compiler to check that the props are used correctly. ### Default props From 82ae67e7532dcf1b92e486405b6f1e8b4a3f9079 Mon Sep 17 00:00:00 2001 From: Nick K Date: Sat, 8 Jun 2024 03:38:50 +0300 Subject: [PATCH 04/28] fix(TextEncoderStream): emoji encoding polyfill and add tests (#6466) Co-authored-by: octet-stream --- .../middleware/cloudflare-pages/index.ts | 4 +- .../middleware/request-handler/api.md | 11 ----- .../middleware/request-handler/index.ts | 2 +- .../middleware/request-handler/polyfill.ts | 47 +++---------------- .../request-handler/polyfill.unit.ts | 19 ++++++++ 5 files changed, 29 insertions(+), 54 deletions(-) diff --git a/packages/qwik-city/middleware/cloudflare-pages/index.ts b/packages/qwik-city/middleware/cloudflare-pages/index.ts index eee224c1e9b3..59205d3d1db1 100644 --- a/packages/qwik-city/middleware/cloudflare-pages/index.ts +++ b/packages/qwik-city/middleware/cloudflare-pages/index.ts @@ -5,7 +5,7 @@ import type { import { mergeHeadersCookies, requestHandler, - _TextEncoderStream_polyfill2, + _TextEncoderStream_polyfill, } from '@builder.io/qwik-city/middleware/request-handler'; import { getNotFound } from '@qwik-city-not-found-paths'; import { isStaticPath } from '@qwik-city-static-paths'; @@ -22,7 +22,7 @@ export function createQwikCity(opts: QwikCityCloudflarePagesOptions) { new globalThis.TextEncoderStream(); } catch (e) { // @ts-ignore - globalThis.TextEncoderStream = _TextEncoderStream_polyfill2; + globalThis.TextEncoderStream = _TextEncoderStream_polyfill; } const qwikSerializer = { _deserializeData, diff --git a/packages/qwik-city/middleware/request-handler/api.md b/packages/qwik-city/middleware/request-handler/api.md index e130f662b746..91fb8b63b50c 100644 --- a/packages/qwik-city/middleware/request-handler/api.md +++ b/packages/qwik-city/middleware/request-handler/api.md @@ -233,17 +233,6 @@ export class _TextEncoderStream_polyfill { get writable(): WritableStream; } -// @internal (undocumented) -export class _TextEncoderStream_polyfill2 { - constructor(); - // (undocumented) - readable: any; - // (undocumented) - writable: any; - // (undocumented) - _writer: any; -} - // (No @packageDocumentation comment for this package) ``` diff --git a/packages/qwik-city/middleware/request-handler/index.ts b/packages/qwik-city/middleware/request-handler/index.ts index 347901517838..a5d10b3195a6 100644 --- a/packages/qwik-city/middleware/request-handler/index.ts +++ b/packages/qwik-city/middleware/request-handler/index.ts @@ -2,7 +2,7 @@ export { getErrorHtml, ServerError } from './error-handler'; export { mergeHeadersCookies } from './cookie'; export { AbortMessage, RedirectMessage } from './redirect-handler'; export { requestHandler } from './request-handler'; -export { _TextEncoderStream_polyfill, _TextEncoderStream_polyfill2 } from './polyfill'; +export { _TextEncoderStream_polyfill } from './polyfill'; export type { CacheControl, Cookie, diff --git a/packages/qwik-city/middleware/request-handler/polyfill.ts b/packages/qwik-city/middleware/request-handler/polyfill.ts index 485bae077f72..15d708138df9 100644 --- a/packages/qwik-city/middleware/request-handler/polyfill.ts +++ b/packages/qwik-city/middleware/request-handler/polyfill.ts @@ -17,13 +17,16 @@ export class _TextEncoderStream_polyfill { chunk = String(chunk); let finalChunk = ''; - for (const item of chunk) { + for (let i = 0; i < chunk.length; i++) { + const item = chunk[i]; const codeUnit = item.charCodeAt(0); + if (this.#pendingHighSurrogate !== null) { const highSurrogate = this.#pendingHighSurrogate; this.#pendingHighSurrogate = null; - if (codeUnit >= 0xdc00 && codeUnit <= 0xdfff) { + + if (0xdc00 <= codeUnit && codeUnit <= 0xdfff) { finalChunk += highSurrogate + item; continue; } @@ -31,12 +34,12 @@ export class _TextEncoderStream_polyfill { finalChunk += '\uFFFD'; } - if (codeUnit >= 0xd800 && codeUnit <= 0xdbff) { + if (0xd800 <= codeUnit && codeUnit <= 0xdbff) { this.#pendingHighSurrogate = item; continue; } - if (codeUnit >= 0xdc00 && codeUnit <= 0xdfff) { + if (0xdc00 <= codeUnit && codeUnit <= 0xdfff) { finalChunk += '\uFFFD'; continue; } @@ -73,39 +76,3 @@ export class _TextEncoderStream_polyfill { return 'TextEncoderStream'; } } - -const resolved = Promise.resolve(); -/** @internal */ -export class _TextEncoderStream_polyfill2 { - // minimal polyfill implementation of TextEncoderStream - // since Cloudflare Pages doesn't support readable.pipeTo() - _writer: any; - readable: any; - writable: any; - - constructor() { - this._writer = null; - this.readable = { - pipeTo: (writableStream: any) => { - this._writer = writableStream.getWriter(); - }, - }; - this.writable = { - getWriter: () => { - if (!this._writer) { - throw new Error('No writable stream'); - } - const encoder = new TextEncoder(); - return { - write: async (chunk: any) => { - if (chunk != null) { - await this._writer.write(encoder.encode(chunk)); - } - }, - close: () => this._writer.close(), - ready: resolved, - }; - }, - }; - } -} diff --git a/packages/qwik-city/middleware/request-handler/polyfill.unit.ts b/packages/qwik-city/middleware/request-handler/polyfill.unit.ts index d6cad161a51d..4516e124725b 100644 --- a/packages/qwik-city/middleware/request-handler/polyfill.unit.ts +++ b/packages/qwik-city/middleware/request-handler/polyfill.unit.ts @@ -69,6 +69,25 @@ describe('_TextEncoderStream_polyfill tests', () => { expect(polyWriter.write({} as any)).toEqual(nativeWriter.write({} as any)); }); + it("can encode emoji characters just the same as Node.js' implementation", async () => { + const polyfillStream = new _TextEncoderStream_polyfill(); + const nativeStream = new TextEncoderStream(); + + const input = '🦊test emoji encoding📦'; + + const polyReader = polyfillStream.readable.getReader(); + const nativeReader = nativeStream.readable.getReader(); + + polyfillStream.writable.getWriter().write(input); + nativeStream.writable.getWriter().write(input); + + const polyResult = await polyReader.read(); + const nativeResult = await nativeReader.read(); + + expect(polyResult.value).toEqual(nativeResult.value); + expect(new TextDecoder().decode(polyResult.value)).toBe(input); + }); + it('handles large input', async () => { const encoderStream = new _TextEncoderStream_polyfill(); const writer = encoderStream.writable.getWriter(); From 34274eda48eb4837488953814b018927010e0bae Mon Sep 17 00:00:00 2001 From: Jack Shelton <104264123+thejackshelton@users.noreply.github.com> Date: Sat, 8 Jun 2024 19:01:05 -0500 Subject: [PATCH 05/28] docs: add sponsors section to homepage (#6467) * add sponsors section to homepage * update layout --- .../docs/src/components/sponsors/sponsors.tsx | 17 +++++++++++++++++ packages/docs/src/routes/api/qwik/api.json | 8 ++++---- packages/docs/src/routes/api/qwik/index.md | 8 ++++---- packages/docs/src/routes/index.tsx | 2 ++ 4 files changed, 27 insertions(+), 8 deletions(-) create mode 100644 packages/docs/src/components/sponsors/sponsors.tsx diff --git a/packages/docs/src/components/sponsors/sponsors.tsx b/packages/docs/src/components/sponsors/sponsors.tsx new file mode 100644 index 000000000000..271ad3014c33 --- /dev/null +++ b/packages/docs/src/components/sponsors/sponsors.tsx @@ -0,0 +1,17 @@ +import { component$ } from '@builder.io/qwik'; +import { BuilderLogo } from '../svgs/builder-logo'; + +export const Sponsors = component$(() => { + // the margin tops are to counterract the margin in the builder block + return ( +
+
+ Special Sponsor + + + + Visual Headless CMS +
+
+ ); +}); diff --git a/packages/docs/src/routes/api/qwik/api.json b/packages/docs/src/routes/api/qwik/api.json index e89739c26a70..a41c01a30190 100644 --- a/packages/docs/src/routes/api/qwik/api.json +++ b/packages/docs/src/routes/api/qwik/api.json @@ -614,7 +614,7 @@ } ], "kind": "Variable", - "content": "> Warning: This API is now obsolete.\n> \n> this is a technology preview\n> \n\nCreates a signal.\n\nIf the initial state is a function, the function is invoked to calculate the actual initial state.\n\n\n```typescript\ncreateSignal: UseSignal\n```", + "content": "> Warning: This API is now obsolete.\n> \n> This is a technology preview\n> \n\nCreates a signal.\n\nIf the initial state is a function, the function is invoked to calculate the actual initial state.\n\n\n```typescript\ncreateSignal: UseSignal\n```", "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-signal.ts", "mdFile": "qwik.createsignal.md" }, @@ -1760,7 +1760,7 @@ } ], "kind": "Function", - "content": "> This API is provided as an alpha preview for developers and may change based on feedback that we receive. Do not use this API in a production environment.\n> \n\nLoad the prefetch graph for the container.\n\nEach Qwik container needs to include its own prefetch graph.\n\n\n```typescript\nPrefetchGraph: (opts?: {\n base?: string;\n manifestHash?: string;\n manifestURL?: string;\n nonce?: string;\n}) => JSXNode<\"script\">\n```\n\n\n\n\n
\n\nParameter\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\nopts\n\n\n\n\n{ base?: string; manifestHash?: string; manifestURL?: string; nonce?: string; }\n\n\n\n\n_(Optional)_ Options for the loading prefetch graph.\n\n- `base` - Base of the graph. For a default installation this will default to `/build/`. But if more than one MFE is installed on the page, then each MFE needs to have its own base. - `manifestHash` - Hash of the manifest file to load. If not provided the hash will be extracted from the container attribute `q:manifest-hash` and assume the default build file `${base}/q-bundle-graph-${manifestHash}.json`. - `manifestURL` - URL of the manifest file to load if non-standard bundle graph location name.\n\n\n
\n**Returns:**\n\n[JSXNode](#jsxnode)<\"script\">", + "content": "> This API is provided as an alpha preview for developers and may change based on feedback that we receive. Do not use this API in a production environment.\n> \n\nLoad the prefetch graph for the container.\n\nEach Qwik container needs to include its own prefetch graph.\n\n\n```typescript\nPrefetchGraph: (opts?: {\n base?: string;\n manifestHash?: string;\n manifestURL?: string;\n nonce?: string;\n}) => JSXNode<\"script\">\n```\n\n\n\n\n
\n\nParameter\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\nopts\n\n\n\n\n{ base?: string; manifestHash?: string; manifestURL?: string; nonce?: string; }\n\n\n\n\n_(Optional)_ Options for the loading prefetch graph.\n\n- `base` - Base of the graph. For a default installation this will default to `/build/`. But if more than one MFE is installed on the page, then each MFE needs to have its own base. - `manifestHash` - Hash of the manifest file to load. If not provided the hash will be extracted from the container attribute `q:manifest-hash` and assume the default build file `${base}/q-bundle-graph-${manifestHash}.json`. - `manifestURL` - URL of the manifest file to load if non-standard bundle graph location name.\n\n\n
\n**Returns:**\n\nJSXNode<\"script\">", "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/components/prefetch.ts", "mdFile": "qwik.prefetchgraph.md" }, @@ -1774,7 +1774,7 @@ } ], "kind": "Function", - "content": "> This API is provided as an alpha preview for developers and may change based on feedback that we receive. Do not use this API in a production environment.\n> \n\nInstall a service worker which will prefetch the bundles.\n\nThere can only be one service worker per page. Because there can be many separate Qwik Containers on the page each container needs to load its prefetch graph using `PrefetchGraph` component.\n\n\n```typescript\nPrefetchServiceWorker: (opts: {\n base?: string;\n scope?: string;\n path?: string;\n verbose?: boolean;\n fetchBundleGraph?: boolean;\n nonce?: string;\n}) => JSXNode<'script'>\n```\n\n\n\n\n
\n\nParameter\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\nopts\n\n\n\n\n{ base?: string; scope?: string; path?: string; verbose?: boolean; fetchBundleGraph?: boolean; nonce?: string; }\n\n\n\n\nOptions for the prefetch service worker.\n\n- `base` - Base URL for the service worker `import.meta.env.BASE_URL` or `/`. Default is `import.meta.env.BASE_URL` - `scope` - Base URL for when the service-worker will activate. Default is `/` - `path` - Path to the service worker. Default is `qwik-prefetch-service-worker.js` unless you pass a path that starts with a `/` then the base is ignored. Default is `qwik-prefetch-service-worker.js` - `verbose` - Verbose logging for the service worker installation. Default is `false` - `nonce` - Optional nonce value for security purposes, defaults to `undefined`.\n\n\n
\n**Returns:**\n\n[JSXNode](#jsxnode)<'script'>", + "content": "> This API is provided as an alpha preview for developers and may change based on feedback that we receive. Do not use this API in a production environment.\n> \n\nInstall a service worker which will prefetch the bundles.\n\nThere can only be one service worker per page. Because there can be many separate Qwik Containers on the page each container needs to load its prefetch graph using `PrefetchGraph` component.\n\n\n```typescript\nPrefetchServiceWorker: (opts: {\n base?: string;\n scope?: string;\n path?: string;\n verbose?: boolean;\n fetchBundleGraph?: boolean;\n nonce?: string;\n}) => JSXNode<'script'>\n```\n\n\n\n\n
\n\nParameter\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\nopts\n\n\n\n\n{ base?: string; scope?: string; path?: string; verbose?: boolean; fetchBundleGraph?: boolean; nonce?: string; }\n\n\n\n\nOptions for the prefetch service worker.\n\n- `base` - Base URL for the service worker `import.meta.env.BASE_URL` or `/`. Default is `import.meta.env.BASE_URL` - `scope` - Base URL for when the service-worker will activate. Default is `/` - `path` - Path to the service worker. Default is `qwik-prefetch-service-worker.js` unless you pass a path that starts with a `/` then the base is ignored. Default is `qwik-prefetch-service-worker.js` - `verbose` - Verbose logging for the service worker installation. Default is `false` - `nonce` - Optional nonce value for security purposes, defaults to `undefined`.\n\n\n
\n**Returns:**\n\nJSXNode<'script'>", "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/components/prefetch.ts", "mdFile": "qwik.prefetchserviceworker.md" }, @@ -3048,7 +3048,7 @@ } ], "kind": "Function", - "content": "> Warning: This API is now obsolete.\n> \n> this is a technology preview\n> \n\nStores a value which is retained for the lifetime of the component.\n\nIf the value is a function, the function is invoked to calculate the actual value.\n\n\n```typescript\nuseConstant: (value: (() => T) | T) => T\n```\n\n\n\n\n
\n\nParameter\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\nvalue\n\n\n\n\n(() => T) \\| T\n\n\n\n\n\n
\n**Returns:**\n\nT", + "content": "> Warning: This API is now obsolete.\n> \n> This is a technology preview\n> \n\nStores a value which is retained for the lifetime of the component.\n\nIf the value is a function, the function is invoked to calculate the actual value.\n\n\n```typescript\nuseConstant: (value: (() => T) | T) => T\n```\n\n\n\n\n
\n\nParameter\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\nvalue\n\n\n\n\n(() => T) \\| T\n\n\n\n\n\n
\n**Returns:**\n\nT", "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-signal.ts", "mdFile": "qwik.useconstant.md" }, diff --git a/packages/docs/src/routes/api/qwik/index.md b/packages/docs/src/routes/api/qwik/index.md index b9c2c5f2e1e5..f9f78b00c0fe 100644 --- a/packages/docs/src/routes/api/qwik/index.md +++ b/packages/docs/src/routes/api/qwik/index.md @@ -1857,7 +1857,7 @@ The name of the context. > Warning: This API is now obsolete. > -> this is a technology preview +> This is a technology preview Creates a signal. @@ -3621,7 +3621,7 @@ _(Optional)_ Options for the loading prefetch graph. **Returns:** -[JSXNode](#jsxnode)<"script"> +JSXNode<"script"> [Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/components/prefetch.ts) @@ -3675,7 +3675,7 @@ Options for the prefetch service worker. **Returns:** -[JSXNode](#jsxnode)<'script'> +JSXNode<'script'> [Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/components/prefetch.ts) @@ -10194,7 +10194,7 @@ qrl > Warning: This API is now obsolete. > -> this is a technology preview +> This is a technology preview Stores a value which is retained for the lifetime of the component. diff --git a/packages/docs/src/routes/index.tsx b/packages/docs/src/routes/index.tsx index 425d1b169f31..07f436aeae63 100644 --- a/packages/docs/src/routes/index.tsx +++ b/packages/docs/src/routes/index.tsx @@ -3,6 +3,7 @@ import { type DocumentHead } from '@builder.io/qwik-city'; import BuilderContentComp from '../components/builder-content'; import { Footer } from '../components/footer/footer'; import { Header } from '../components/header/header'; +import { Sponsors } from '~/components/sponsors/sponsors'; import { QWIK_MODEL, QWIK_PUBLIC_API_KEY } from '../constants'; export default component$(() => { @@ -11,6 +12,7 @@ export default component$(() => {
+