middleman / middleman

Hand-crafted frontend development
https://middlemanapp.com
MIT License
7.05k stars 749 forks source link

Middleman won't reload helpers when helpers are edited (though it claims to reload itself) #1105

Closed lolmaus closed 6 years ago

lolmaus commented 10 years ago

When i edit a helper under /helpers/, Middleman says:

== The Middleman is reloading
== The Middleman has reloaded

But changes in the helper are not applied. I have to restart Middleman manually every time i edit a helper.

Tested on Windows.

Tuckie commented 10 years ago

This would probably better belong in https://github.com/middleman/middleman-livereload

Edit: Realized this is a just reload issue, not live-reload. Carry on...

duff commented 10 years ago

I'm seeing the same thing too. I tried middleman server --reload-paths=helpers, but that doesn't seem to cause changes to the helpers to be reloaded.

I was curious if anyone might know a way for changes to /helpers to get picked up when running locally.

bhollis commented 10 years ago

Yeah, middleman is already watching helpers, so adding it as a CLI argument won't help.

duff commented 10 years ago

Gotcha. Just to make sure I understand, when you say that it's watching helpers, does that mean that when a helper's code changes, it would get picked up without restarting the middleman server?

I wasn't sure if that was the expected behavior or if my expectations were out of alignment with reality. Or perhaps I don't have something configured correctly. Or maybe a pull request might help.

Oh - and I also noticed that there's more than one way to setup helpers. I'm referring to using modules approach referred to at the bottom of this page:

http://middlemanapp.com/basics/helpers/#toc_9

Thanks for the help!

lolmaus commented 10 years ago

Middleman is capable of noticing that helpers files were changed, but it's unable to make use of those changes without full restart.

tdreyno commented 10 years ago

Definitely a bug.

jackcasey commented 10 years ago

I'm seeing the same thing. To clarify I don't necessarily need live-reload for my custom helpers. Just having them update on a page reload would be really helpful.

jackcasey commented 10 years ago

Actually it'd be really handy to reload arbitrary ruby classes that I've manually included, but I understand that might be a bit out of scope.

fabrik42 commented 10 years ago

Actually it'd be really handy to reload arbitrary ruby classes that I've manually included

Same problem here. I'm using some Ruby libs that I placed in lib to create content in middleman templates. I was expecting a rails-like behavior (to reload changed files), because it recognizes the changes in the files:

== The Middleman is reloading
== The Middleman has reloaded

But it seems that it does not reload the files (needs server restart).

bhollis commented 10 years ago

The stuff Rails does to make this work is insane black magic. We don't do that (yet).

fabrik42 commented 10 years ago

Well, it seems that you already bundle the Padrino Reloader (which is able to reload Ruby files), but it is not used.

joallard commented 10 years ago

Is there a workaround for this? I can't upgrade to v4 because of #1380

Edit Rebased @themindoverall's patch over v3.3.6

gem "middleman", github: 'joallard/middleman', branch: 'reload_helpers'
tdreyno commented 10 years ago

This should be working on the official stable version.

zmoazeni commented 9 years ago

I am still having problems with helpers reloading properly with v3.4.0

tdreyno commented 9 years ago

Does the command line messaging show that "middleman is reloading"?

zmoazeni commented 9 years ago

Does the command line messaging show that "middleman is reloading"?

Yeah.

tdreyno commented 9 years ago

... does is ever say it "has reloaded"?

zmoazeni commented 9 years ago

Yes. It's very easy to reproduce given the steps I've listed on both 3.4.0 and 4.0.0.rc1.

The html reloads fine, but the helper code in /helpers does not reload.

zmoazeni commented 9 years ago

