From 6903b2b7db6118d1a7fba4f2de777d805231e555 Mon Sep 17 00:00:00 2001 From: Patrick Elsen Date: Thu, 31 Oct 2024 01:33:50 +0100 Subject: [PATCH] Adds GitLab Pages example --- src/deployment/csr.md | 255 +++++++++++++++++++++++++++++++----------- 1 file changed, 189 insertions(+), 66 deletions(-) diff --git a/src/deployment/csr.md b/src/deployment/csr.md index aff7beb..fe02bae 100644 --- a/src/deployment/csr.md +++ b/src/deployment/csr.md @@ -14,104 +14,227 @@ _Note: Leptos does not endorse the use of any particular hosting service - feel Examples: +- [GitLab Pages](#gitlab-pages) - [Github Pages](#github-pages) - [Vercel](#vercel) - [Spin (serverless WebAssembly)](#spin---serverless-webassembly) -## Github Pages +## General Advice -Deploying a Leptos CSR app to Github pages is a simple affair. First, go to your Github repo's settings and click on "Pages" in the left side menu. In the "Build and deployment" section of the page, change the "source" to "Github Actions". Then copy the following into a file such as `.github/workflows/gh-pages-deploy.yml` +Depending on the complexity of your application, you may find that the size of +the WebAssembly binary can get large. This impacts users of your application by +slowing down loading time. There are two easy things you can do to mitigate +this: using `wasm-opt` to reduce the size, and compeessing it. There is more +general information in the [Optimizing WASM Binary Size](./binary_size.md) that +you should follow, but these two tips are useful for CSR applications built +with Trunk. -```admonish example collapsible=true +### Optimizing WebAssembly + +If you use Trunk to build your client-side rendered application, then you will have +an `index.html` file which tells Trunk what assets to build, and where to put them. + +Part of this is metadata telling Trunk how to include your Rust application. This +is specified as a `` element, typically in the `` of your `index.html`. +If you add the `data-wasm-opt` attribute to this element, then Trunk will call +`wasm-opt` on your binary, which can significantly reduce code size. + +```html + +``` + +Similar to how your `Cargo.toml` supports different optimization levels, so +does `wasm-opt`. Typically, using the `s` or `z` levels will get you small code +sizes. Depending on your application, you may see a 10% reduction in code size +by enabling this. + +### Compression + +The WebAssembly output is highly compressible. Depending on the compression +algorithm used, you can get significant savings. Typical compression ratios are +50% with gzip and 70% using brotli. - name: Release to Github Pages +If your hosting solution handles compression for you, then you don't need to do +anything. Some hosting solutions allow serving precompressed content, but +require you to do the compression. The way it works is when a user requests +`file.wasm`, the browser indicates that it supports compression, and you have a +`file.wasm.gz` file, then it will serve it instead. + +One way to create these precompressed files is by running this command: + +```bash +find dist -not -name '*.gz' -not -name '*.br' -type f -exec gzip -vk {} \; +find dist -not -name '*.gz' -not -name '*.br' -type f -exec brotli -vk {} \; +``` + +This will pre-compress all of your assets with gzip and brotli, which have +almost universal browser support. + +## GitLab Pages + +Deploying a Leptos application with GitLab Pages is very straightforward. +GitLab CI uses a `.gitlab-ci.yml` file, which specifies some actions to be +taken (which generally involve running some commands in a docker container with +an image that you specify). + +CI jobs can specify outputs (called *artifacts*). If you have a magic CI job +named *pages*, then the output of this job is what gets hosted. You can also +add custom domains, so that you can deploy static sites. + +A simple example is the following configuration. If you create a file in your +repository called `.gitlab-ci.yml` and paste the following configuration into +it, then it will build your project with `trunk`, compress all assets, and +publish them to GitLab Pages. One important thing to keep in mind is that you +likely want a `_redirects` file to cause all requests to go to `index.html`, +otherwise your routing won't work correctly. This example includes one. + +You may want to adjust the Rust and Trunk versions to the most recent ones and +the name of the default branch. + +~~~admonish example collapsible=true +```yaml +stages: + - build + - publish + +# adjust these +variables: + RUST_VERSION: "1.81" + TRUNK_VERSION: "0.21.1" + +# Build stage: builds everything using trunk. +build: + stage: build + image: rust:$RUST_VERSION + before_script: + - rustup target add wasm32-unknown-unknown + - wget -qO- https://github.com/thedodd/trunk/releases/download/v${TRUNK_VERSION}/trunk-x86_64-unknown-linux-gnu.tar.gz | tar -xzf- -C /usr/local/bin + script: + - trunk build --release + artifacts: + paths: + - dist + +# Pages job: compress files and publish statically. this takes the output from +# the "build" job and produces a folder containing everything that needs to be +# statically hosted. +# +# we also have to do is add a redirects file: because this is a single-page +# app, we want every path to resolve to the index.html (otherwise you get a 404 +# if you request diff.rs/serde, because there is no actual file or folder named +# "serde"). +pages: + stage: publish + image: alpine + before_script: + - apk add brotli gzip + script: + - mv dist public + - find public -not -name '*.gz' -not -name '*.br' -type f -exec gzip -vk {} \; + - find public -not -name '*.gz' -not -name '*.br' -type f -exec brotli -vk {} \; + - echo '/* / 200' >> public/_redirects + artifacts: + paths: + - public + only: + - master +``` +~~~ + +## Github Pages + +Deploying a Leptos CSR app to Github pages is a simple affair. First, go to your Github repo's settings and click on "Pages" in the left side menu. In the "Build and deployment" section of the page, change the "source" to "Github Actions". Then copy the following into a file such as `.github/workflows/gh-pages-deploy.yml` - on: - push: - branches: [main] - workflow_dispatch: +~~~admonish example collapsible=true +```yaml +name: Release to Github Pages - permissions: - contents: write # for committing to gh-pages branch. - pages: write - id-token: write +on: + push: + branches: [main] + workflow_dispatch: - # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. - # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. - concurrency: - group: "pages" - cancel-in-progress: false +permissions: + contents: write # for committing to gh-pages branch. + pages: write + id-token: write - jobs: - Github-Pages-Release: +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false - timeout-minutes: 10 +jobs: + Github-Pages-Release: - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} + timeout-minutes: 10 - runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} - steps: - - uses: actions/checkout@v4 # repo checkout + runs-on: ubuntu-latest - # Install Rust Nightly Toolchain, with Clippy & Rustfmt - - name: Install nightly Rust - uses: dtolnay/rust-toolchain@nightly - with: - components: clippy, rustfmt + steps: + - uses: actions/checkout@v4 # repo checkout - - name: Add WASM target - run: rustup target add wasm32-unknown-unknown + # Install Rust Nightly Toolchain, with Clippy & Rustfmt + - name: Install nightly Rust + uses: dtolnay/rust-toolchain@nightly + with: + components: clippy, rustfmt - - name: lint - run: cargo clippy & cargo fmt + - name: Add WASM target + run: rustup target add wasm32-unknown-unknown + - name: lint + run: cargo clippy & cargo fmt - # If using tailwind... - # - name: Download and install tailwindcss binary - # run: npm install -D tailwindcss && npx tailwindcss -i -o # run tailwind + # If using tailwind... + # - name: Download and install tailwindcss binary + # run: npm install -D tailwindcss && npx tailwindcss -i -o # run tailwind - - name: Download and install Trunk binary - run: wget -qO- https://github.com/trunk-rs/trunk/releases/download/v0.18.4/trunk-x86_64-unknown-linux-gnu.tar.gz | tar -xzf- - - name: Build with Trunk - # "${GITHUB_REPOSITORY#*/}" evaluates into the name of the repository - # using --public-url something will allow trunk to modify all the href paths like from favicon.ico to repo_name/favicon.ico . - # this is necessary for github pages where the site is deployed to username.github.io/repo_name and all files must be requested - # relatively as favicon.ico. if we skip public-url option, the href paths will instead request username.github.io/favicon.ico which - # will obviously return error 404 not found. - run: ./trunk build --release --public-url "${GITHUB_REPOSITORY#*/}" + - name: Download and install Trunk binary + run: wget -qO- https://github.com/trunk-rs/trunk/releases/download/v0.18.4/trunk-x86_64-unknown-linux-gnu.tar.gz | tar -xzf- + - name: Build with Trunk + # "${GITHUB_REPOSITORY#*/}" evaluates into the name of the repository + # using --public-url something will allow trunk to modify all the href paths like from favicon.ico to repo_name/favicon.ico . + # this is necessary for github pages where the site is deployed to username.github.io/repo_name and all files must be requested + # relatively as favicon.ico. if we skip public-url option, the href paths will instead request username.github.io/favicon.ico which + # will obviously return error 404 not found. + run: ./trunk build --release --public-url "${GITHUB_REPOSITORY#*/}" - # Deploy to gh-pages branch - # - name: Deploy 🚀 - # uses: JamesIves/github-pages-deploy-action@v4 - # with: - # folder: dist + # Deploy to gh-pages branch + # - name: Deploy 🚀 + # uses: JamesIves/github-pages-deploy-action@v4 + # with: + # folder: dist - # Deploy with Github Static Pages - - name: Setup Pages - uses: actions/configure-pages@v4 - with: - enablement: true - # token: + # Deploy with Github Static Pages - - name: Upload artifact - uses: actions/upload-pages-artifact@v2 - with: - # Upload dist dir - path: './dist' + - name: Setup Pages + uses: actions/configure-pages@v4 + with: + enablement: true + # token: - - name: Deploy to GitHub Pages 🚀 - id: deployment - uses: actions/deploy-pages@v3 + - name: Upload artifact + uses: actions/upload-pages-artifact@v2 + with: + # Upload dist dir + path: './dist' + - name: Deploy to GitHub Pages 🚀 + id: deployment + uses: actions/deploy-pages@v3 ``` +~~~ For more on deploying to Github Pages [see the example repo here](https://github.com/diversable/deploy_leptos_csr_to_gh_pages)