DEV Community

Cover image for Build Deploy a LaTeX editor using GitHub Actions
Practicing Datscy
Practicing Datscy

Posted on

Build Deploy a LaTeX editor using GitHub Actions

LaTeX is writing language that is often used for long articles, books, and/or papers. LaTeX represents the Greek characters Tau=T Epsilon=E Chi=X, implying "The Skill Art Technique" [1]. It is specifically used for professional writing and university thesis writing because:

  1. it can print any font/symbol effortlessly due to its efficient type scripting system,
  2. it can create 100-1000 page pdf documents without risk of file encoding errors and/or file corruption because all text is written in a plain text file (.tex) and directly transformed to pdf.

It consists of a text coding language that specifies document notation. The writer writes their text, mixed with the LaTeX text coding language, in a simple text file with the extension (.tex). The (.tex) file is then compiled into a .pdf file, using the LaTeX compiler using a series of postscript commands.

LaTeX is not popular for mainstream document users because Google Office Suite and Microsoft Office do not require users to write type scripting code with their text, and make them compile the final document into its visual product. Many mainstream users prefer to directly arrange document text into the final visual product, instead of using code to create the visual product. In order to overcome this dislike, there are many popular online LaTeX editors, like Overleaf, that hide the compiling process and code via templates such that users only need to write.

In this blog post, I show how to build and deploy a simple LaTeX webapp using GitHub Actions; a comparable alternative.

Steps to make a GitHub repository a LaTeX editor

Step 0: Make a GitHub Actions workflow

  1. Create a GitHub repository
  2. Make the repository a deployed page (Settings - Pages - Build and deployment: GitHub Actions)
  3. Create .github and .github/workflows folders
  4. Create the following yaml in the .github/workflows folder.

LaTeX compiles a file named index.tex that is in the repository, into a file called index.pdf. The git push command saves only the generated index.pdf file from the GitHub Actions runner to the repoName repository.

name: CI github pages

on:
  push:
    branches:
      - main

# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions: write-all

# 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

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Pages
        uses: actions/configure-pages@v5

      - name: Install Latex
        run: |
          sudo apt-get install texlive;
          sudo apt-get install texlive-latex-extra;
          sudo apt-get install texlive-font-utils; 

          DOCUMENT_NAME="index.tex";
          DOCUMENT_NAME_WO_EXT="$(echo $DOCUMENT_NAME | cut -d '.' -f 1)";
          echo "DOCUMENT_NAME_WO_EXT = $DOCUMENT_NAME_WO_EXT"; 

          latex $DOCUMENT_NAME

          dvips -P pdf "${DOCUMENT_NAME_WO_EXT}.dvi"
          ps2pdf "${DOCUMENT_NAME_WO_EXT}.ps"

      - name: Commit and push changes
        run: |
          repoOwner=$(echo "${{ github.repository }}" | cut -d '/' -f 1);
          repoOwnerEmail="EMAIL_USERNAME@gmail.com";
          git config --global user.email ${repoOwnerEmail};
          git config --global user.name ${repoOwner};
          git pull origin main;
          git checkout main;
          git branch --set-upstream-to origin/main;
          git merge main --ff-only;
          git add /home/runner/work/repoName/repoName/index.pdf;
          git diff-index --quiet HEAD || git commit -m "add files" --allow-empty;
          git push

      - name: Upload Artifact
        uses: actions/upload-pages-artifact@v3
        with:
          # location of the artifacts
          path: "./"

  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4
Enter fullscreen mode Exit fullscreen mode

Step 1: Make a simple UI interface

Below is a simple HTML outline to make a webapp where the user can view both the .tex and .pdf file from the repository. Thus, in order to use this workflow/webapp:

  1. Copy-paste changes in the .tex file on GitHub.
  2. The GitHub Actions .yaml automatically launches when any changes are made to the files in the repository. Refresh the webapp page when the .yaml workflow finishes.
  3. View the .tex and .pdf file using the GitHub Pages webapp url. Make changes to the .tex textarea in the webapp using spell check from the browser, and copy-paste the changes from the textarea into the .tex file on GitHub (which brings us back to step 1!).
<!DOCTYPE html>
<html>
<head></head>
<body>

<!-- ---------------------------------------- -->
<!-- View two split window -->
<div align="left">
<table style='text-align: left; width: 500px; display:block'>
<tr>

<th id="pdf_viewer_input">
<h3>[Step 0] View the .tex file.</h3>
<textarea id="tex_file" rows="35" cols="100" placeholder=".tex file" style="display:block" width:100px; height: 200px;></textarea>
<br><br>
<button id="show_tex_wo_CORS" onclick="show_tex_wo_CORS()">[Step 0] Show .tex file</button>
</th>

<!-- ---------------------------------------- -->

<th id="pdf_viewer_output">
<h3>[Step 1] View PDF.</h3>
<br><br>
<button id="show_pdf_wo_CORS" onclick="show_pdf_wo_CORS()">[Step 1] Show .pdf file.</button>
</th>

</tr>
</table>
</div>  
<!-- ---------------------------------------- -->


<!-- ---------------------------------------- -->
<!-- CSS -->
<style>
div { padding: 10px; display:block; font-family:courier; font-size:15px; height:300px; }

div#notification { position: relative; color: #3236a8; }
div#error { position: relative; color: #bd1f17; }

table {vertical-align: top; border-collapse: collapse; position: relative; z-index: 0; border: 0px solid black;}

tr {vertical-align: top; border: 0px solid black; padding: 30px 30px; }

th, td {vertical-align: top; border: 0px solid black; padding: 10px; }
th#pdf_viewer_input {width: 100%; }
th#pdf_viewer_output {width: 100%; }

object#pdf_object_element {position: absolute; vertical-align: top; top: 200; z-index: 200; }
</style>


<!-- --------------------------------------------------- -->

<script>


// ----------------------------------------------------
// Step 0
// ----------------------------------------------------
async function show_tex_wo_CORS() {
var file_download_url = "https://repoOwner.github.io/repoName/index.tex";

    return await fetch(file_download_url)
        .then(res => res.text())
        .then(str_data => {
      console.log("str_data: ", str_data);
      document.getElementById("tex_file").innerHTML = str_data;
    })
        .catch(error => { console.log(error); });
}

// ----------------------------------------------------
// Step 1
// ----------------------------------------------------
// Show pdf without CORS
async function show_pdf_wo_CORS() {

  try {
    // without CORS: name of file
    var file_download_url = "https://repoOwner.github.io/repoName/index.pdf";

    let file_download_url_name = file_download_url.split('/').pop();
    console.log("file_download_name: ", file_download_url_name);

    var objectElement = document.createElement('object');
    objectElement.setAttribute("id", "pdf_object_element");
    objectElement.setAttribute("type", "application/pdf");
    objectElement.setAttribute("width", 800);
    objectElement.setAttribute("height", 1200);
    objectElement.setAttribute("data", file_download_url_name);
    document.getElementById('pdf_viewer_output').appendChild(objectElement);

  } catch (error){
    document.getElementById("error").innerText = error;
  }

}

</script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

View of the webapp displaying both the .tex and .pdf documents

View of the webapp displaying both the .tex and .pdf documents

In a more complex version, the webapp can REST API PUT (ie: save) changes from the textarea to the .tex file in the repository. And, then launch the backend (.yaml) to recreate the index.pdf, once the index.pdf is recreated in the repository the webapp refreshes both the index.tex and the index.pdf.

Happy Practicing! 👋

💻 GitHub | 🌷 Practicing Datscy @ Dev.to | 🌳 Practicing Datscy @ Medium

References

  1. LaTeX - Wikipedia: https://en.wikipedia.org/wiki/LaTeX

Top comments (0)