DEV Community

Deploy to Github Pages like a pro with Github Actions

Roland Doda on March 15, 2020

GitHub Pages is a static site hosting service designed to host your personal, organization, or project pages directly from a GitHub repository. No...
Collapse
 
codergo profile image
sam

Great article, thank you. I had to do some changes to get it working through trial and error. For example if you have a custom domain you need to write a CNAME file to the dist/build directory before the git commands. Indenting was also broken for me on copy paste.

Collapse
 
the_one profile image
Roland Doda

Hi Sam, thank you for your comment.

Yeah those are some valid issues, glad to read you fixed them on your own.
I remember I created this library which does everything automatically if you use vue-cli -> github.com/Rolanddoda/vue-cli-plug....

However, both the article and the repo are old and nowadays it's not recommended to use vue-cli because it's in Maintenance Mode.

Collapse
 
beatrizsmerino profile image
Beatriz Sopeña Merino • Edited

Hi!!!, Great post I have been using the gh-pages-deploy.js script for a while and it worked perfectly, but for some reason now I get an error when usingrequire`.

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module...
...require() of ES modules is not supported...is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.

Is this happening to anyone?

https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l7mysc2axiuhoo71h1re.png

Collapse
 
the_one profile image
Roland Doda

Hi, thanks.
Probably it's an error coming from upgrading packages. For instance, chalk and other libraries that gh-pages-deploy script uses, are now ESM only!
If you want me to help you, please drop me a message on Linkedin with a screenshot of the error you are getting.

Collapse
 
beatrizsmerino profile image
Beatriz Sopeña Merino

Thanks Ronald!
Right, I was trying a lot of things for a while and finally found it by installing an older version of the packages.

    "dependencies": {
        "chalk": "^4.1.2",
        "execa": "^5.1.1",
        "node-emoji": "^1.11.0",
    },
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
the_one profile image
Roland Doda

Glad to see that you fixed it.

Thread Thread
 
beatrizsmerino profile image
Beatriz Sopeña Merino

I was also getting some errors in the yml file.
https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wdxdsqk54ds9w8myekjd.png

I solved it by updating it following the structure of this file :
github.com/Rolanddoda/vue-cli-plug...
https://dev-to-uploads.s3.amazonaws.com/uploads/articles/onysv4ohfp8kxs8j9v62.png

... and the name of my npm script also had a different name

I leave it here written down in case someone else finds it helpful.

Thread Thread
 
the_one profile image
Roland Doda

Thanks for that. Yes setup-node@v1.1.0 is deprecated and setup-node@v2 should be used. I will make sure to update the article. Since you are using vue and you found the vue-cli plugin, then I guess you don't have to follow this article anymore. You can just install the plugin and everything that is in that article will automatically be done for you.

Thread Thread
 
beatrizsmerino profile image
Beatriz Sopeña Merino

Thanks, yes I will take a look at the repo, when I have time, it is more updated and I see that there are more automations to get the user's name and email.

Thread Thread
 
the_one profile image
Roland Doda

Yup. :)

Collapse
 
nsnyder profile image
Nathan Snyder

Excellent post! Thank you! If I may make a recommendation, removing the first layer of indentation in the code block would help a lot I think. It took me a few minutes to figure out why my .yml was being rejected, but it was because everything except the name: line was indented too much.

Still, this got me up and running quickly, with a few minor tweaks to improve things for my workflow! Unfortunately, my user page has to deploy on master so I'm doing that. I might move my personal website to a different repo though, because being able to use gh-pages without polluting master would definitely be preferable.

Collapse
 
mcshaz profile image
Brent McSharry • Edited

Thank you for posting this great article. Just a few additional notes you might even want to put in the article.
1) I am fairly sure github pages has no way of implementing History mode, so it is important that if you are using the Vue router, it is set like so

export default new Router({
  mode: 'hash',
Enter fullscreen mode Exit fullscreen mode

2) For the script to deploy to github pages from the local machine, I would advise checking if there are uncommitted changes first with something like

    try {
        await execa("git", ["update-index", "--refresh"]); 
        const { stdout } = await execa("git", ["diff-index", "HEAD"]);
        if (stdout) {
            console.log("Please stash or commit changes first!");
            process.exit(1);
        }
   }
Enter fullscreen mode Exit fullscreen mode

3) It might be worth putting the final git commands in a finally block so you always end up back on master. Also note below the rm command is replaced by rimraf - rm is platform specific (and certainly will not work on Windows) and rimraf deals with this for us.

   const rmrf = promisify(rimraf);
    let exitCode = 0;
    try {
        await execa("git", ["checkout", "--orphan", "gh-pages"]);
        console.log("Building...");
        await execa("yarn", ["run", "build-modern"]);
        // Understand if it's dist or build folder
        const folderName = existsSync("dist") ? "dist" : "build";
        await execa("git", ["--work-tree", folderName, "add", "--all"]);
        await execa("git", ["--work-tree", folderName, "commit", "-m", "gh-pages"]);
        console.log("Pushing to gh-pages...");
        await execa("git", ["push", "origin", "HEAD:gh-pages", "--force"]);
        await rmrf(folderName, { glob: false })
        console.log("Successfully deployed");
    } catch (e) {
        console.log(e.message);
        exitCode = 1;
    } finally {
        await promises.writeFile(configFilePath, originPublicPath, fileOpts);
        await execa("git", ["checkout", "-f", "master"]);
        await execa("git", ["branch", "-D", "gh-pages"]);
    }
    process.exit(exitCode);
Enter fullscreen mode Exit fullscreen mode
Collapse
 
the_one profile image
Roland Doda

Hi Brent and thank you for this comment.

As I said in the end of the article, I want to keep the script very minimal so anyone understands it and can modify it. There is so many things to add to that script and to the whole article itself, but I wanted to go with simplicity.

Here are my answers to your notes:

1) There is a way to get the History mode work with github pages. See -> github.com/Rolanddoda/vue-router-g...
However, going with hash mode, is something that you can easily do, but it's out of the scope of this article on automating deployment to github pages by using github actions. (I would had to talk about vue router history mode and hash mode).

2) It's worth noting that the script will run in github actions environment after you have pushed on master. So no need to check for uncommitted changes.

3) For the same reason as on the second note, no need to add a finally block and also the rm command will run in ubuntu as I've defined in the github actions workflow.

Again, there are so many things to add on that article but I want to keep it simple so anyone can easily extend it. I hope I have helped people on how to take advantage of github actions and github pages.

Thanks for taking the time to comment Brent,
With Respect, Roland.

Collapse
 
mishajib profile image
MI Shajib

Thank you very much. It helped me very much.

Collapse
 
the_one profile image
Roland Doda

Glad to read that it helped you 🎉.
If you are using vue.js though I have created a vue-cli plugin which automates everything and it's literally a zero-config solution. Check it out -> github.com/Rolanddoda/vue-cli-plug....
I have in mind some improvements to do there but haven't found the time yet.

Collapse
 
chapkovski profile image
Philipp Chapkovski

Small note for those who use yarn (like me) and not npm. You will get
npm ERR! cipm can only install packages when your package.json and package-lock.json or npm-shrinkwrap.json are in sync.
because obviously package-lock.json doesn't exist. You either need to create package-lock by npm install or change a bit last lines of gh-pages-deploy.yml to

      - name: Clean install dependencies
        run: yarn install --frozen-lockfile

      - name: Run deploy script
        run: |
          git config user.name "Your username" && git config user.email "your email"
          yarn run gh-pages-deploy
Collapse
 
the_one profile image
Roland Doda

Thank you Philipp.

Collapse
 
dohahelmy profile image
Doha Helmy

Hello, Thank you for the great tutorial.
one problem I have is rm -r dist doesn't work! it says that rm is not recognized and I tried replacing it with del so it asked me to delete everything inside dist and I said yes.
and nothing is working :(
Can you please help?

Collapse
 
the_one profile image
Roland Doda

I have to see what and where the issue is. Feel free to send me an email at rolanddoda2014@gmail.com so I can help you to fix the issue

Collapse
 
abhilashkulkarniofficial profile image
Abhilash Kulkarni

Thank you for the article. I've published many websites on gh-pages using this. I was getting an error while deploying using Github actions and it turns out that the setup-node version has been updated and using setup-node@v1.1.0 will throw an error. I used the updated version setup-node@v2 and it worked fine.

Collapse
 
bobik808 profile image
Konstantin Grachev

Excellent post! Thank you, Roland.

As Nathan Snyder pointed out, the .yml block doesn't work if you copy from the first character to the last as there is an indentation on the entire code block that is not immediately apparent. Though this is a minor detail, it might help other less experienced programmers (like myself) to take note of this.

Collapse
 
ogbenihmmd profile image
Hammed A. Olajide

I got mine working after tweaks here and there. Thank you sooo much!

Collapse
 
dance2die profile image
Sung M. Kim

Thanks for the post, Roland,

Especially arrows on the images are helpful as people don't have to scan the image to find out where.

Collapse
 
the_one profile image
Roland Doda

Glad to read that you liked the article and the way it's written Sung. It took me some days (considering I am working full-time) to finish it but I always try to make good articles. So far I have got 3 emails from people thanking me and they are amazed about the automation. Wondering if you have tried it.

Collapse
 
dance2die profile image
Sung M. Kim

I've tried gh pages & actions but only separately.

Should an opportunity comes, then I will try it :)

Collapse
 
jgascue profile image
Javier Gascue • Edited

Thanks for the post, Roland, nice done!
Is exactly what i was looking for, and save me a lot of time for sure :)
Only with the intention of improvement, and for others who may be had the same issue,
there is a little mistake in this line, its miss a "-" in the word worktree:
git --worktree dist add --all Docs (for react: replace dist with build)

should be >>
git --work-tree dist add --all Docs (for react: replace dist with build)
Got me crazy until I realised it

My congrats for the site aswell. Shum Faleminderit!

Collapse
 
the_one profile image
Roland Doda • Edited

Ahh yes, instead of --work-tree was --worktree without the dash. Thanks Javier. The typo is already fixed now.

Collapse
 
olgashrir profile image
OlgaShrir

Hey Roland, thanks for the article!
My GitHub pages shows me the readme.md file instead of my website. I found that the reason is that the index.html file is not in the root directory, but in public directory. Locating index.html in public directory is vue's default. What can I do to see the whole website and not just the readme.md file?

Collapse
 
the_one profile image
Roland Doda

Hi, I need to investigate what is going on there in order to know for sure what is happening.
Please, DM me on Linkedin -> linkedin.com/in/roland-doda/
or send me an email at rolanddoda2014@gmail.com

Collapse
 
leozengtao profile image
Leo Zeng

Thanks for the awesome post, it helps me a lot.

Collapse
 
jaseelbavu profile image
Jaseel P V

What an awesome article. Thank you Roland Doda for you effort.

Collapse
 
the_one profile image
Roland Doda

Glad to read that you liked it :)

Collapse
 
huckbit profile image
Max Ranauro

Very nice post mate thank you! Excellent work!!!

Collapse
 
the_one profile image
Roland Doda

Glad to read that you liked it Max.

Collapse
 
s0xzwasd profile image
Daniil Maslov

Thank you, just yesterday I searched for this information on Google, but found it here :)

Collapse
 
the_one profile image
Roland Doda

Thanks for the comment Daniil

Collapse
 
artilishes profile image
Arthur

Nice one, thanks for sharing.

Collapse
 
the_one profile image
Roland Doda

Thanks for the comment Arthur

Collapse
 
patarapolw profile image
Pacharapol Withayasakpunt

Links are always nice.

I also use similar? method to deploy unrelated brach to Heroku.