jonstavis's avatar

Using Elixir versioning with Git

Can anyone recommend a best practice for committing versioned Elixir build files (each new file with a new name) to a git repository?

for example

public/
├── build
│   ├── css
│   │   ├── app-1d254907.css
│   │   └── app.css.map
│   ├── js
│   │   ├── all-1eae52c4.js
│   │   └── all.js.map
│   └── rev-manifest.json

When you delete a file from git the refs to that file still stick around your repository forever. With even a moderately sized static asset file, your git repository could grow pretty large with references to old build files after many small changes to your css/js.

If it is not recommended to commit build files to git, what is the best practice for deploying versioned assets? I'm not crazy about running gulp on a production server.

0 likes
24 replies
sdbruder's avatar

Dont commit.

They are 100% generated and can be re-generated as you see fit or need, there is no need to commit them.

4 likes
jonstavis's avatar

Thanks for your response. How would you push them to your production server if you didn't commit?

mhankins's avatar

@jonstavis I usually run gulp on production, but it does mean you have to install it on the server. I'm not sure if that is best practice, but it ensures my new assets get copied over.

jonstavis's avatar

I'm having a problem wrapping my head around this and it seems really opposite to the "Laravel way" that you would have to choose between committing a new > 100k file (L5 ships with bootstrap) for every minor CSS change you make vs. running a javascript build tool on a production server. Further, the build folder is not referenced in the shipped .gitignore file, suggesting that the creators want this folder committed.

It feels like there was an architectural decision made to make static asset filenames unique vs. using a query string to prevent browser caching. Is there an advantage to the former that outweighs my above two stated (both not so great) options?

Drfraker's avatar

I have the exact same question. Having these files update with each change seems odd. @JeffreyWay , would it be possible to have the elixir() function just increment a query string on the end of the file instead of changing the actual file name? Then it would bust the cache but not have git need to track all of these deleted and re-created files. Just a thought I'm sure there is a reason why that wouldn't work. Seems too simple...

2 likes
sietzekeuning's avatar

I'm very curious to know this as well. Having these files recommitted on every change seems wrong as does running the build tool on production. So what to do?

1 like
jonstavis's avatar

Bump.

@JeffreyWay (or anyone else), I'm really curious if there is an easy workaround for this or if versioned query strings as opposed to new file names could be a consideration for a new Elixir feature.

Thank you!

bashy's avatar

