DEV Community

Cover image for Submodules with Vercel and Next.js
Maciej Sulecki
Maciej Sulecki

Posted on

Submodules with Vercel and Next.js

Vercel is the team behind Next.js and they have their platform called Vercel, I frequently use it to deploy my Next.js projects and it works great, the concern I had was when I tried to deploy my repo with a submodule there.

See, Vercel does support submodules however only when these are public, which in my case was not an option. I would have to change my whole CI/CD pipeline, stop using the submodule or figure something out.

I started figuring something out.

https://github.com/vercel/vercel/discussions/4566#discussioncomment-125253
https://github.com/vercel/vercel/discussions/4566#discussioncomment-125253

First there I've found a confirmation that my problem is real, there really is no support for private submodules on Vercel  -  and judging by the rate of Vercel bringing new updates to Next.js (very frequent) and the fact that this issue still hasn't been resolved I think that the private submodules still have a long way to come and are not quite high on the TODO list.

After thinking about it and checking out the Vercel docs to find out what are my limitations, I've finally started getting somewhere.

The solution I came up with is a simple script that you run instead of the default installation command on Vercel (instead of yarn or npm install). I've been using this script for half a year now and I have changed it and made it better countless times, now its fully working version works just like the real native private submodule would.

How to use it?

It's rather simple.

📋 Step by step 🚀

  • copy the ./vercel-submodule-workaround.sh to the root of your project

  • make sure the file is executable - run this command:

    chmod u+x vercel-submodule-workaround.sh
    
  • in your package.json add a script:

    {
        "scripts":{
            "vercel-install": "./vercel-submodule-workaround.sh && yarn --ignore-scripts --production=false",
        }
    }
    

    Info:

    --production=false ensures that dev-dependencies will be installed, if you dont need your dev-dependencies to install then just delete this flag.

    --ignore-scripts ignores pre and post install scripts if you want the scripts to run delete this flag.

  • Tell Vercel to use vercel-install instead of the defalt install command

    • project -> Settings -> General => Build & Development Settings
    • in INSTALL COMMAND type
    yarn vercel-install 
    # or 
    npm vercel-install
    
    • toggle OVERRIDE on
  • Create a Github access token

    • Settings -> Developer settings -> Personal access tokens
    • Generate new token
    • set a note (eg. vercel)
    • set expiration to whatever you see fit (eg. No expiration)
    • select repo

      [x] repo - Full control of private repositories

    • copy the generated token

  • Add the token to Vercel Environment Variables

    • Project -> Settings -> Environment Variables
    • add a new variable called GITHUB_ACCESS_TOKEN and with value of the token you just copied

+ Post Scriptum

I haven't added support for multiple submodules but it should be easy enough, try edditing this part and then the rest of the script.

The code itself

I have thrown in a looooot of comments so that you can easily understand what's happening, it's always good to understand what you're using especially if its some bash script and especially if you're using it to run important code on production ;)

# github submodule repo address without https:// prefix
SUBMODULE_GITHUB=github.com/beeinger/vercel-private-submodule

# .gitmodules submodule path
SUBMODULE_PATH=library

# github access token is necessary
# add it to Environment Variables on Vercel
if [ "$GITHUB_ACCESS_TOKEN" == "" ]; then
  echo "Error: GITHUB_ACCESS_TOKEN is empty"
  exit 1
fi

# stop execution on error - don't let it build if something goes wrong
set -e

# get submodule commit
output=`git submodule status --recursive` # get submodule info
no_prefix=${output#*-} # get rid of the prefix
COMMIT=${no_prefix% *} # get rid of the suffix

# set up an empty temporary work directory
rm -rf tmp || true # remove the tmp folder if exists
mkdir tmp # create the tmp folder
cd tmp # go into the tmp folder

# checkout the current submodule commit
git init # initialise empty repo
git remote add origin https://$GITHUB_ACCESS_TOKEN@$SUBMODULE_GITHUB # add origin of the submodule
git fetch --depth=1 origin $COMMIT # fetch only the required version
git checkout $COMMIT # checkout on the right commit

# move the submodule from tmp to the submodule path
cd .. # go folder up
rm -rf tmp/.git # remove .git 
mv tmp/* $SUBMODULE_PATH/ # move the submodule to the submodule path

# clean up
rm -rf tmp # remove the tmp folder
Enter fullscreen mode Exit fullscreen mode

That's it! 🎉

Thanks for reading, hope it has helped you!
The full repo containing this solution is available here:
https://github.com/beeinger/vercel-private-submodule
If you have some ideas how to improve this solution or you'd like to implement the support for more than one submodule, let me know!
I'll gladly cooperate!

Top comments (1)

Collapse
 
artu_hnrq profile image
Arthur Henrique

All right, fair workaround strategy!
Thanks for sharing