Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
  • May 11 09:03

    janbiedermann on master

    update config for example and t… (compare)

  • May 11 08:43

    janbiedermann on master

    further readme split up (compare)

  • May 11 08:24

    janbiedermann on master

    fix travis config (compare)

  • May 11 08:21

    janbiedermann on master

    fix links (compare)

  • May 11 08:19

    janbiedermann on master

    exclude specs in fixtures clean up a bit corrections in readme and 8 more (compare)

  • May 11 06:09

    janbiedermann on master

    update branch for compilation t… add es6_modules_string branch t… (compare)

  • May 10 20:11

    janbiedermann on master

    let var be let (compare)

  • May 10 18:42

    janbiedermann on master

    add test to execute ruby with c… (compare)

  • May 10 17:18

    janbiedermann on master

    update doc for branches and PRs (compare)

  • May 10 13:00

    janbiedermann on master

    keep test_apps folder for tests (compare)

  • May 10 12:21

    janbiedermann on master

    simplify a bit spec add owl to dependencies test for 'public/assets' add te… and 2 more (compare)

  • May 09 21:53
    francescoagati closed #2
  • May 09 21:53
    francescoagati commented #2
  • May 09 21:47
    janbiedermann commented #2
  • May 09 16:02
    francescoagati opened #2
  • May 09 16:01
    francescoagati starred isomorfeus/opal-webpack-loader
  • May 04 02:19

    janbiedermann on master

    document file tree more accurat… (compare)

  • May 03 16:30
  • May 03 15:42

    janbiedermann on 0.7.3

    (compare)

  • May 03 15:41

    janbiedermann on 0.7.3

    (compare)

Isomorfeus Robot
@isomorfeusbot
[slack] <janbiedermann> its less automatic. To make it automatic, the component would have to keep track of all the possible things to be loaded and wait for the results to arrive. Hm, i have an idea ...
Isomorfeus Robot
@isomorfeusbot
[slack] <janbiedermann> for loading anything it would be:
preload do
  promise Whatever.returns.a_promise.here
end
Isomorfeus Robot
@isomorfeusbot

[slack] <janbiedermann> another improvement:

  preload do
    opereration 'MyOp', promise_run: { props: :as_hash }
    data 'MyGraph', promise_some_method: { props: :as_hash }
  end

This would lazy load those classes and call those methods on them with the props provided and waits for the promise to resolve and then renders.

Isomorfeus Robot
@isomorfeusbot

[slack] <janbiedermann> of course we make that preload thing universal, so we can do:

class MyGraph
  preload do
    data 'MyCollection'
    data 'MyOtherCollection'
  end

and so on. So we can keep the preloads, the lazy loads of other classes where they are needed. Otherwise the preloads would be required to happen all in a component for example.

[slack] <janbiedermann> and we make a promise_preload.then available, so it can be used in custom methods.
[slack] <janbiedermann> also a preloaded?
Isomorfeus Robot
@isomorfeusbot

[slack] <janbiedermann> in addition we turn the world upside down, so instead of:

components
lazy_components

we have

components # all lazy loaded
startup_components # all loaded at startup
[slack] <janbiedermann> something like that.
Isomorfeus Robot
@isomorfeusbot
[slack] <frédéric ZINGG> 😃 always good to turn the world upside down.
Looks like right, everything should be lazy loaded by default.
[slack] <janbiedermann> then we can create REALLY LARGE APPS .....
Isomorfeus Robot
@isomorfeusbot
[slack] <janbiedermann> ... and we must keep track of dependencies manually, but thats not hard, just must be done.
Isomorfeus Robot
@isomorfeusbot
[slack] <janbiedermann> That means then, that on the client, everything except startup_cpomponents and policies is lazy loaded?
[slack] <janbiedermann> hm... maybe
[slack] <frédéric ZINGG> not sure what you mean by POLICIES on client side ?
Isomorfeus Robot
@isomorfeusbot
[slack] <janbiedermann> All policies, in addition to being enforced on the server, are availalbe on the client so that you can make ui decisions, for example:
 if user.authorized?(MyGraph, :save)
   SaveButton()
end
[slack] <janbiedermann> and also i was on a short :walking: and i found a way around the requirement to preload.
[slack] <janbiedermann> but that needs a bit more time to implement.
[slack] <frédéric ZINGG> ha ok, remember, nice :thumbsup:
[slack] <janbiedermann> (and i am not 100% sure it works like i imagine)
Isomorfeus Robot
@isomorfeusbot
[slack] <janbiedermann> (well, can make it work anyway, but may break const_missing semantics)
Isomorfeus Robot
@isomorfeusbot
[slack] <janbiedermann> (no, would not)
Isomorfeus Robot
@isomorfeusbot
[slack] <janbiedermann> Oh my, i thought Hot Reloading for SSR for node would be extremely complicated, and in a way it is, but then i just added 5 lines ruby code and we have Hot Reloading for SSR in node in development. This way its easy to verify the actual components work in SSR.
Comes with a penalty though, hot reloading takes a tiny bit longer and it loads the whole asset bundle, so SSR is a bit slower. But thats ok, during normal development its not in the way.
[slack] <janbiedermann> ❤️ Ruby
Isomorfeus Robot
@isomorfeusbot
[slack] <janbiedermann> The automatic resolution of missing constants within render blocks would not work, because with webpack we need to know what we load, a component, a data thing, a operation, to get the webpack path for loading.
If we don't know, we would have to try all of them, possibly causing a large delay.
So with lazy loading everything, we must keep track of dependencies. Still thinking though, maybe there is another way to automate this.
Isomorfeus Robot
@isomorfeusbot
[slack] <janbiedermann> Ok, have a new idea, we can get help from the compiler, opal es6_modules_1_1 branch already has require_lazy , we could have a require_lazy_tree,
The compiler would do this:
For a require_lazy_tree "components":
  • create the dynamic import for webpack
  • collect all the filenames in dir and following autoloading convention create a global structure:
    { constant_name: [import_directory, file_path] }
    So for "components": `{ "MyComponent": ['components', 'my_component.rb'] }
  • at runtime, when that component cannot be resolved by the runtime or opal-autoloader, it will be resolved by the lazy loader.
  • lazy loader now has constant name and can look up the import directory and file_path and can delegate to the correct loader.
  • the correct loader will be created by require_lazy_tree, so for components for example there could be a globally accessible components_lazy_loader which will then be used.
  • now comes the problem, when at runtime the constant is loaded, its done asynchronously, so we cannot return the constant, because we dont have it yet, yet synchronous ruby demands a constant. here we need something to handle, a new rule, a new convention
  • this breaks ruby semantics, but we know that, so we can prepare, just the question how?
  • continue thinking ....
Isomorfeus Robot
@isomorfeusbot
[slack] <janbiedermann> maybe that doesnt matter so much, as all we need is the correct lazy loader, like the components_lazy_loader, the in the const_missing from within a component render block, we can trigger a later render once the constant is fully loaded.
[slack] <janbiedermann> Its a opt in.
Isomorfeus Robot
@isomorfeusbot
[slack] <janbiedermann> To make that useful, there must be a global lazy_load('MyConstant'), it can then be used in any class and returns a promise.
For isomorphic purposes that should be available on the server too, doing nothing, just returning the constant wrapped in a resolved promise.
[slack] <janbiedermann> with all that no need to manually keep track of lazy load dependencies anymore in component render blocks.
Isomorfeus Robot
@isomorfeusbot
[slack] <janbiedermann> But what about other lazy loaded classes like MyGraph?, then any class access must be wrapped in lazy_load('MyOtherClass'), still manually keeping track.
[slack] <janbiedermann> and making potentially everything asynchronous.
Isomorfeus Robot
@isomorfeusbot
[slack] <janbiedermann> and another problem, what about all those includes? These are all constants that demand immediate resolution ... so when a constant is lazy loaded, first the includes must be lazy loaded too, not sure how to do that, but that needs the compiler again. More thinking ...
Isomorfeus Robot
@isomorfeusbot
[slack] <janbiedermann> there is now a patch for opal, included in es_modules_1_1 branch, that defers evaluation of modules included with require_tree.
This takes of seconds from large apps boot processes.
Now, maybe, its possible to configure webpack to split the large app assets into smaller chunks that it can load on demand, maybe then we don't even need any lazy loading of code.
[slack] <janbiedermann> Ill play with webpack config a bit.
Isomorfeus Robot
@isomorfeusbot

[slack] <janbiedermann> webpack is not much helping here, but actually, es6_modules_1_1 already has everything needed to implement route based lazy loading, along with the preload and while_loading.

class MySubRouteComponent < LucidComponent::Base
  preload do
    require_lazy 'my_sub_route_entry'
  end
  render do
   ....
end

then my_sub_route_entry.rb would be like this:

require_tree 'sub_route', :autoload

and the Route Component from react router just would start MySubRouteComponent.

Thats it. Good enough for the moment. Can improve later on.

[slack] <janbiedermann> filesystem layout would be like this:
components
  my_sub_route_component.rb
  my_sub_route_entry.rb
  sub_route
     more_components_here.rb
     ...
  shared
     shared_components_here.rb
     ...
[slack] <janbiedermann> my_sub_route_component must be explicitly required, the rest not.
no require_tree 'components', but probably good to have one require_tree 'components/shared', :autoload_dirskip
Isomorfeus Robot
@isomorfeusbot
[slack] <janbiedermann> for the website this scheme above is implemented, using latest i-react 16.10.12.
(Not yet published, the website)
This scheme of lazy loading works, with a adjusted webpack config, specifically for SSR, SSR cant do anything with those chunks, chunks must be disabled in SSR.
[slack] <janbiedermann> But thats where the issues start, what to do with SSR?
SSR has all the code and can render the page, then the rendered page gets delivered to the client, and the client loads the code, throws the rendered result away, shows a 'Loading...' and then renders again ...
Isomorfeus Robot
@isomorfeusbot
[slack] <janbiedermann> :thinking_face: needs some info from server that its already rendered, so the client doesn't need to show the 'Loading ...'
But then, what about some other promise is resolved ..., not a code load ...
Basically, the preload is executed twice, once in SSR once on the browser.
If the browser got the data, lets say from a graph, delivered with the render, than the preload will resolve anyway instantly. So for i-data thats not an issue. For code load maybe i have a solution. Just for any other promise whos state is not delivered along with the SSR result, that case may have to be handled.
Isomorfeus Robot
@isomorfeusbot
[slack] <janbiedermann> well, trapped in a way.
If we render the preloaded content completely on the server, then, when that arrives on the client, we cannot execute the render block, because a constant may have to be loaded. So on the client the while_loading block must be executed until everything is preloaded.
[slack] <janbiedermann> no way araound it. That means, that lazy loaded content, meaning Constants, cannot be used in SSR. SSR will always render the while_loading block.
Isomorfeus Robot
@isomorfeusbot

[slack] <janbiedermann> easy fix, just setting Component.state.preloaded = true will initalize the state and prevent execution of the preloaded block a second time and render the complete page. This can be used to enable SSR for pages that dont need to preload dpending on context, like a user, like public pages.

  preload do
    something.then
      self.class.state.preloaded = true
   end
  end

first render shows the while_loading block, second render the render block. Good for search engines, but still, client will have to load anyway again.

Isomorfeus Robot
@isomorfeusbot
[slack] <janbiedermann> well, thats true for all instances of the SSR node vm. Well for now i would consider lazy loading and SSR not really practical.
[slack] <janbiedermann> Anyway, lazy loading, autoloading, opal performance in actions: https://isomorfeus.com
Isomorfeus Robot
@isomorfeusbot
[slack] <janbiedermann> Easy solution: provide a alternative loader.rb file for SSR which does not lazy load code and in the components prevent lazy loading of code in ssr by guarding it with on_browser?, for example.
Well, 2 loaders to maintain, but thats the way it works.
[slack] <janbiedermann> Not really a problem, as the ssr loader will just have require_tree s, so if components get added, nothing to do.
Isomorfeus Robot
@isomorfeusbot
[slack] <janbiedermann> Whoaa! 😲
Go to http://isomorfeus.com, open devtools, network tab, watch assets loading, now click on "Guides" at the bottom of the page, watch it lazy load in assets, click on "Development Tools" - NOW-
SHIFT reload the lazy loaded page and watch it Server Side Rendered, lazy loaded and rendered WITHOUT a blink or a flash, absolutely seamless ... absolutely smooth ... 😎

[slack] <janbiedermann> This is enabled by the new:

  while_loading :except_ssr do

not the :except_ssr, it prevents the while_loading block from running in SSR and instead renders the normal render block and at the same time, configures a few things for the Component, so that if it is loaded via SSR it absolutely smooth, if its not loaded via SSR it shows the while loading block.

[slack] <janbiedermann> ( 🕶 )