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

JS entry point for apps, make it possible to load resources async #17169

Closed
PVince81 opened this issue Jun 25, 2015 · 21 comments
Closed

JS entry point for apps, make it possible to load resources async #17169

PVince81 opened this issue Jun 25, 2015 · 21 comments

Comments

@PVince81
Copy link
Contributor

PVince81 commented Jun 25, 2015

The fact that currently app's JS code can do "whatever they want" makes it impossible to load resources asynchronously like translations or mimetypes. This leads to workarounds like having a generated JS file that can be loaded with addScript() instead of on-demand / with ajax.

One solution to think about would be to provide entry point hooks for apps.

An app's JS code should then register itself: OC.App.register("My app", myAppClass).
The myAppClass would then have a method init() that will be called asynchronously after all async resources are ready.

Note that this is not only about the currently visible app. Multiple apps can register their JS code at the same time, like file viewers (FileActions) when the file action is visible, etc.

So it's a matter of providing a single entry point for apps.

@DeepDiver1975 @rullzer @Raydiation

@PVince81 PVince81 changed the title App JS code must run asynchronously JS entry point for apps, make it possible to load resources async Jun 25, 2015
@PVince81
Copy link
Contributor Author

Note: the files app and other core apps already use a similar mechanism with OC.Plugins.register().
For example https://github.com/owncloud/core/blob/master/apps/files/js/favoritesplugin.js#L115

Additionally there is also the complexity of having apps using APIs of other apps.
For example the PDF viewer app uses the FileActions API from the files app to register its action.

The files_sharing app extends the FileList class provided by the files app, to be able to display a list of shared files.

So this isn't only about a single app.

@DeepDiver1975 DeepDiver1975 added this to the 8.1-current milestone Jun 25, 2015
@DeepDiver1975
Copy link
Member

Can we have this for 8.2?

@DeepDiver1975 DeepDiver1975 modified the milestones: 8.2-next, 8.1-current Jun 25, 2015
@PVince81
Copy link
Contributor Author

Yes, we can have the discussion during 8.2.

Regardless of the solution, it will be incompatible with any existing apps. So the hardest part would be to find a way to provide a fallback.

@DeepDiver1975
Copy link
Member

Regardless of the solution, it will be incompatible with any existing apps. So the hardest part would be to find a way to provide a fallback.

From my understanding it more of that kind:
In case an app registers a init callback we call it - if not we simply don't?

Non of the existing apps as of today has such an init mechanism - and if it should continue to work - right?

@PVince81
Copy link
Contributor Author

Yes.

It is more about using APIs that require async loading of stuff, but using them in a non-async manner.
So let's say if we do @rullzer's mimetype change but load JSON asynchronously, but provide a method OC.Mimetypes.getIcon() without callback or promise, then if an app calls OC.Mimetypes.getIcon() too early, they won't get any result. However if they call it inside the init() method (which we call afterwards), they'd get results.

So as long as old apps don't use such APIs, they should be fine.

This means as soon as we want to introduce such APIs that require async load, the init() mechanism needs to be ready too.

This will also be needed to be able to get rid of the ".js" translation files eventually.

Apart from translation, I can't think of any other API that would affect old apps right now.

@BernhardPosselt
Copy link
Contributor

What about using a proper module loader instead of reinventing the wheel?

@PVince81
Copy link
Contributor Author

Yes, but the module loader should not be imposed onto app developers.

So far the design goal seemed to be that app developers can use whatever frameworks they want, so whatever solution we find here must be compatible.

In past projects we used requirejs but I don't think it would fit well. If we do, it means app developers need to define their classes as AMD classes.

Do you know any others that could fit better ?

@oparoz
Copy link
Contributor

oparoz commented Jul 4, 2015

I'm with @Raydiation. Custom sauce is going to increase the complexity and the maintenance level of the project. Educating devs into using a loader is going to have long term benefits for a relatively small price to pay in development time.

@BernhardPosselt
Copy link
Contributor

BTW, stumbled over https://www.youtube.com/watch?v=NpMnRifyGyw which shows how jspm works, his examples are in ReactJS but ignore that ;)

How jspm works is that it basically does not care which module system you are using.

Just take a look :)

@BernhardPosselt
Copy link
Contributor

Another thing: tons of JS libs and transpilers are not compatible with IE8, can we defer this until IE8 support is dropped?

@BernhardPosselt
Copy link
Contributor

I don't want to use the worst hacky solution just to be compatible with IE8

@PVince81
Copy link
Contributor Author

PVince81 commented Jul 6, 2015

jspm looks cool (as is systemjs on which it's based on).

I still wonder whether it loads the scripts asynchronously.
One tricky issue with JS is that if you don't load the scripts through script tags in the header, you have to do asynchronously. And if you do async, your JS code needs to be async-compatible and not try and execute things in the main thread (body.onload or $(document).ready()) but rather react on events.

It seems that async-compatible code is inevitable. Well, this would be the correct way to code anyway. So most importantly the module loader needs to be somewhat backwards-compatible with the old legacy non-async-compatible code.

Then is also the question of what happens with all the addScript() and co, whether we still want them or only have a single one to load the jspm bootstrap ?

And another point is whether the module loader in question is compatible with the asset pipeline or have some means of concatenating/minifying the modules for faster loader. I'm pretty sure they all have such means, we just need to look into it and try it out.

Also the question whether we can make it load resources like json files (translations), CSS (probably) before other modules are loaded.

And then build a POC based on a few core JS files and a few JS files from the files app 😄

@PVince81
Copy link
Contributor Author

PVince81 commented Jul 6, 2015

Well, I guess the old addScript() code can continue living and jspm loading would be optional for use by apps, which means apps can still decide to load their JS code statically with addScript().

But this means that if we made core use jspm by default, any app that depends on core code (ex: the whole OC namespace) would require a way to wait for it to be loaded. If an app is not async-compatible, that would be impossible.

So at first I guess we could only add jspm (or any other module loader) to apps like files, files_sharing and co, but not the core JS code.

@PVince81
Copy link
Contributor Author

PVince81 commented Jul 6, 2015

unless... we add some magic. Apps usually add their scripts with addScript(). So if instead of adding script tags, we generate a "bootstrap.js" script for apps and have that script use jspm to require every file that was specified in addScript(), that could work ?

@BernhardPosselt
Copy link
Contributor

As for backwards compatibility: Starting with IE9+ you can use JavaScript getters and setters (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get) to override attribute access which could let us polyfill old APIs as needed.

@PVince81
Copy link
Contributor Author

Moving this tricky topic to 9.0

@PVince81 PVince81 modified the milestones: 9.0-next, 8.2-current Sep 22, 2015
@PVince81 PVince81 modified the milestones: 9.1-next, 9.0-current Feb 12, 2016
@PVince81 PVince81 removed this from the 9.1-current milestone Jun 15, 2016
@PVince81 PVince81 modified the milestones: 9.2-next, 9.1-current Jun 15, 2016
@PVince81 PVince81 modified the milestones: backlog, 10.0 Jan 27, 2017
@PVince81
Copy link
Contributor Author

Potentially relevant discussion if we were to use webpack for core and for apps: webpack/webpack#118

@PVince81
Copy link
Contributor Author

Another worry I have is whether an app's webpack modules would be able to "extend" (in the JS subclass way) classes from the core module. This would require the app bundle to know about the core bundle.

@PVince81
Copy link
Contributor Author

more here https://stackoverflow.com/q/43163909, seems someone got it to work

@PVince81
Copy link
Contributor Author

PVince81 commented Jun 7, 2018

Obsoleted by Phoenix which will come with its own redesigned app loading logic: owncloud/web#2

@lock
Copy link

lock bot commented Jul 30, 2019

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked as resolved and limited conversation to collaborators Jul 30, 2019
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

5 participants