angular-hybrid icon indicating copy to clipboard operation
angular-hybrid copied to clipboard

Downgraded Components dot get resolve in minified code

Open jo-soft opened this issue 5 years ago • 6 comments

Given a state definition like this:

// file A.ts
export const coreHomeUiRouterState: NgHybridStateDeclaration = {
  name: 'home',
  url: '',
  component: CoreHomeComponent
};

angular.module('dccApp').config([
  '$stateProvider',
  function($stateProvider) {
    $stateProvider.state(coreHomeUiRouterState);
  },
]);

and a component

// file B.ts
@Component({
  selector: 'core-home',
  template: '<p>hallo world</p>,
})
export class CoreHomeComponent {}

which gets downgraded using ngMigrate

// file C.ts
export function downgradeCoreHome() {
  angular
    .module('App')
    .directive('coreHome', <angular.IDirectiveFactory>downgradeComponent({ component: CoreHomeComponent }));
}

in minified code (to be precise: mode:production in webpack) i get the following error if i navigate to the 'home' state:

Error: [$injector:unpr] Unknown provider: function e(){}DirectiveProvider <- function e(){}Directive https://errors.angularjs.org/1.6.10/$injector/unpr?p0=function%20e()%7B%7DDirectiveProvider%20%3C-%20function%20e()%7B%7DDirective

for un-minified code it works completely fine and the content gets rendered.

jo-soft avatar Jun 06 '19 13:06 jo-soft

I am experiencing the same thing with Angular 9.1.9.

With webpack mode: "development" everything works. With mode: "production" (and everything else staying the same) I get the following errors when navigating to any route/state in the /tasks tree.

Transition Rejection($id: 1 type: 6, message: The transition errored, detail: NullInjectorError: R3InjectorError(e)[e -> e -> e]: 
  NullInjectorError: No provider for e!)
NullInjectorError: R3InjectorError(e)[e -> e -> e]: 
  NullInjectorError: No provider for e!

We've implemented like this.

tasks.states.ts

import { CompletedTasksComponent } from "./components/completed-tasks/completed-tasks.component";
import { NgHybridStateDeclaration } from "@uirouter/angular-hybrid";

export const states = [
  {
    name: "tasks",
    url: "/tasks",
    component: "tasks", // AngularJS
    parent: "main",
    redirectTo: "currentTasks",
    resolve: {
      categories: function(apiService) {
        return apiService.tasks.getCategories();
      },
    },
  },

  {
    name: "currentTasks",
    url: "/current",
    component: "currentTasks", // AngularJS
    parent: "tasks",
    data: {
      title: "Current Tasks",
    },
  },

  {
    name: "completedTasks",
    url: "/complete",
    component: CompletedTasksComponent, // Angular 9
    parent: "tasks",
    data: {
      title: "Completed Tasks",
    },
  },
] as NgHybridStateDeclaration[];

tasks.module.ts

import { states } from "./tasks.states";

@NgModule({
  imports: [
    ...,
    UIRouterUpgradeModule.forChild({ states: states }),
  ],
  declarations: [CompletedTasksComponent, TaskComponent],
  exports: [],
})
export class TasksModule {}

Package versions:

    "@uirouter/angular": "^6.0.1",
    "@uirouter/angular-hybrid": "^10.0.1",
    "@uirouter/angularjs": "^1.0.26",
    "@uirouter/core": "^6.0.5",

Plonq avatar Jun 11 '20 07:06 Plonq

@Plonq can you show code from declared components ?

jakubmank avatar Jun 11 '20 08:06 jakubmank

@Plonq can you show code from declared components ?

EDIT: I removed the code here because it's irrelevant and created noise. See my solution below.

Plonq avatar Jun 11 '20 08:06 Plonq

It also works with webpack mode: "none" so it's something to do with the production mode rather than the development mode.

Plonq avatar Jun 11 '20 08:06 Plonq

Further to my previous comment, I've narrowed it down to TerserPlugin. With mode set to "none", and manually adding minification with TerserPlugin with default config, I get the error shown in my first comment.

TerserPlugin config that triggers the error:

optimization: {
  minimize: true,
  minimizer: [new TerserPlugin()],
},

Plonq avatar Jun 11 '20 09:06 Plonq

I have found a solution (to my problem at least).

The problem seems to be the resolve function isn't getting dependencies automatically annotated by the angularjs-annotate babel plugin. I'm guessing because it doesn't look like AngularJS code.

The solution is to either manually inject resolve dependencies like so:

resolve: {
  categories: getCategories,
}

getCategories.$inject = ["apiService"];
function getCategories(apiService) {
  return apiService.tasks.getCategories();
}

Or use the explicit markup for babel-plugin-angularjs-annotate

Plonq avatar Jun 11 '20 22:06 Plonq

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. This does not mean that the issue is invalid. Valid issues may be reopened. Thank you for your contributions.

stale[bot] avatar Nov 12 '22 11:11 stale[bot]