One of the reason I am reluctant to add more API functions to the
phantom object is outlined in
http://code.google.com/p/phantomjs/issues/detail?id=41. Now, when I
start creating PhantomJS few years ago for my own uses, what I wanted
to do is running the script in the context of the web page. After
PhantomJS is launched, seems that what most people want (including but
not limited to testing use cases) is to able "control" the life time
and execution of a web page. IOW we want to run a "supervisor" script
that can fully control the "worker" web page.
If we start with an example first (and let's assume we already have
module support from
http://code.google.com/p/phantomjs/issues/detail?id=32), the code may
look like this (API names are subject to change):
var WebPage = require('WebPage');
var page = WebPage.open(url);
page.addListener("progressChanged", function (percent) {
if (percent >= 100) {
page.rasterize(outputFileName);
}
});
Obviously sometimes we still want to run a script in the context of
the page itself, e.g. to grab certain elements using selectors. This
means it is also necessary to transfer the data between the sandboxed
"worker" script back to the "supervisor" script (and vice versa). What
I propose in issue #41 is something similar to the WebWorker API, e.g.
message passing approach.
The outcome of this solution is that the worker script will never get
access to anything new (except the post message function, which is
harmless). Thus, we will have the freedom to extend the API of the
supervisor script to cover things like socket communication, file API,
etc etc.
Thoughts? Feedback?
--
Ariya Hidayat
http://www.linkedin.com/in/ariyahidayat
Most likely. Suppose we ignore the require/module support and don't
care about regressions, this is as easy as starting with creating a
WebPage QObject and add it to the window object. The said QObject
instance will have methods like open and signals like progressChanged.
It's too sad we have to wrap it in another QObject (as opposed to just
using QWebPage), but that makes easier to not suddenly expose every
single public methods in QWebPage.
QCoreApplication a(argc, argv);
if (argc < 2) {
fprintf(stderr, "*** you must specify a script file to evaluate\n");
return(-1);
}
QString fileName = QString::fromLatin1(argv[1]);
QFile file(fileName);
if (!file.open(QFile::ReadOnly)) {
fprintf(stderr, "*** failed to open `%s' for reading\n", argv[1]);
return(-1);
}
QScriptEngine engine;
QString code = QTextStream(&file).readAll();
file.close();
Console console;
QScriptValue consoleObj = engine.newQObject(&console);
engine.globalObject().setProperty("console", consoleObj);
QScriptValue result = engine.evaluate(code);
if (engine.hasUncaughtException()) {
int line = engine.uncaughtExceptionLineNumber();
std::cerr << "uncaught exception at line" << line << ":" << qPrintable(result.toString()) << std::endl;
}
exit(EXIT_SUCCESS);
#include <iostream>#include "console.h"Console::Console(QObject *parent) :QObject(parent){
}
void Console::log(const QString &message){
std::cout << qPrintable(message) << std::endl;}
void Console::error(const QString &message){
std::cout << qPrintable(message) << std::endl;}
Ivan De Marino
Front End Developer @ Betfair
Sent from my iPhone 4
Right now, the reservation I have is debugger support. There is a
stand-along Qt Script debugger Kent has built, but I would like to
leverage Web Inspector feature and provide a unified remote debugger
(see issue #6).
All is not lost. The advantage of easy of use, compared with the
current state of QtWebKit <-> native world, bindings will be there
once http://bugreports.qt.nokia.com/browse/QTBUG-11464 is solved.
If this would have been a non-WebKit tool, Qt Script makes a lot of
sense. In fact, with the automatic binding generator it's possible to
write any application, in particular GUI one based on Qt, entirely in
ECMAScript. I have demonstrated this, also please refer to Kent
Hansen's past blog entries on Qt Labs.
Right now, the reservation I have is debugger support. There is a
stand-along Qt Script debugger Kent has built, but I would like to
leverage Web Inspector feature and provide a unified remote debugger
(see issue #6).
var page = require("WebPage"),
inspector = require ("WebInspector");
inspector.attach(page);
All is not lost. The advantage of easy of use, compared with the
current state of QtWebKit <-> native world, bindings will be there
once http://bugreports.qt.nokia.com/browse/QTBUG-11464 is solved.
Once the script engine is unified, it's just the same thing whether to
use Qt Script or not. Qt Script just provides the convenient
wrapper/API.
> Remote Web Inspector? http://pmuellr.github.com/weinre/
Nothing to do with that (which is a nice workaround). But that's
different chapter.
> Still, the web inspector is built around a webpage: how hard would be to
> move that to a more general scope? The idea of generalizing PhantomJS,
> thinking of the webpage as a module, would make a "normal debugger" still a
> good idea. IMHO.
> Maybe we could start with normal "script debugging" and than the
> WebInspector could be a module. Something like
>
> var page = require("WebPage"),
> inspector = require ("WebInspector");
> inspector.attach(page);
>
> This would not only allow very cool code (come on, initialising an
> inspector like that would be really cool ;) ), but would allow to start
> coding, setting this as a future task.
Inspecting the web page itself is one thing, debugging the code that
does the above 3-lines is another thing.
> Do you think what's available today in QtScript is not good enough for our
> purpose?
As I said before, it won't allow us to have debugging support.
It's probably safe to assume that, if it would have been easy to make
headless WebKit as part of NodeJS, then I would have done that at the
first place. There are different technical challenges which need to be
solved first, if possible at all. If I am about to mention one, it's
because QtWebKit and Node will not share the same JS engine and
therefore it's impossible to share the context.
Don't get me wrong, I love Node and I use it for what it is intended
to be. The Windows support is getting better and recently becomes one
of the emphasizes of the project. However, I have delayed PhantomJS
long enough, it's not funny to not giving Windows users the full
support just because of that.
In other words, there is nothing really wrong with the Unix approach
of "Write programs that do one thing and do it well". You can do all
your crazy JavaScript processing with Node and when you are ready,
just feed it to/from PhantomJS.
I'm sure that all various technical challenges can be solved in time,
probably with the help of some experts out there. However, for those
who need various testing solutions using headless WebKit, PhantomJS as
it (and with upcoming improvements for 1.2, stay tuned), they can
already use it right now.
Thanks for the feedback.
Regards,
Ariya
Check also my recent WebPage refactoring. For passing from the web
page context back to the script, that's fairly easy using evaluate()
function. However, I agree that we may need message passing (see my
comment #5 at http://code.google.com/p/phantomjs/issues/detail?id=41#c5)
for the other way around.
Keep the feedback coming!
Thanks.
Regards,
Ariya