0

私は現在、かなり大きな Angular JS アプリケーションのパフォーマンスを向上させようとしています。これは、javascript ファイルの 1 つの大きなチャンクから、遅延ロードされる可能性のある 3 ~ 4 つの小さなチャンクに移行することによって実現しています。

次の npm パッケージとバージョンを使用しています。

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

最初は、すべての必要な JavaScript ファイルを取得し、requirejs オプティマイザーを使用してそれらすべてを 1 つのファイルに含める 1 つの面倒なタスクがありました。そのmain.jsため、特定のすべてのパッケージのすべてのパスとシムが定義された 1 つのメイン構成ファイルがありました (私は必要に応じてサンプル構成などを投稿できます)。

ここでのアイデアは、この 1 つの大きなファイルを持つことから移行し、アプリケーションを 3 つから 4 つの小さな JavaScript ファイルにモジュール化して、ロード時間を短縮することです (4 つの小さなファイルを並行してロードする方が、1 つの大きなファイルをロードするよりも高速であるため)。

そのために、grunt-requirejs の modules オプションと bundles オプションを使用して、すべてのモジュールとその内容を定義します。

プロジェクトの構造は次のとおりです。

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

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']
                }
              } 
           }
        ]
      }
    }
  } 

requirejs:bundle 実行後の dist フォルダーは次のようになります。

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

したがって、app_minitestserviceは に含まれapp.jsangularjqueryは に含まれvendor.jsます。

src フォルダー内の私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);
};

長いファイルの内容で申し訳ありませんが、それなしで問題を説明することは不可能です:) したがって、問題は、オプティマイザーとアプリ自体の Requirejs 構成全体を配置するための中心的な場所が必要なことです。ただし、明らかに、オプティマイザのパスは gruntfile パスに対して相対的であり、実行中のアプリのパスは対応するファイルに対して相対的です。

バンドル構成は requirejs によって自動的に生成されるため (bundlesConfigOutFile のため)、そこで使用される名前については、モジュール オプションから取得されるため、実際には多くのことを行うことはできません。

生成されて app.js に含まれるバンドル構成は次のようになります。

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

まず、RequireJs が vendor.js をパスでロードしたいという問題がありました。scripts/scripts/vendor.js

それを修正するために、私は abaseUrl = '/'require.configofに含めましたapp

しかし、今、私は問題を抱えていますtestservice.injectapp_miniangular.

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(){});
 
})();
4

1 に答える 1

0

わかりました、おそらく誰もこれをすべて読んでいないだろうと思いましたが、本当の問題をもっとうまく指摘できたはずだと気づきました. ( app_mini と angular は、 testservice に挿入されるまでに未定義でした)

したがって、問題は、シム構成を渡すのを完全に逃したことでした。これにより、require js が angular および jquery を AMD モジュールにラップできるようになります。それが見つからなかったため、angular が見つからず、app_mini だけでなく testservice も破損し、アプリ全体も破損しました。

そこで、shim を追加して、ベンダー モジュールの構成を適宜編集しました。

modules: [
      {
        name: 'scripts/vendor',
        exclude: [],
        override: {
          {
            paths: {
              'angular': 'bower/angular/angular',
              'jquery': 'bower/jquery/dist/jquery'
            },
            shim: {
              angular: {
                exports: 'angular',
                deps: ['jquery']
              }
            },
            bundles: {
            } 
          },
        }
      },
于 2017-01-05T11:52:44.963 に答える