简体   繁体   English

结合requirejs包和requirejs优化器时的模块注入问题

[英]Module injection problems when combining requirejs bundles and requirejs optimizer

I am currently trying to increase the performance of a rather big Angular JS application, by moving from one big chunk of javascript file, to having 3 - 4 smaller ones, that could potentially even be lazy loaded. 我目前正试图通过从一大块javascript文件移动到具有3-4个较小的javascript文件(可能甚至是延迟加载)来提高一个相当大的Angular JS应用程序的性能。

I am using the following npm packages and versions: 我正在使用以下npm软件包和版本:

grunt-contrib-requirejs: 1.0.0
grunt: 0.4.5
requirejs: 2.3.0

Initially, there was one grunt task, which took ALL the required javascript files, included them all into one file using the requirejs optimizer, for that there was one main config file main.js where all the paths and shims for all the specific packages were defined (I can post sample configs etc if required). 最初,有一个艰巨的任务,它把所有必需的javascript文件,并使用requirejs优化器将它们全部包含到一个文件中,因为有一个主配置文件main.js ,其中所有特定软件包的所有路径和main.js都是定义(如果需要,我可以发布示例配置等)。

Now the idea is to move from having this one big file, to modularize the application into 3 - 4 smaller javascript files, to shorten load time (because loading 4 small files parallel is faster than loading 1 big file). 现在的想法是从拥有一个大文件开始,将应用程序模块化为3-4个较小的javascript文件,以缩短加载时间(因为并行加载4个小文件比加载1个大文件要快)。

For that we are using the modules option in grunt-requirejs and the bundles option to define all the modules and their contents. 为此,我们使用grunt-requirejs中的modules选项和bundles选项来定义所有模块及其内容。

The project structure is as follows: 项目结构如下:

/src/
  ./Gruntfile.js
  ./scripts/
    ./app.js
    ./vendor.js
    ./app_mini.js
    ./features/
      ./test.service.js
/dist/

The grunt task is defined like this: grunt任务的定义如下:

requirejs: {
    bundle: {
      options: {
        baseUrl: '/src',
        mainConfigFile: '/src/scripts/app.js',
        bundlesConfigOutFile: 'scripts/app.js',
        findNestedDependencies: true,
        dir: '/dist',
        modules: [
          {
            name: 'scripts/vendor',
            exclude: [],
            override: {
              {
                paths: {
                  'angular': 'bower/angular/angular',
                  'jquery': 'bower/jquery/dist/jquery'
                },
                bundles: {
                } 
              },
            }
          },

          {
            name: 'scripts/app',
            exclude: ['scripts/vendor'],
            override: {
              {
                paths: {
                  'vendor': 'scripts/vendor',
                  'app_mini': 'scripts/app_mini',
                  'testservice': 'scripts/features/test.service'
                },
                bundles: {
                  'vendor': ['angular', 'jquery']
                }
              } 
           }
        ]
      }
    }
  } 

The dist folder after execution of requirejs:bundle looks like this: 执行requirejs:bundle之后的dist文件夹如下所示:

/dist/
  ./scripts/
    ./app.js
    ./vendor.js

So, app_mini and testservice are included into app.js , and angular and jquery are included into vendor.js . 因此, app_minitestservice包含在app.js ,而angularjquery包含在vendor.js

My app.js in the src folder looks more or less like this: 我的src文件夹中的app.js看起来app.js如下:

define('app',
  [
    'angular', 
    'app_mini',
    'testservice'
   ],
   function(
     angular,
     app_mini,
     testservice) {}
);

require([
  'angular',
  'app_mini',
  'testservice'
], function (
  angular,
  app_mini,
  testservice
) {
  // entry to app


}, function(err) {
  console.log('error loading module: ' + err.requireModules);
};

I am sorry for the long file contents, but it is impossible to describe the problem without it :) So, the problem is, I would like to have a central place to put the whole Requirejs config for the optimizer and for the app itself. 很抱歉,文件内容太长,但是如果没有它,就无法描述问题:)因此,问题是,我想在中央放置一个用于优化程序和应用程序本身的整个Requirejs配置。 However, obviously the paths for the optimizer are relative to the gruntfile path, and the paths for the running app, are relative to the corresponding file. 但是,显然,优化程序的路径是相对于gruntfile路径的,而运行中的应用程序的路径是相对于相应的文件的。

As the bundle configuration is automatically generated by requirejs (because of bundlesConfigOutFile), I cannot really do a lot about the names used there, as they get pulled from the modules option. 由于bundle配置是由requirejs自动生成的(由于bundlesConfigOutFile的影响),因此我不能对那里使用的名称做太多事情,因为它们是从modules选项中拉出来的。

The bundles config which gets generated and included into app.js looks like this: 生成并包含在app.js中的bundles配置如下所示:

require.config({
  bundles: {
    'scripts/vendor': [
      'angular',
      'jquery'
    ],
    'scripts/app': [
      'testservice',
      'app_mini',
      'app'
    ]
  }
});

Now first, I had the problem that RequireJs wanted to load vendor.js by path scripts/scripts/vendor.js 现在首先,我遇到了一个问题,RequireJs想通过路径scripts/scripts/vendor.js

To fix that, I included a baseUrl = '/' into the require.config of app 为了解决这个问题,我在apprequire.config中包含了baseUrl = '/'

But now I have a problem, that testservice is not able to inject app_mini and angular , so it is throwing an error there, because both of these modules are undefined. 但是现在我有一个问题, testservice不能注入app_miniangular ,所以在那里抛出错误,因为这两个模块都是未定义的。

The optimized app.js in the dist folder looks like this, maybe you can spot the problem: dist文件夹中经过优化的app.js如下所示,也许您可​​以发现问题所在:

(function(){


define(
    'testservice',[
        'angular',
        'app_mini'
    ], function(
        angular,
        app_mini
    ) {
        'use strict';
 
        app_mini.factory('testservice', TestService);
 
        function TestService() {
            var service = {
                test: test
            };
            return service;
        };
 
        var test = function() {
            console.log("testservice::test()");
        };
});
 
define('app_mini',
    [
        'angular',
        'testservice'
    ],
 
    function (
        angular,
        testservice
    ) {
        'use strict';
 
 
        var module = angular.module(‘some.project’, []);
 
        module.run(AppRun);
 
        AppRun.$inject = [
            '$rootScope',
            'testservice'
        ];
        function AppRun($rootScope, testservice) {
            console.log(“yay, it works”);
 
            testservice.test();
        }
 
        return module;
    }
);
 
require.config({
    bundles: {
        'scripts/vendor.bundle': [
            'angular',
            'jquery'
        ],
        'scripts/app.bundle': [
            'testservice',
            'app_mini',
            'app'
        ]
    }
});
 
require.config({
    baseUrl: '/'
});
 
 define(‘app’,
    [
        'angular',
        'app_mini',
        'testservice'
    ], function(
        angular,
        app_mini,
        testservice
){});
 
require([
        'angular',
        'app_mini',
        'testservice'
    ], function (
        angular,
        app_mini,
        testservice
    ) {
 
    angular.element().ready(function () {
        var $html = angular.element(document.getElementsByTagName('html')[0]);
        angular.bootstrap($html, [app_mini['name']]);
    });
 
}, function (err) {
    'use strict';
 
    console.log('Error loading requirejs-module: ' + err.requireModules);
});
 
define("scripts/app.bundle", function(){});
 
})();

Alright, I figured that probably noone will read through all this, and I just noticed that I could have pointed out the real problem much better. 好吧,我认为可能没有人会仔细阅读所有这些内容,而我只是注意到我本可以更好地指出真正的问题。 ( It was that app_mini and angular were undefined by the time they got injected into testservice ) 这是app_mini和angular在被注入到testservice时尚未定义

So the problem was just that I completely missed to pass in the shim config, which allows require js to wrap angular and jquery into AMD modules. 所以问题是我完全错过了传递shim配置,该配置允许require js将angular和jquery包装到AMD模块中。 Because that was missing, angular could never be found, which broke app_mini as well as testservice and therefore also the whole app. 因为缺少该属性,所以无法找到angular,这破坏了app_mini以及testservice以及整个应用程序。

So I edited the vendor module config accordingly, by adding the shim: 因此,我通过添加垫片对供应商模块配置进行了相应的编辑:

modules: [
      {
        name: 'scripts/vendor',
        exclude: [],
        override: {
          {
            paths: {
              'angular': 'bower/angular/angular',
              'jquery': 'bower/jquery/dist/jquery'
            },
            shim: {
              angular: {
                exports: 'angular',
                deps: ['jquery']
              }
            },
            bundles: {
            } 
          },
        }
      },

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM