AngularJS 模块 + Webpack + ES6 导入 - 依赖注入和连接顺序问题

Posted

技术标签:

【中文标题】AngularJS 模块 + Webpack + ES6 导入 - 依赖注入和连接顺序问题【英文标题】:AngularJS modules + Webpack + ES6 imports - Problem with dependency injection & concat order 【发布时间】:2020-04-24 17:03:07 【问题描述】:

问题总结

我正在迁移一个旧的 AngularJS 应用程序以使用 Webpack,我将它分成三个部分,我想将它们表示为 AngularJS 模块:

src-ts-admin src-ts-common src-ts-store

例如,我希望 'src-ts-admin' 使用来自 'src-ts-common' 的服务,但不幸的是 webpack 以错误的顺序捆绑文件以进行 AngularJS 依赖注入,所以我最终会遇到类似的错误..

Error: "[$injector:unpr] Unknown provider: filterServiceProvider <- filterService <- initializerService

.. 其中 initializerService 是来自 src-ts-admin 的服务,而 filterService 来自 src-ts-common。问题的核心在于

module("ADMIN").service("initializerService") 之前执行 module("COMMON).service("filterService")

.. 虽然我无法在依赖项中发现问题。

文件概述

src-ts-admin: app.ts

这是 webpack 的入口点,但不是很有趣。应用路由会触发 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);

我的想法

我得到的错误是..

Error: "[$injector:unpr] Unknown provider: filterServiceProvider <- filterService <- initializerService

.. 这表明 app.initializer.ts 在 filter.service.ts 之前执行,尽管它正在导入该文件。

你看到我犯了什么明显的错误吗?你有什么最佳实践来构建 AngularJS + Webpack 模块导入和剪切文件吗?

--- 解决方案(更新!)---

感谢https://***.com/a/59631154/5244937 我可以解决我的问题。我应该使用的模式是初始化 app.module.tscommon.module.ts 文件中的角度模块(例如 angular.module(commonModuleName).service("filterService", filterService);),而不是与它们的类实现一起初始化。

这里是更正的文件:

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

/** 这里我 (1) 删除了 common.module 的导入和 (2) angular.module(..).service("filterService", ..) 的初始化 */

import angular from "angular";

export class filterService 
    static $inject = [];
    constructor() 
    /* ...simplified... */
    

【问题讨论】:

请问您如何导入import angular from "angular"。我在导入 angularjs v1.3.7 时遇到了挑战 【参考方案1】:

您的依赖项倒置Module 应导入其依赖项(其他模块或过滤器/服务/组件)。

如果您遵循此操作,您的 AppModule 将导入其子模块,然后再导入其服务。

这意味着您的服务应该导出类。 相关模块应导入服务类,并在模块上注册并导出模块名称。 父模块应导入其子模块。

// serviceX.js

export class serviceX 
  static $inject=[];
  ...

// childModule.js

import serviceX from './services/serviceX.js';
import componentY from './components/componentY.js';
import angular from 'angular';

export default angular.module('childModule', [])
.service('serviceX', serviceX)
.component('componentY', componentY)
// ... rest of the childModule deps
.name;
// appModule.js

import externalDep from 'external-dep';
import childModule from './modules/childModule';
import angular from 'angular';

const appModule = anguler.module('appModule', [externalDep, childModule]).name;

angular.bootstrap(document, [appModule]);

【讨论】:

你是对的。连同下面的教程,我已经更正了导入和文件的结构。 angular-tips.com/blog/2015/06/…我会用我现在的状态更新我原来的帖子

以上是关于AngularJS 模块 + Webpack + ES6 导入 - 依赖注入和连接顺序问题的主要内容,如果未能解决你的问题,请参考以下文章

AngularJS 和 Webpack 集成

使用 webpack 导入 angularjs 的最佳实践是啥?

使用 Typescript 和 Webpack 管理依赖项的 AngularJS

在 Heroku 上部署 AngularJs + webpack + gulp

AngularJS- 使用 LazyLoad- Webpack 动态加载脚本文件

无法使用 webpack 在依赖项上加载 angularjs $templateCache 模板