Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Running Vash on non-Node environments #39

Closed
UweKeim opened this issue Apr 28, 2014 · 9 comments
Closed

Running Vash on non-Node environments #39

UweKeim opened this issue Apr 28, 2014 · 9 comments

Comments

@UweKeim
Copy link

UweKeim commented Apr 28, 2014

After a whole day of trying to get Vash up and running in V8 within a .NET ClearScript application, I do have the following results:

  • It runs successfully for single-file-based templates.
  • It fails with error "Cannot call method 'normalize' of undefined" on a path.normalize call when using template includes through @html.include.

Even after debugging the Vash sources (through the Install Google Chrome Developer Tools for Java plug-in in Eclipse), I still cannot find a way to see what's going on here.

ClearScript

ClearScript is an implementation of V8 that runs "inside" a .NET application and makes binding to .NET objects from JavaScript easy and fast.

What I did

Since ClearScript is neither Node.js nor a browser, I created some .NET mockup classes for simulating e.g. the path or the fs variables.

Still, the above error.

I also tried to temporarily modify my local "vash.js" file but without any reasonable result.

My question

Do you think it is possible at all to use Vash in an environment that is neither browser nor Node.js?

@kirbysayshi
Copy link
Owner

So, vash itself will run in any environment that provides ES5 compatibility. But what you're running into is that the layout helpers need a way to load a file. And to do that they assume that either:

  • the fs and path modules are available to read files from the local filesystem and then cache it in vash.helpers.tplcache
  • vash.helpers.tplcache[TEMPLATEPATH] contains a compiled template (this is how it works in a browser)

So if you want to use another environment, you'll need to either:

  • prepopulate vash.helpers.tplcache with every template you'll ever need (I recommend this)
  • replace vash.loadFile with a method that can load files in your environment

@UweKeim
Copy link
Author

UweKeim commented Apr 29, 2014

Thanks, Andrew.

Since I actually do provide replacements for fs and path (at least I think so) and still see the error "Cannot call method 'normalize' of undefined" on a path.normalize call, I'm currently trying to find the reason.

Can it be that vash creates kind of "context" when processing a template that makes my global replacements for fs and path somehow disappear? Can this be related to your solution for #37 where you show me how to make the require available to templates?

@kirbysayshi
Copy link
Owner

How are you providing the replacements? Vash calls var path = require(‘path’), so if you’re just providing it as a global it’s going to
be overridden if the require call returns nothing.

Yip yip,
~ Drew*

On Tue, Apr 29, 2014 at 12:30 AM, Uwe Keim notifications@github.com wrote:

Thanks, Andrew.

Since I actually do provide replacements for fs and path (at least I
think so) and still see the error "Cannot call method 'normalize' of
undefined" on a path.normalize call, I'm currently trying to find the
reason.

Can it be that vash creates kind of "context" when processing a template
that makes my global replacements for fs and path somehow disappear? Can
this be related to your solution for #37https://github.com/kirbysayshi/vash/issues/37where you show me how to make the
require available to templates?


Reply to this email directly or view it on GitHubhttps://github.com//issues/39#issuecomment-41640753
.

@UweKeim
Copy link
Author

UweKeim commented Apr 29, 2014

That did it! 😄

I'm now putting the following snippet at the very first line before loading the "vash.js" content:

function require(name) {
    return host.require(name);
}

With host being my C#-provided mockup object that I add to the engine via:

_hf = new HostFunctions();
_engine.AddHostObject(@"host", HostItemFlags.GlobalMembers, _hf);

And in turn implementing HostFunctions like this:

public class HostFunctions
{
    public object require(string name)
    {
        switch (name)
        {
            case "fs":
                return new MockFs();
            case "path":
                return new MockPath();
            default:
                throw new Exception();
        }
    }
}

I'm not yet through this completely, hope it's OK to ask a further question below.

@UweKeim
Copy link
Author

UweKeim commented Apr 29, 2014

Last thing (hopefully):

I had to modify your sources. At 2 occurrances, I had to replace:

window['vash'] = vash

with

vashHolder = vash

That I defined before loading the "vash.js" content as:

var vashHolder = {};

Then I could call Vash with:

...
var tpl = vashHolder.compile(content);
...

The reason I had to do this was that the environment checks for AMD, NODSJS and BROWSER used the BROWSER case as a fallback which does not apply to my case.

My question

Is there a way to use Vash somehow like above without modifying your sources?

@meandmycode
Copy link

Really interesting runtime, I'd not seen ClearScript before.

I'll add my 2c to this, the hoops you are jumping through at the moment are that ClearScript allows you to execute JavaScript and bind between .NET, but ClearScript doesn't support CommonJS (which is probably a good choice to make at a low level).

Vash determines the exporting type by trying to feature detect functionality of each distinct module syntax, for Node.js style (CommonJS) vash checks to see if 'module' is an object and that is has an exports property (see https://github.com/kirbysayshi/vash/blob/master/build/vash.js#L17).

You have a few options, the easiest is probably to define 'window' as a global, vash will then fallback and export itself to window.

Alternatively you can aim to make ClearScript support CommonJS, this may have already been done before, but if not you'll want to define a global called 'module' that has an exports property that is an object.

After vash is has executed, the module.exports property will be populated.

Another thing that may help from the vash source side is not to assume the global object is 'window', but to export to 'this' from a function being invoked at the global level: http://stackoverflow.com/questions/7290086/javascript-use-strict-and-nicks-find-global-function

@UweKeim
Copy link
Author

UweKeim commented Apr 29, 2014

Thanks, @meandmycode I first tried to mock a window object but most likely I did something wrong on this, as I did not manage to make it working fully.

In addition the require calls are only executed when window is not defined, so this does not seem to be a solution for my case.

@UweKeim
Copy link
Author

UweKeim commented Apr 29, 2014

So my final question remains:

Is there a way to use Vash inside ClearScript (as described above) without modifying the sources of Vash?

@kirbysayshi
Copy link
Owner

@UweKeim, @meandmycode is right, the easiest thing for you to do is to just define a window as a global within your execution environment. I had never heard of ClearScript before today, but this was recommended via another thread:

_engine.Execute("window = this");

That should at least let vash export itself properly.

@UweKeim UweKeim closed this as completed May 8, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants