我的项目包括以下文件:
./index.html
./js/main.js
./js/vendor/require.js
./js/viewmodel/vm.js
该index.html
具有以下相关代码段:
<script data-main="js/main.js" src="js/vendor/require.js"></script>
<script type="text/javascript">
require(['viewmodel/vm', 'ko'],
function(viewmodel, ko) {
ko.applyBindings(viewmodel);
}
);
</script>
js/main.js
文件如下所示:
var root = this;
define('jquery', ['http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.3.js'], function () { return root.$; });
define('ko', ['http://ajax.aspnetcdn.com/ajax/knockout/knockout-2.1.0.js'], function (ko) { return ko; });
js/viewmodel/vm.js
文件...
define(['jquery', 'ko'],
function($, ko) {
return {
subject: 'world',
greeting: 'hello'
}
}
);
当您打开浏览器进行索引.html时,浏览器会尝试加载名为 js/ko.js
的文件,而不是使用 main.js
中定义的模块。似乎 data-main 属性指向的 js 文件不能保证在依赖项解析之前运行。这对我来说似乎是不正确的,因为数据主js文件的一个目的是定义需求配置(即路径,填充程序等)。我正在使用 require v2.1.2。
如果我将main.js
文件的内容复制到 index.html
中的脚本块中,这将非常有效。通过"完全正常",我的意思是它将 ko 解析为一个模块,并找到适当的 CDN 链接来解决 ko,而不是尝试下载 ./js/ko.js
.
要使用 data-main
属性来配置整个应用程序,它必须是所有代码的单个入口点。
第二个脚本块通过提供第二个入口点来打破此要求。 由于这些入口点将彼此独立(异步)解析,因此不能依赖一个入口点来影响另一个入口点。
若要解决此问题,请以向应用程序提供单个入口点的方式重构代码,并通过此入口点进行配置。
这是因为requirejs设置了异步。脚本的属性。
这意味着两个脚本脚本元素上的布尔异步属性允许外部 JavaScript 文件在可用时运行,不会延迟页面加载 第一。
都是并行加载和计算的,因此两个脚本都无法访问另一个脚本的方法或函数。如果要在一个脚本中定义requirejs变量,则不得使用requirejs加载该脚本。
对我来说,有三种可能性可以解决这个问题:
- 将 main.js 的内容添加到您的页面(如您所提到的)
- 加载主文件.js不需要 requirejs 作为普通脚本
- 在加载脚本之前定义 require 配置(链接到 requirejs docu )
我遇到了同样的问题。我正在工作的网站的体系结构是在页面的每个部分异步加载的组件。每个组件都有自己的 html、css 和 js 代码。因此,我的解决方案是为所有必需的依赖项代码保留一个保护函数,以保护它们不会在主 javascript 文件之前运行:
索引.html
<head>
<script type="text/javascript">
window.BeforeMainGuard = {
beforeMainLoadedFunctions: [],
hasMainLoaded: false,
guard: function( func ) {
console.assert( typeof func === 'function' );
if( this.hasMainLoaded ) {
func();
}else {
this.beforeMainLoadedFunctions.push( func );
}
},
onMainLoaded: function() {
for( var i = 0; i<this.beforeMainLoadedFunctions.length; ++i ) {
var beforeMainLoadedFunction = this.beforeMainLoadedFunctions[i];
beforeMainLoadedFunction();
}
this.beforeMainLoadedFunctions = null;
this.hasMainLoaded = true;
}
};
</script>
<script data-main="js/main.js" src="js/vendor/require.js"></script>
<script type="text/javascript">
window.BeforeMainGuard.guard( function() {
require(['viewmodel/vm', 'ko'],
function(viewmodel, ko) {
ko.applyBindings(viewmodel);
}
);
});
</script>
</head>
js/main.js
require.config({
// your config
});
require( [ 'AppLogic' ], function( AppLogic ){
AppLogic.Init();
window.BeforeMainGuard.onMainLoaded();
} );