Problem Summary
I am migrating an old AngularJS application to use Webpack and I am splitting it into three parts, which I want to represent as AngularJS modules:
- src-ts-admin
- src-ts-common
- src-ts-store
For example I'd like 'src-ts-admin' to consume services from 'src-ts-common', but unfortunately webpack bundles files in the wrong order for AngularJS Dependency Injection, so that I end up with errors like ..
Error: "[$injector:unpr] Unknown provider: filterServiceProvider <- filterService <- initializerService
.. where initializerService is a service from src-ts-admin and filterService is from src-ts-common. The core of the problem is that
- module("ADMIN").service("initializerService") executes before
- module("COMMON).service("filterService")
.. although I cannot spot the problem in the dependencies.
File Overview
src-ts-admin: app.ts
This is the webpack entry point, however not so interesting. The application routing will trigger app.initializer.ts.
import angular from 'angular';
import { appModule } from './app.module';
src-ts-admin: app.module.ts
import angular from 'angular';
import commonModuleName from '../src-ts-common/common.module';
var modulezz;
modulezz = [commonModuleName,'ngRoute', 'ui.router', 'ui.multiselect', 'ui.bootstrap', 'ui.bootstrap-slider', 'ui.bootstrap.buttons', 'duScroll',
'ngMessages', 'colorpicker.module', 'angular-bind-html-compile', 'pascalprecht.translate'];
export var appModule = angular.module("ADMIN", modulezz);
export default appModule.name;
src-ts-admin: app.initializer.ts
import angular from "angular";
import appModuleName from "./app.module";
import { filterService } from "../src-ts-common/service/filter-service-model";
export class InitializerController {
static $inject = ...etc...
constructor(...etc...) {
/* THIS IS KICKED OFF BY AN ANGULAR ROUTE, THIS KICKS OFF THE InitializerController BELOW */
}
}
angular.module(appModuleName).controller("initializerController", InitializerController);
export class InitializerService {
static $inject = ["$stateParams", "$window", "$timeout", "filterService", ...etc...];
constructor(private $stateParams, private $window, private $timeout, private filterService: filterService, ...etc...) {
/* THIS IS WHERE THE DEPENDENCY INJECTION FAILS */
}
}
angular.module(appModuleName).service("initializerService", InitializerService);
src-ts-common: common.module.ts
import angular from 'angular';
export default angular.module("COMMON",[]).name;
src-ts-common: filter.service.ts
import angular from "angular";
import commonModuleName from '../common.module';
export class filterService {
static $inject = [];
constructor() {
/* ...simplified... */
}
}
angular.module(commonModuleName).service("filterService", filterService);
My thoughts
The error I get is ..
Error: "[$injector:unpr] Unknown provider: filterServiceProvider <- filterService <- initializerService
.. which indicates to me that app.initializer.ts is executed before filter.service.ts, although it is importing that file.
Do you see any obious errors I made? Do you have any best practices to structure AngularJS + Webpack module imports and cut files?
--- Solution (Update!) ---
Thanks to https://stackoverflow.com/a/59631154/5244937 I could solve my problem. The pattern I should have used was to initialize the angular modules (e.g. angular.module(commonModuleName).service("filterService", filterService);) in the app.module.ts and common.module.ts files and NOT together with their class implementations.
Here the corrected files:
src-ts-admin: app.ts
/* here i am more or less just kicking off the angular application after i import app.module.ts */
import { appModule } from './app.module';
appModule.run(["$rootScope", "$location", ...,
function ($rootScope, $location, ...) {
..
}
appModule.controller('appController', ['$scope', ..,
function ($scope: any, ...) {
..
}
src-ts-admin: app.module.ts
/** here (1) i am initializing all angular controllers, services, factories from the ADMIN package & (2) importing the COMMON module */
import angular from 'angular';
import ngRoute from 'angular-route';
import uiRouter from 'angular-ui-router';
import 'angular-messages';
import 'angular-translate';
import dptCommonModuleName from '../src-ts-common/common.module';
var modulezz;
modulezz = [dptCommonModuleName, ngRoute, uiRouter, 'ui.multiselect', 'ui.bootstrap', 'ui.bootstrap-slider', 'ui.bootstrap.buttons', 'duScroll',
'ngMessages', 'colorpicker.module', 'angular-bind-html-compile', 'pascalprecht.translate'];
export var appModule = angular.module("DPT", modulezz);
export var appModuleName = appModule.name;
/**
* Services
*/
angular.module(appModuleName).service("systemParameterService", systemParameterService);
angular.module(appModuleName).service("statisticsService", statisticsService);
angular.module(appModuleName).service("deletionCheckService", deletionCheckService);
...
src-ts-admin: app.initializer.ts
/** here i have removed (1) the import of angular.module.ts and (2) the initialization of angular controller and service "initializerController" and "initializationService" */
import angular from "angular";
import { filterService } from "../src-ts-common/service/filter-service-model";
export class InitializerController {
static $inject = ...etc...
constructor(...etc...) {
/* THIS IS KICKED OFF BY AN ANGULAR ROUTE, THIS KICKS OFF THE InitializerController BELOW */
}
}
export class InitializerService {
static $inject = ["$stateParams", "$window", "$timeout", "filterService", ...etc...];
constructor(private $stateParams, private $window, private $timeout, private filterService: filterService, ...etc...) {
/* THIS IS WHERE THE DEPENDENCY INJECTION FAILS */
}
}
src-ts-common: common.module.ts
/* here i have added the initialization of the angular service filterService and all other services, factories, .. contained in that module */
var moduleName = angular.module("DPT.COMMON",[]).name
export default moduleName;
angular.module(moduleName).factory("filterModel", function () { return filterModel; });
angular.module(moduleName).factory("filterPresetModel", function () {return filterPresetModel;});
angular.module(moduleName).factory("productModel", function () {return productModel;});
angular.module(moduleName).factory("propertyProfileModel", [function () {return propertyProfileModel;}]);
angular.module(moduleName).factory("propertyValueModel",function () {return propertyValueModel;});
src-ts-common: filter.service.ts
/** here i have (1) removed the import of common.module and (2) teh initialization of angular.module(..).service("filterService", ..) */
import angular from "angular";
export class filterService {
static $inject = [];
constructor() {
/* ...simplified... */
}
}
import angular from "angular". I am having challenges importing angularjs v1.3.7npm install @types/angular1