mgechev / aspect.js

JavaScript library for aspect-oriented programming using modern syntax.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Lazy loading of multiple aspects targeting woven class

mgechev opened this issue · comments

Problem

In case we lazy-load multiple aspects which aim to alter behavior to already woven target it will not work because we'll check the private flag __woven__ and in case it's set to true we'll skip further woving.

Solution

A better idea is to keep the __woven__ property Set<Aspect> so we can push new elements into the set, each time we wove it with another aspect. We can check if the target has been already woven by given aspect by checking if the aspect is into the set, which is an operation with a constant complexity.

With lazy loading, you mean lazy loading bundles with aspects?

Yes, lazy-loaded bundles which have definition of aspects.

Will have a look in the coming days if I can help you with that.

Going to take a swing at this one.

I created an Angular CLI example with lazy loading. I have an AppService in the main bundle together with a simple LoggerAspect.

import {beforeMethod, Wove, Metadata} from 'aspect.js';

class LoggerAspect {
  @beforeMethod({
    classNamePattern: /^AppService/,
    methodNamePattern: /^(world)/
  })
  invokeBeforeMethod(meta: Metadata) {
    console.log(`Inside of the logger. Called ${meta.className}.${meta.method.name}.`);
  }
}

I created a lazy loaded bundle with a second logger aspect on the same AppService.

import {beforeMethod, Wove, Metadata} from 'aspect.js';

class Logger2Aspect {
  @beforeMethod({
    classNamePattern: /^AppService/,
    methodNamePattern: /^(world)/
  })
  invokeBeforeMethod(meta: Metadata) {
    console.log(`Inside of logger 2. Called ${meta.className}.${meta.method.name}.`);
  }
}

When I navigate to the route with the lazy bundle, it successfully attaches the aspect to the AppService, the controller calls appService.world(), and both loggers print their message. So I don't think we'd have to do anything for this anymore.

I've put it on GitHub in the lazy-aspect repository. Just check it out, install the dependencies and run npm start.

Both routes are being lazy loaded (Home and About). Open the developer tools and take a look when at the home page. It has just one logger aspect and calls the AppService.world() method.

Inside of `before` logger. Calling AppService.world.
world

Navigate to the About page. It attaches a second after logger aspect and also calls the AppService.world() method.

Inside of `before` logger. Calling AppService.world.
world
Inside of the lazy loaded `after` logger. Called AppService.world.

Thanks for looking into it!