In the meantime, this is a very crude way to reload middleman when any ruby changes. (There are probably more elegant ways to do this, but it's what I ended up getting working)

# in the Gemfile
group :development do
  gem "god"
  gem "guard"
end

# in a new file named: middleman.god
# this will start middleman
God.watch do |w|
  w.name = "middleman"
  w.start = "bundle exec middleman server"
  w.keepalive
  w.log = "#{File.expand_path("..", __FILE__)}/middleman.log"
  w.dir = File.expand_path("..", __FILE__)
end

# in a new file named: Guardfile
# this watches for any ruby changes and tells god to restart middleman
# it would be nice to do this all with Guard, but I don't know enough about managing daemons in Guard
require 'guard/plugin'

module ::Guard
  class God < Plugin
    def reload
      reload_god
    end

    def run_on_additions(paths)
      reload_god
    end

    def run_on_modifications(paths)
      reload_god
    end

    def run_on_removals(paths)
      reload_god
    end

    private

    def reload_god
      `god restart`
    end
  end
end

guard 'God' do
  watch(%r{^.+\.rb$})
end
# start god first
$ god -c middleman.god

# then start guard
$ guard -i # you should be good to go at this point

# If you want to close down, CTRL-C guard and then run:
$ god terminate

You can also use guard-middleman which will rebuild the actual html every time something changes, but I just wanted to stick with the ruby server for now.

This is also handy because it will restart whenever lib/ changes

zslabs commented 8 years ago

@tdreyno Seem to be facing this issue still in 4.1.1. It says it reloads, but manual refreshes still show old code. Not sure if it helps, but get this message when trying to reload most times:

middleman.1 | /Library/Ruby/Gems/2.0.0/gems/middleman-livereload-3.4.6/lib/middleman-livereload/reactor.rb:14: warning: toplevel constant Mutex referenced by Thread::Mutex
tdreyno commented 8 years ago

Unfortunately, Ruby's require only reads the file the first time. There are ways to hack around this, but they are very invasive.

Are you requiring the files in helpers/ or is Middleman automatically doing that?

zslabs commented 8 years ago

Hey @tdreyno, I'm letting Middleman automatically pull them in; following the example in the docs, careers_helpers.rb has a module CareersHelpers definition.

tdreyno commented 8 years ago

Okay, I might be able to hack it in there :) Let me think about it.

zslabs commented 8 years ago

Cool - thanks for taking another look!

ryanburnette commented 7 years ago

I would love it if this issue were one day patched in both 3 and 4.

andreamoro commented 7 years ago

This is still an open issue on the most recent version of Middleman

fedegos commented 7 years ago

No solution yet?

codener commented 7 years ago

As @tdreyno wrote, require only reads files the first time. However, there is load, which just loads that file each time you call it.

Since config.rb is re-evaluated each time Middleman reboots, this will successfully reload helpers:

# in config.rb:

# Middleman fails to reload helpers, although it notices their modification
# This force-reloads them
Dir['helpers/*'].each(&method(:load))

If you have nested helpers, you need to adapt the glob string to something like 'helpers/**/*'.

ryanburnette commented 6 years ago

This was a game changer for me. Thank you so much!

jsoref commented 6 years ago

@tdreyno would it be unreasonable to add the blob from https://github.com/middleman/middleman/issues/1105#issuecomment-305715209 into: https://github.com/middleman/middleman-templates-default/blob/master/template/config.rb (as a comment)? (I'm happy to provide a PR if it's welcome)

andreamoro commented 6 years ago

I have completely missed the previous answer. Will the hack above apply also to Classes / Extensions? What if I have something like class SeoSupport < Middleman::Extension in the helpers folder and the following in the config.rb file?

require "helpers/seo"
activate :seo_support

In fact, also in the attempt to learn, I have created some classes (like the above) and some "wild" methods in individual files whose first line is method thisandthat. The latter however are never recalled with the require method. Am I missing something? @tdreyno

tdreyno commented 6 years ago

@jsoref I replaced require with load in our internal code and added some tests. It seems to work in the base case.

andreamoro commented 6 years ago

Still not sure how I have to reference my routines though.

tdreyno commented 6 years ago

@andreamoro In that case, I think you should switch require to load and place the file in lib. Helpers are specific to template helper methods and require a specific form (an exported module and pure methods)

andreamoro commented 6 years ago

@tdreyno ok, if for the classes I've to use a different way (do I need to create a lib folder, where?), Considering the helpers method are just within the helpers subfolder I'm literally missing where and when I should change the require to load.

Can you please give me more hints?

tdreyno commented 6 years ago

I would suggest always using load if you want their contents to reload on change. Ruby's require caches files, which we can't really control.

You can create a lib folder as a sibling to helpers. Those are the two paths watched by default for .rb file changes. The only difference is that there is a little additional processing that happens for files in helpers to inject their methods into the template context.

andreamoro commented 6 years ago

So, unless I'm mistaken, by creating a lib folder and moving all class files into it sound suffice. Correct?