skeeto / skewer-mode

Live web development in Emacs
The Unlicense
1.1k stars 57 forks source link

I couldn't get Skewer-HTML do the same as impatient-mode. #58

Open ReneFroger opened 9 years ago

ReneFroger commented 9 years ago

Thanks for sharing this package, your work is really appreciated. I loved the impatient mode. It remembers me sort of Browserlink for Vim.

Around half year ago, I couldn't get Skewer working so I gave it up. When I tried impatient-mode, I thought I needed to develop a package, so I asked some questions about the structure in this topic.

However, someone attended me on skewer-mode, so I decided to give a second try. But I couldn't get it working again. I decided to open a issue, even when I'm not sure if it's related to Skewer or me. So could you perhaps tell me what I'm missing yet?

Setup:

GUI version GNU Emacs 25.0.50.1 (x86_64-w64-mingw32) of 2015-07-25 on KAEL Compiled from wemacs-w64. skewer-mode, using the latest version of skewer-mode from MELPA Windows 7 x64 bit.

Actions:

I create a page, called foobar.html. The web-mode is the major mode for that buffer. In the browser I see the page foobar.html inside the environment http://intranet-development/app/foobar.html.

When I change something in buffer foobar.html, save it, then refresh the browser, I see the changes. I would like to make it interactively.

  1. In the buffer foobar.html. I press M-x httpd-start. Then I check the values of httpd-port with C-h v. The values are 8080. Then I call M-x skewer-mode.
  2. When I open in the browser the following URI: http://localhost:8080/skewer, then I see javascript code from Skewer, version 1.4. So the HTTP-server with skewer seems working.
  3. I paste in foobar.html the following code:

    <!DOCTYPE html>
    <html>
    <head>
       <title>Skewer</title>
       <script src="http://localhost:8080/skewer"></script>
    </head>
    <body> Testing 123
    </body>
    </html>

I save foobar.html, and reload the browser. I see the sentence Testing 123 in my browser. When checking the source code, I see the script source of skewer. When clicking, I see the javascript for Skewer.

  1. I call M-x skewer-html-mode. And it's enabled in the buffer of foobar.html.
  2. When change the sentence of Testing 123 to Test 1, I call skewer-load-buffer, but I don't see anything changed in my browser. I called every skewer function, but without any result. When I press f12 inside Chrome, I type in the console skewer();. But I get the message undefined.

So I guess I could paste the content of /skewer javascript into

<script>
[entire content of /skewer here]
</script>

But I'm not sure about that, because I don't understand what went wrong here. I would like to have the same functionality from Impatient mode, see changes that you type in your buffer directly in your browser, but now on another server than the localhost:8080.

I guess Skewer is able to do that, but I couldn't figure out how get working. Which commands or actions do I need yet to make it 'live' as in impatient-mode? By the way, I really appreciate all the work you did for the community. I enjoyed your auto-tetris mode. :+1:

ReneFroger commented 9 years ago

@skeeto I wonder if there might be any update on this thing? And I appreciate all your work that's done, by the way.

skeeto commented 9 years ago

It's not documented properly, but skewer-load-buffer only works for JavaScript (js2-mode buffers). In short, if it doesn't start with "skewer-html" then it's not intended for use in skewer-html-mode. By default in skewer-html-mode, you need to "evaluate" some element in the page and the structurally matching element (e.g. "the fourth div under the second article under body") will be replaced in client page. By design, the result of this should be obvious and unsurprising. As a caveat, you cannot "evaluate" the top-level elements -- html, head, and body -- because browsers currently do not allow these elements to be replaced. I bring that up because updating the whole page at once by evaluating these tags is an obvious idea, but it doesn't work.

Skewer isn't really intended for automatic interactive use, in part because there are different ways to achieve it, each with its own trade-offs and problems. You could send a refresh page command (location.reload()") to the page on every change (e.g. after-change-functions), but that will certainly have problems depending on what you're doing. Anyway, that's exactly how impatient-mode works, so you may as well use that instead of skewer-html-mode.

Finally, if you want to check if the page is properly connected as a client, look at M-x list-skewer-client and/or eval an alert() in a js2-mode buffer.

ReneFroger commented 9 years ago

Thanks for your well written reply, I appreciate it.

As a caveat, you cannot "evaluate" the top-level elements -- html, head, and body -- because browsers currently do not allow these elements to be replaced.

Clear enough. But why am I able to edit the contents of the body-tag, and see them replaced in the browser with impatient-mode?

And there is a reason why I couldn't use Impatient mode. See also this issue for explaination. So that's why I tried out skewer, after a recommendation from another user. What are the current restrictions to get impatient-mode working with pages that are located on other servers, instead the Emacs HTTP server?

skeeto commented 9 years ago

impatient-mode works by refreshing the entire page on each update. This has the side effect of losing page state (JavaScript variables, some form fields, etc.). That's the trade-off. Since impatient-mode is intended for static content, this usually doesn't matter. I didn't want this for Skewer because it's intended for use in conjunction with skewer-mode and skewer-css-mode, where refreshing the page would likely lose important state.

If I understand you correctly, you want to visit an arbitrary page on the web in your browser, connect Emacs to it via a Skewer-like mechanism (bookmarklet, etc.), view the page's HTML-serialized DOM (not the original source, since it may have changed!) in a buffer, and manipulate this HTML live just like impatient-mode. Skewer currently gets you all the way to that last part. You can serialize the structural part of the DOM with skewer-html-fetch-selector-into-buffer (but not JavaScript state, such as event listeners, since these cannot be serialized or even accessed), edit it, and evaluate elements that you want updated. To get live updating, you would need to hook after-change-functions to evaluate the currently changing element. Then you're just stuck with the problem we're already discussing: Due to current browser restrictions, it won't work if you're directly inside a top-level element (html, head, body). That requires a refresh, but the refresh will match it up with the original server's content, not Emacs' content.

ReneFroger commented 9 years ago

Thanks for your clear answer. I will figure it out tommorow on my work, and update it to you.

Not related to this issue by the way, but this seems also interesting for you, in the line with impatient-mode and skewer.

ReneFroger commented 9 years ago

With the skewer-html-fetc-selector-into-buffer, I need to fill in which 'Selector' I want to use. Guessing what this means, I thought it asked a element. So I filled the ID-name of a HTML element, like #foobar.

But nothing happens. I found nothing in the documentation about this. The page that I'm testing is running on a XAMPP stack.

skeeto commented 9 years ago

As a caveat, it doesn't actually include the tags of the selected element itself. (This is probably a mistake and perhaps should be fixed.) You probably want to select #foobar's parent element. Also, just a heads up, skewer-html-fetch-selector-into-buffer is still a little flakey and I'm not sure if anyone ever uses it, so there dragons here.