[This is old and you probably shouldn't do this]

On an old app, I had a production gulp function to do simple stuff when pushing. That way I could exclude the build folder totally within the .gitignore file.

Query string shouldn't be needed, I can even manage that in CloudFlare (if required)

1 like
jonstavis's avatar

Thanks for that suggestion @bashy I do realize that a lot of folks are running gulp on production servers. I and a couple others on this thread would prefer not to do this, and that's what we're inquiring about.

1 like
jcsarda's avatar

I have an application that hasn't been launched yet. For now, my staging server is regenerating the files after every new CI deployment, but I also commit all of my assets to my repo because of the fact that these elixir directories are not already in the gitignore file. I figured if they wanted them ignored it would be in there. But, this is no longer the way I'm going to do things.

I think the best way to handle this is to have my development box (homestead) generate them throughout development, but gitignore all of my generated assets to prevent a messy commit history with little changes to the assets along with every design related commit.

Then, upon deployment to staging, I will let my staging server generate them during my Development -> Staging deployment. So Gulp will only be installed on my staging server where the "production-like" testing is done.

Then, copy or rsync the "public/build" directory as part of my Staging -> Production deployment workflow.

aditya-cherukuri's avatar

We came down to that if something happened to our gulp on prod we would be screwed and scrambling to fix it and get our prod push up and running. So we decided to check it in. Id say its the lesser of 2 evils but im not so sure its quite annoying if you work on a large team and have to git chekcout --theirs and then run gulp before you commit again.

Drfraker's avatar

I was asking about this almost a year ago and it has a lot of people wondering what to do. I'm surprised that @JeffreyWay has not chimed in to let everyone know the "best practice" way of doing this.

I think a better way to handle versioning would be to have the elixir function generate a unique query string hash dynamically for each version of a file based on the server environment when the page is generated. That way we could achieve the same result without having a repository change at all. Is there a reason that I'm missing that makes that impossible?

JeffreyWay's avatar

@Drfraker - I commit versioned files, and do not run Gulp on production. I have no problem with it, but just... don't. As @aditya-cherukuri noted, if something happened to go wrong or error out, you'd be scrambling to fix it. Or at least rolling everything back. I'd rather everything be ready to go when I do the commit.

3 likes
JoshMountain's avatar

@JeffreyWay Do you run into constant merge conflicts when working with other devs on the same project? I feel like I am doing something wrong by committing these build files.

3 likes
erikverbeek's avatar

I was looking into this issue today and seem to have come up with a decent workflow for myself.

I found this little plug-in npm-laravel-elixir-gitadd. It let's you automatically add the changes to the build folder to your Git repository.

This let's me compile the files, create the versioned files and add them to git. They get renamed in git with every compile.

The only thing that I'm not too happy with is that I now have 3 versions of every script. One in assets to work with, one in public/js which is only used to to create the versioned files and the one in build/js that actually gets used. If anyone knows how to compile and version from assets directly to the build folder, I'd love to hear how.

I am the only developer on this project so I don't know if this might create a lot of conflicts if you're working with multiple people on the same repository.

gulpfile.js example:

var elixir = require('laravel-elixir');

require('laravel-elixir-gitadd'); 

elixir(function(mix) {

    mix.sass('app.scss');
    mix.browserify('script1.js');
    mix.browserify('script2.js');
    mix.browserify('script3.js');

    mix.version([
        'js/script1.js',
        'js/script2.js',
        'js/script3.js',
    ]);

    mix.gitadd('public/build');

});
1 like
richpeers's avatar

I'm very tempted to the leave node_modules folder away from the production server, and in contradiction to a lot of the above comments, commit the new public/build folder with the changes that come with it - its a large part of the front end anyway, so any commits are already pre-compiled by elixir.

Also, there's just so much unknown rubbish buried in those node_module folders!

jonstavis's avatar

I've been back and forth over the last year since originally posting this thread between using elixir version() and using a variation of this package which retains the same build file every build but tacks on a url parameter for cachebusting: https://github.com/Gercoli/laravel-elixir-cachebuster

I'm fine with going either of these routes, and I'm reassured by @JeffreyWay and others agreeing that committing built asset files is the way to go....... however, with both variations (Elixir version() and cachebuster package) I'm constantly running into merge conflicts in these build files when myself or someone else on my team needs to merge to commit or merges a PR.

Our current workaround is to

  1. Stop gulp
  2. Do the merge- get conflicts
  3. Delete everything in the public/ and public/build folders
  4. Restart gulp
  5. git add -A

Anyone else run into this and have any ideas or recommended workflows?

Thanks!

erikverbeek's avatar

@jonstavis The gitadd package I mentioned in my previous post does exactly the same thing automatically.

It deletes the previous build files and adds brand new files with a new randomized sequence in the filename.

This way git won't try to merge them and the browser will always recognize it as a new file to be downloaded instead of used from cache.

1 like
ejdelmonico's avatar

I always commit versioned css and js files. Elixir deletes the old version when you compile again so no worries. If you are using {{ elixir(css/app.css) }} and the same for JS...no problems. It works well for me and I can always glance at github to make sure I am on the correct file versions.

Presto's avatar

I thought I would chime in with my two cents, I too was in the same boat, working on a team using git version control, we were running into issues with multiple files getting tracked by git every time someone would check in a new build.

I ended up going with Laravel Elixir Git Add, I wrote a blog post about Our Setup / Tutorial, for anyone else running into the same problem.

jekinney's avatar

When I work with a team we generally have a master where project manger only has access. A dev branch for a development/testing server. Then other branches from dev branch as needed.

The gulp file has version commented out and when a all the commits are merged and tested in the dev branch, then the project manager merges the dev into master. Seeing you have to check out master anyways takes a minute at most to uncomment the version and run gulp --production locally. Commit and push. Done. Then check out div branch and keep working.

KeitelDOG's avatar

It's my first experience with Elixir and I just want to combine and minify css and js for the moment. I have a Staging server like the Production and I use Git. From my experience I stay away from unstable packages as much as I can, and I consider npm and gulp can give me unexpected results if I have to update them. So I want to stay away from running Gulp in production. But I haven't noticed a good flow to handle this with git with multiple devs.

KeitelDOG's avatar

I don't like gulp in production, neither the new files in build incrementing in my git. I'm looking for a way to just bypass the elixir version:

  • build will not be tracked
  • I will use the public/css files only in the stylesheets links
  • for css and js version I will continue to use my old GET parameter version ?v=1.2.3
  • public/css is already tracked by Git

So I guess the same css file will be tracked line-by-line by Git for every developer.

pk28's avatar

@JEFFREYWAY - Hi Sir, how do you avoid merge conflicts in compiled files ? I would like to know. I'm currently facing same problem. And i don't want to compile my files on production server. I've gone through every discussions related to this issue and almost every related tutorial but can't find proper workflow . If you've any tutorial that i'm missing or if you can provide your solution . I will really appreciate that. Thank you.

Please or to participate in this conversation.