结合 requirejs 包和 requirejs 优化器时的模块注入问题
Module injection problems when combining requirejs bundles and requirejs optimizer
我目前正在尝试提高一个相当大的 Angular JS 应用程序的性能,方法是从一大块 javascript 文件移动到 3 - 4 个较小的文件,这可能甚至可以延迟加载。
我正在使用以下 npm 包和版本:
grunt-contrib-requirejs: 1.0.0
grunt: 0.4.5
requirejs: 2.3.0
最初,有一个 grunt 任务,它获取所有必需的 javascript 文件,使用 requirejs 优化器将它们全部包含到一个文件中,因为有一个主配置文件 main.js
其中所有特定包的所有路径和垫片都已定义(如果需要,我可以 post 示例配置等)。
现在的想法是从拥有一个大文件转变为将应用程序模块化为 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_mini
和testservice
被包含在app.js
中,angular
和jquery
被包含在vendor.js
中。
我的 app.js
在 src 文件夹中看起来大致是这样的:
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 路径的,而 运行 应用程序的路径是相对于相应文件的。
由于 bundle 配置是由 requirejs 自动生成的(因为 bundlesConfigOutFile),我真的不能对那里使用的名称做很多事情,因为它们是从模块选项中提取的。
生成并包含在 app.js 中的捆绑包配置如下所示:
require.config({
bundles: {
'scripts/vendor': [
'angular',
'jquery'
],
'scripts/app': [
'testservice',
'app_mini',
'app'
]
}
});
现在首先,我遇到了 RequireJs 想要通过路径 scripts/scripts/vendor.js
加载 vendor.js 的问题
为了解决这个问题,我在 app
的 require.config
中包含了一个 baseUrl = '/'
但是现在我遇到了一个问题,testservice
无法注入 app_mini
和 angular
,所以它在那里抛出一个错误,因为这两个模块都是未定义的.
优化后的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(){});
})();
好吧,我想可能没有人会通读所有这些,我只是注意到我本可以更好地指出真正的问题。 (是 app_mini 和 angular 在注入测试服务时未定义 )
所以问题是我完全没有传递 shim 配置,它允许 require js 将 angular 和 jquery 包装到 AMD 模块中。因为它丢失了,angular 永远找不到,这破坏了 app_mini 以及测试服务,因此也破坏了整个应用程序。
所以我通过添加垫片相应地编辑了供应商模块配置:
modules: [
{
name: 'scripts/vendor',
exclude: [],
override: {
{
paths: {
'angular': 'bower/angular/angular',
'jquery': 'bower/jquery/dist/jquery'
},
shim: {
angular: {
exports: 'angular',
deps: ['jquery']
}
},
bundles: {
}
},
}
},
我目前正在尝试提高一个相当大的 Angular JS 应用程序的性能,方法是从一大块 javascript 文件移动到 3 - 4 个较小的文件,这可能甚至可以延迟加载。
我正在使用以下 npm 包和版本:
grunt-contrib-requirejs: 1.0.0
grunt: 0.4.5
requirejs: 2.3.0
最初,有一个 grunt 任务,它获取所有必需的 javascript 文件,使用 requirejs 优化器将它们全部包含到一个文件中,因为有一个主配置文件 main.js
其中所有特定包的所有路径和垫片都已定义(如果需要,我可以 post 示例配置等)。
现在的想法是从拥有一个大文件转变为将应用程序模块化为 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_mini
和testservice
被包含在app.js
中,angular
和jquery
被包含在vendor.js
中。
我的 app.js
在 src 文件夹中看起来大致是这样的:
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 路径的,而 运行 应用程序的路径是相对于相应文件的。
由于 bundle 配置是由 requirejs 自动生成的(因为 bundlesConfigOutFile),我真的不能对那里使用的名称做很多事情,因为它们是从模块选项中提取的。
生成并包含在 app.js 中的捆绑包配置如下所示:
require.config({
bundles: {
'scripts/vendor': [
'angular',
'jquery'
],
'scripts/app': [
'testservice',
'app_mini',
'app'
]
}
});
现在首先,我遇到了 RequireJs 想要通过路径 scripts/scripts/vendor.js
为了解决这个问题,我在 app
require.config
中包含了一个 baseUrl = '/'
但是现在我遇到了一个问题,testservice
无法注入 app_mini
和 angular
,所以它在那里抛出一个错误,因为这两个模块都是未定义的.
优化后的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(){});
})();
好吧,我想可能没有人会通读所有这些,我只是注意到我本可以更好地指出真正的问题。 (是 app_mini 和 angular 在注入测试服务时未定义 )
所以问题是我完全没有传递 shim 配置,它允许 require js 将 angular 和 jquery 包装到 AMD 模块中。因为它丢失了,angular 永远找不到,这破坏了 app_mini 以及测试服务,因此也破坏了整个应用程序。
所以我通过添加垫片相应地编辑了供应商模块配置:
modules: [
{
name: 'scripts/vendor',
exclude: [],
override: {
{
paths: {
'angular': 'bower/angular/angular',
'jquery': 'bower/jquery/dist/jquery'
},
shim: {
angular: {
exports: 'angular',
deps: ['jquery']
}
},
bundles: {
}
},
}
},