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

Thoughts: ES6 integration features #63

Open
IngwiePhoenix opened this issue Oct 27, 2015 · 3 comments
Open

Thoughts: ES6 integration features #63

IngwiePhoenix opened this issue Oct 27, 2015 · 3 comments

Comments

@IngwiePhoenix
Copy link

This is not really a proposal, but rather a bit of an idea that I had.

While working with OJ, I had faced, back and forth, the issue of how to share classes. Since I use OJ mainly on the client using WebPack and my transformers/loaders, I would always have to somehow get the various files to come together.

My current aproach is to use a custom preprocessor to build my code. It works like the C one, but for OJ.

Since we are nearing proper ES6 support, I had something like this on my mind:

@implementation Foo
// ...
@end

export default Foo;

and

import Foo from "classes/Foo.oj";

@implementation Bar : Foo
// ...
@end

The options we have for implementing this:

  • If we find an export statement, the following class-name should be treatened as if we'd called [ClassName class].
  • We create an @-macro for ex-/importing classes

However, OJ currently knows of the files "statically", as it comes from the array of files. So, when we find an import statement, we should consider adding that file to the files list and dropping the statement alltogether. Result:

@implementation Foo
@end

// removed: import FooClass from "Foo.oj";
@implementation Bar : FooClass
@end

The JavaScript of this "import" would be something like

var $oj_cls_FooClass =  $oj._cls.Foo;

That would, onc eagain, require us to read the AST and generate a changed statement for what used to be an import atatement.

One example which would be very close to my project's workflow:

import BIRD3Editor from "BIRD3/Extensions/MarkdownEditor";
// snip
@implementation App
-(void)run {
    if($("body").find("[data-editor]").length != 0) {
        var editors = $("body").find("[data-editor]");
        for(var i = 0; i<editors.length; i++) {
            [BIRD3Editor initWithElement:editors[i]];
        }
    }
}

These are only thoughts, so feel free to ignore this if you wish to :). I just thought I'd share what I had in my mind.

@iccir
Copy link
Member

iccir commented Oct 27, 2015

While working with OJ, I had faced, back and forth, the issue of how to share classes. Since I use OJ mainly on the client using WebPack and my transformers/loaders, I would always have to somehow get the various files to come together.

I still haven't quite grasped the issue of sharing classes. What we (both my company and my friend's startup) do is concatenate all .oj files together and compile as one unit. We have a file watcher in place, as soon as an .oj file is modified, it spits out a new webapp.js file with the compiled contents. Remind me again why this doesn't work in your case? (You can use your preprocessor to figure out which files to include, and then compile all files at once).

In the above example, All you should need is some kind of #import BIRD3/Extensions/MarkdownEditor. Your preprocessor would see this, add MarkdownEditor.oj to the compile list as a requirement for App.oj, and know to compile both in the same compilation unit.

@IngwiePhoenix
Copy link
Author

I still haven't quite grasped the issue of sharing classes. What we (both my company and my friend's startup) do is concatenate all .oj files together and compile as one unit. We have a file watcher in place, as soon as an .oj file is modified, it spits out a new webapp.js file with the compiled contents. Remind me again why this doesn't work in your case? (You can use your preprocessor to figure out which files to include, and then compile all files at once).

To build my front-end code, I use the WebPack bundler. To bundle files, it scans the input for any require - and now import - statement and picks up what it reads. That way, it traverses through the entire code by picking up these statements, makes a list of files, and bundles them into an environment that mimics NodeJS - or, commonly known as "CommonJS". It also supports the AMD specification, but that one is rarely used. WebPack also supports asynchronous require calls - but in the end, it all boils down to the fact that multiple files get put together into one.

However, for this modular aproach to work, it wraps all the modules into a function and assigns it an ID. For instance:

function(module, exports, __webpack_require__) {
    // module code
}

All the require statements get translated to become __webpack_require__ statements instead. So what once was

var oj = require("oj/src/runtime");

could become:

var oj = __webpack_require__(2);

As you can see, with all the OJ code being wrapped per-function, I believe you can see what issues it proposes. The classes do indeed get registered into the global $oj_oj object - however, if webpack decides to put the required module code below the one that needs it, the class would not be defined.

That is why I built a C-style preprocessor to put the files together, while still being able to utilize WebPack - which has many other features. For instance, I can litterally require a SCSS file, and it'll get transformed into CSS and split into a different, global CSS file. This also works with other file types. My OJ loader does the same - it compiles OJ code and returns it to WebPack. The compiler state is attached to WebPack's, so that it can keep track of classes and alike. It works pretty well. But importing and exporting - or generally, sharing classes across modules opposes a strange behaviour sometimes.

Because: OJ actually may not know of a class during compilation.

That is the kind of problem I have, and why I built custom tools to tackle it. :)

I could add the #import directive, indeed - and I might do that, since my re-structure of the codebase also affected the OJ files.

@IngwiePhoenix
Copy link
Author

I should add, that the following code does not work in a RequireJS/CommonJS environment.

Foo.oj

@implementation Foo
+(void) doIt { console.log("Doing something..."); }
@end

App.oj

require("oj-node"); // Allow .oj files to run
require("./Foo.oj");

// This will fail: Foo not defined
[Foo doIt];

// But this, will work.
@class Foo;
[Foo doIt];

However, module.exports = [Foo class]; will actually work.

var Foo = require("./Foo.oj");
[Foo doIt];

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

2 participants