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

Lazy Loading Route-less Engines #232

Open
ghost opened this Issue Oct 25, 2016 · 13 comments

Comments

Projects
None yet
8 participants
@ghost

ghost commented Oct 25, 2016

I don't think this feature has been implemented / tested but I'll go ahead and log an issue for tracking. Lazy-loading non-routeable engines is not working. The assets are never loaded and as such are not registered...

I end up with this error "Assertion Failed: You used {{mount 'nonrouteable'}}, but the engine 'nonrouteable' can not be found.""

@trentmwillis

This comment has been minimized.

Member

trentmwillis commented Oct 25, 2016

Yeah, this hasn't really been considered yet. I think the primary question was how to handle the fact that the mount point will render asynchronously. Once that is determined, we just need to identify where we in that lifecycle we initiate the request to load the Engine assets.

@ghost

This comment has been minimized.

ghost commented Oct 25, 2016

That makes sense. Thanks

@trentmwillis trentmwillis changed the title from Lazy Loading Nonrouteable Engines to Lazy Loading Route-less Engines Nov 23, 2016

@aalasolutions

This comment has been minimized.

aalasolutions commented Feb 7, 2017

Any updates on this? Our app is route-less and need to use lazy loading for the engine. Main JS file is like 3MB and some users are not having access to all the areas.

@villander

This comment has been minimized.

Contributor

villander commented Feb 3, 2018

Route-less Engines, on the other hand, are Engines which are not able to be routed to. This means that they don’t live at a specific route, but are instead mounted within a template or your application. Examples of good candidates for route-less Engines are chat boxes or complex forms.

Following the concept of route-less, I think we should start the request to load the Engine assets, when the template of that route / component is called. We can do something like what React does:

import React from 'react';
import { render } from 'react-dom';
import { BrowserRouter as Router, Route } from "react-router-dom";

import AppTemplate from './commons/ui/components/AppTemplate';
import AsyncComponent from './AsyncComponent';
import basePath from './commons/utils/basePath';

import "./style/app.scss";

const home = () => import(/* webpackChunkName: "home" */ './modules/home/index');
const projects = () => import(/* webpackChunkName: "projects" */ './modules/projects/index');
const contact = () => import(/* webpackChunkName: "contact" */ './modules/contact/index');

render(
  <Router>
    <AppTemplate>
      <Route path={basePath``} exact={true} component={() => <AsyncComponent moduleProvider={home} />} />
      <Route path={basePath`projects`} exact={true} component={() => <AsyncComponent moduleProvider={projects} />} />
      <Route path={basePath`contact`} exact={true} component={() => <AsyncComponent moduleProvider={contact} />} />
    </AppTemplate>
   </Router>,
  document.getElementById("app")

Yeah, this hasn't really been considered yet. I think the primary question was how to handle the fact that the mount point will render asynchronously. Once that is determined, we just need to identify where we in that lifecycle we initiate the request to load the Engine assets.

I would love to work on this and various features of ember-engines, but I need someone to introduce me to the gears of this addon

@GCheung55

This comment has been minimized.

Contributor

GCheung55 commented Mar 8, 2018

The recent talk by Dan Ambramov about async rendering in React made me think of this lazy loading routless engines issue.

@anulman

This comment has been minimized.

anulman commented Jul 7, 2018

Bumping this thread; per @villander's React notes I'd also suggest looking upstream at Webpack's code splitting guide, particularly re prefetch & preload.

Since Ember is convention > configuration though, I think our syntax shifts slightly. Specifically, I think non-routable {{mount 'foo'}}s ought to:

  • Accept an eager=true arg as a local override to the application's lazyLoading: true config—at build time this engine would be compiled into its host;
  • Accept prefetch=true to lazy-load the engine once the host has completed loading & booting; and
  • Otherwise default to lazy-loading at render time

In all cases, {{mount}} should accept actions for lifecycle hooks (eg willLoad, didLoad, willRender, didRender, onError) and expose load & error states via contextual component (eg isLoading & didError).

This would look something like:

Lazy-load a chat room on a parent route's template:

{{outlet}}
{{#mount 'chat-room' as |engine|}}
  {{#engine.isLoading}} It never hurts to try<br />{{loading-spinner}} {{/engine.isLoading}}
  {{#engine.didError}} Could not load chat; reload the page or <button onclick={{action engine.retry}}>click to retry</button>
{{/mount}}

Prefetch a login modal once host has loaded + booted:

{{#if isShowingLoginModal}}
  {{#mount 'login-modal' prefetch=true didLoad=(action 'instrumentLoginLoad') as |engine|}}
    {{#engine.isLoading}} {{loading-spinner}} {{/engine.isLoading}}
    {{#engine.didError}} Load error; <button onclick={{action engine.retry}}>click to retry</button> {{/engine.didError}}
  {{/mount}}
{{/if}}

Opt-in for old behaviour (ie expect the engine to be loaded):

{{#if isShowingLoginModal}}
  {{mount 'login-modal'}}
{{/if}}

If useful, I have a spike of another approach to code-splitting modules I'm calling Ember Async Registry, which has a few tradeoffs vs. Ember Engines and IMO is more useful in route-less engine scenarios. Happy to share more if of interest; I've written a draft blog post introducing the concept (for publishing week of Jul 9), but do not yet have an addon any app can just "drop in".

@toovy

This comment has been minimized.

toovy commented Oct 23, 2018

I'm curious, is anyone still working on this?

@rwjblue

This comment has been minimized.

Collaborator

rwjblue commented Oct 23, 2018

AFAICT ember-engines/ember-asset-loader#56 is the only thing required...

@toovy

This comment has been minimized.

toovy commented Oct 23, 2018

@rwjblue thanks, sounds like it is a simple step. You already posted reference code. What is hindering the implementation?

@rwjblue

This comment has been minimized.

Collaborator

rwjblue commented Oct 23, 2018

Someone to do it 😸

@toovy

This comment has been minimized.

toovy commented Oct 24, 2018

Guess then we'll have to wait for someone smart having the time! :)

@buschtoens

This comment has been minimized.

Contributor

buschtoens commented Oct 24, 2018

Cross-posting ember-engines/ember-asset-loader#56 (comment):

The most recent Ember.js times newsletter had a reference to this, that reminded me about this addon I once wrote: ember-lazy-mount

I guess this is not really relevant, since it uses a component instead of a template helper, but maybe you still find it useful. ✌️

@toovy

This comment has been minimized.

toovy commented Oct 25, 2018

Just tested https://github.com/buschtoens/ember-lazy-mount and it seems to work fine. As I now know this addon now I'm fine with the solution, still I think the code somehow should be incorporated in standard engines (or asset loader). This feature is really great, once more it enables you to manage big applications and split the code apart. A great win for ember.

Shouldn't we update the readme at https://github.com/ember-engines/ember-engines#lazy-loading-engines? I guess lazy loading is fully supported now.

Furthermore the docs at http://ember-engines.com/guide/lazy-loading says that

Currently, lazy loading is not supported for route-less Engines. Progress can be tracked at this issue.

With a reference to this issue. Ok now you will find a solution once you look into the issue. But maybe the documentation should directly point to the addon so that the reader does not assume that this feature is not available or "an issue".

What do you think?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment