Skip to content
This repository has been archived by the owner on Aug 24, 2022. It is now read-only.

Building JavaScript #782

Open
iskiselev opened this issue Aug 5, 2015 · 6 comments
Open

Building JavaScript #782

iskiselev opened this issue Aug 5, 2015 · 6 comments

Comments

@iskiselev
Copy link
Member

Based on discussion in #780, #779, #356, #289, #522, #333, #100 I'm opening new issue to discuss how JSIL should work with JavaScript.
Js code that required to execute translated application could be grouped into several categories:

  • Translated user application and its dependencies - currently it is the only group that is processed by JSILc.exe
  • Hand-written implementation of BCL classes - mostly in Libraries\JSIL.Bootstrap.*.js
  • .Net VM JavaScript implementation and helper classes
  • Loader (JSIL.js and some part of other files).

It would be good, if finally JSIL will be able to do bundling/minification of all this *.js code, or provide clear instruction how end user can do it with external tool. So, it sounds reasonable to add processing of all other groups of *.js files inside JSILc.exe.
Note: We still need think how bundling/minification will coexist with #100, #333, end-user application plugin architecture.

Also we have a problem with Hand-written implementation of BCL classes - each BCL assembly could be Translated, Stubbed, Ignored - and each option requires different version of hand-written *.js implementation.

Probably, we could assembly translation mode inside manifest, so that loader will be able to select appropriate librarian *.js file - on other side we may move creating of such *.js file inside JSILc.exe translation logic (the more I think the more I option with writing correct manifest).

@kg
Copy link
Member

kg commented Aug 5, 2015

At the point where we've introduced the idea of having a build step generate the library .js files, a bunch of constraints are off the table.

For example, maybe the time is right to not hand-write the .js files at all, and instead have C# classes/proxies that contain raw JS when necessary. The proxies have accumulated a bunch of this already, in the form of JSReplacement and Verbatim. We'd probably have the distinction between 'inline' JS and JS that replaces a function body. Doing that would eliminate the hand-written implementation category, which is nice since that's easily the hairiest category.

The loader isn't a manifest but it's probably possible to narrowly scope what the loader is responsible for, roughly like how it is now. There's just some mixing of responsibilities, in part due to the goofy way the XNA stuff loads resources.

Ideally, like now you define a jsilConfig and then include JSIL.js, and the rest happens for you automatically. But the result of that becomes a simpler, more general process, where only the core loader infrastructure is imported, and the whole set of libraries is imported with manifests (which enables dealing with minified/combined/archived files). That potentially lets us express dependencies, too. Debug builds would easily be able to have a bunch of individual files, or at least a very simple set of combined files.

If we do manifest-per-assembly then translated/stubbed/ignored mostly influences which files go into that manifest and where those files come from. Many of them would probably just be copied from the builtin/default implementations.

This essentially needs to happen if bytecode ever becomes a thing (and I really want it to, since it solves many problems).

Would defining the raw JS implementations as C# functions in proxies be reasonable to you? Or is it too awkward compared to how things are now?

There's cough another C# -> JS compiler that took this approach and other than the awkwardness of having to invoke the compiler every build to update the compiled support libraries, it seemed to work pretty well. It makes it easier to write automated functional tests for the support libraries, too, which is nice.

@iskiselev
Copy link
Member Author

I very like idea of using only proxy assemblies instead of *.js implementations, with raw js if needed. I pretty sure that it will cover most cases. But right now we need to improve work of class proxies, probably add some more attributes. We will need discuss how some "Js raw" implementation will live in C# proxies - such as some helper method without strong types.
Also we need to think how we could translate data from proxies if we ignore assembly.
And we still need three groups of proxies on top of BCL assemblies - for Ignored, Stubbed, Translated case (Ignored and Stubbed may same proxy) - so we need to discuss how we will mange it.

@iskiselev
Copy link
Member Author

If we'll exclude BCL classes implementations in *.js files and will use proxy instead, additional benefit is compatibility of such solution with DCE. We can teach DCE work with proxy implementation, but DCE has no ideas about used types/members in raw .js files.

@Bablakeluke
Copy link

Hey guys, just a quick note to say absolutely wonderful work here and I'm looking forward to contributing towards this project in the future! On this, I'd like to suggest a bit of a different approach; something along the lines of the following (C#):

JS.Import("jsObjectName");

e.g:

JavascriptObject console=JS.Import("console");
console["log"].Run("Hello World");

Results in the compiler emitting:
console.log("Hello World");

Importantly the above is valid C#, potentially allowing JS and C# to get mixed fairly easily and directly "from anywhere" in the C# space. BCL methods could then be compiled into an ordinary C# DLL, within the types/namespaces that they are implementing. That DLL/ those DLL(s) could then be merged together with the mono ones, essentially replacing the methods found in the mono DLLs (i.e. mostly the extern ones). As for the compiler, it would need to look out specifically for these JS.Import calls, and emit them as the raw JS they represent.

Our goal is the ability to compile a CIL-like stream (WebIL) into JS, asm.js or WebAssembly(+GC) at runtime in the browser, so ideally the minimal size of the runtime is just the IL parse, the opcode->JS process and GC for asm.js/ WebAssembly. Everything else coming in as libs, with special opcodes in the IL for those symbol import calls as well as an opcode for emitting browser-specific code, which could be something as follows (C#):

if(JS.Exists("File")){
// File implementation here
}else if(JS.Exists("localStorage")){
// localStorage here
} // and so on

Those Exists calls being represented as a particular opcode, emitting 'true' or false, which essentially results in the whole thing shorting to if(true){} and would either be optimised out by the runtime or the underlying JS engine.

@iskiselev
Copy link
Member Author

@Bablakeluke, I already suggested something similar in #532, and we even discussed it with even approved by @kg, but for now I have some tasks with higher priority.
I think for further discussion #532 will be better place, but if you really need it and want to contribute - probably it is good task to start with :)

@Bablakeluke
Copy link

Brilliant ok, I've started on that; more information will be over in #532 shortly :)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants