Prestashop: Extend JS Router to add routing from modules

Created on 30 May 2020  路  11Comments  路  Source: PrestaShop/PrestaShop

Describe the bug:

As described in symfony documentation, there is a solution to generate routing in javascript like so:
<script> var url = Routing.generate('blog_show', { 'slug': 'my-blog-post' }); </script>

Is it possible to do that with PrestaShop?

Expected solution:

This JS routing is already used in the core pages, as explained in this comment https://github.com/PrestaShop/PrestaShop/issues/19473#issuecomment-636381199

It should be usable in a module for core routes (doc needed) however it is not possible to add custom route from modules.

Possible solution

Since rewriting the source from the core (admin-dev/themes/new-theme/js/fos_js_routes.json) would be complicated and a hassle, a more flexible solution would be to allow the modules to extend the router with their own routes.

Using an event system (or something similar), modules should be able to add their routes in the Router js class: https://github.com/PrestaShop/PrestaShop/blob/develop/admin-dev/themes/new-theme/js/components/router.js

From the module point of view the idea would be to generate its own json file (or any other format for that matter), and be able to do something like this (very rough idea):

import {EventEmitter} from '@components/event-emitter';
import routes from `my_module/my_routes.json`;

EventEmitter.on('router.routes', (event) => {
    event.addRoutes(routes);
});

And in the router something like this:

...
import {EventEmitter} from './event-emitter';
import RoutesEvent from `@components/events/routes-events`
...

export default class Router {
  constructor() {
    const routesEvent = new RoutesEvent();
    EventEmitter.emit('router.routes', routesEvent);
    Routing.setData(routesEvent.getRoutes());
    Routing.setBaseUrl($(document).find('body').data('base-url'));

    return this;
  }

  ...
}
BO Developer Feature PR available develop

Most helpful comment

Hi @gadnis

I think @matks explained it all ^^ It is indeed usable if you only need core routes, but not for modules ones. So I'll reformulate this issue title and description into a different way: Extend JS Router to add routing from modules

We should also add something in the doc to explain how to use this router from a module (even only for core routes for now) I created an issue for this here https://github.com/PrestaShop/docs/issues/554

All 11 comments

Thanks for opening this issue! We will help you to keep its state consistent

We use this solution for Symfony pages in the BO 馃槈

And we use it like this:

      this.router.generate('admin_addresses_edit', {
        addressId: address.addressId,
        liteDisplaying: 1,
        submitFormAjax: 1,
      });

See for example admin-dev/themes/new-theme/js/pages/order/create/addresses-renderer.js

However we have 1 issue: this needs for Symfony routes to be parsed and dumped into a JSON file that we put in admin-dev/themes/new-theme/js/fos_js_routes.json

So if you create a new route, you need to re-generate this file ! If you are a shop admin / developer you can do it, but if you create a module ; you cannot do it easily as you might not have access to this part of the shop

We have no good solution for that today unfortunately 馃槩 still looking for one

@matks that鈥檚 great news! Looking forward to module solution too. Thanks ;)

Hi @gadnis

I think @matks explained it all ^^ It is indeed usable if you only need core routes, but not for modules ones. So I'll reformulate this issue title and description into a different way: Extend JS Router to add routing from modules

We should also add something in the doc to explain how to use this router from a module (even only for core routes for now) I created an issue for this here https://github.com/PrestaShop/docs/issues/554

I just updated the description with a rough (very rough ^^) possible solution This will need to be polished by the @PrestaShop/prestashop-core-developers team

Hi guys,

Any news about this issue?

We are currently talking about this issue with @NeOMakinG .
We plan to do a "quick win" by adding javascript events in order to be able to add custom routes.
And we will do our best to improve the generation of the json file to avoid duplication between javascript and Symfony routing.

We are currently talking about this issue with @NeOMakinG .
We plan to do a "quick win" by adding javascript events in order to be able to add custom routes.

Nice idea !

And we will do our best to improve the generation of the json file to avoid duplication between javascript and Symfony routing.

Even if modules can use JS events to add custom routes, the question will remain "how modules can expose new routes (= routes introduced by the modules) without compiling the JSON ?"

And I'm thinking ... maybe we can provide a helper function to generate dynamically new JSON definitions ?

I'm thinking about

public function myCustomAPIEndpointAction()
{
    $myHelperService = $this->get('help_me');
    $json = $myHelperService->exposeRouteAsJSONDefinition('my_custom_route');

    return new JSONResponse($json);
}

And then the JS would "just" have to pass the JSON data returned by this endpoint to the router for the new route to be added ?

We are currently talking about this issue with @NeOMakinG .
We plan to do a "quick win" by adding javascript events in order to be able to add custom routes.

Nice idea !

And we will do our best to improve the generation of the json file to avoid duplication between javascript and Symfony routing.

Even if modules can use JS events to add custom routes, the question will remain "how modules can expose new routes (= routes introduced by the modules) without compiling the JSON ?"

And I'm thinking ... maybe we can provide a helper function to generate dynamically new JSON definitions ?

I'm thinking about

public function myCustomAPIEndpointAction()
{
    $myHelperService = $this->get('help_me');
    $json = $myHelperService->exposeRouteAsJSONDefinition('my_custom_route');

    return new JSONResponse($json);
}

And then the JS would "just" have to pass the JSON data returned by this endpoint to the router for the new route to be added ?

Not sure it's a good idea.
If you have X routes in Y modules, you shouldn't have to build a custom JSON for all your modules, it will decrease a lot (a lot lot lot) performance.
Since all routes are already compiled and loaded in Symfony Cache, we shouldn't use a static file to use routes in javascript.

IMHO, the best solution is to render a dynamic JSON file containing what we already generate and use in Symfony.
I don't know if I'm clear enough to be understood :sweat_smile:

I did a PR for the quickwin, also, I still provided the EventEmitter into the prestashop global object so it's easier for peoples working on symfony page to use it instead of installing it himself in his module :

https://github.com/PrestaShop/PrestaShop/pull/21471

Was this page helpful?
0 / 5 - 0 ratings