Build Deploy a LaTeX editor using GitHub Actions
Practicing Datscy
Posted on September 25, 2024
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:
- it can print any font/symbol effortlessly due to its efficient type scripting system,
- 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
- Create a GitHub repository
- Make the repository a deployed page (Settings - Pages - Build and deployment: GitHub Actions)
- Create .github and .github/workflows folders
- 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
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:
- Copy-paste changes in the .tex file on GitHub.
- 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.
- 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>
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
- LaTeX - Wikipedia: https://en.wikipedia.org/wiki/LaTeX
Posted on September 25, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.