requirejs回调未定义

时间:2014-12-20 12:24:39

标签: node.js requirejs

项目结构

root
    wwwroot <-- files under this location are static files public to the site
        css
        lib
            bootstrap/js/bootstrap.js
            jquery/js/jquery.js
            knockout/knockout.js
            requires/require.js
        scripts
            modules               ┌───────────────┐
                global.js      <--│ Built modules │
                dropdown.js       └───────────────┘
    modules
        global.js                 ┌────────────────┐
        dropdown               <--│ Source modules │
            dropdown.js           └────────────────┘
    gruntfile.js

global.cs目录(〜/ modules / global.js预构建版本)

require.config({
    baseUrl: "scripts/modules",
    paths: {
        jquery: "../../lib/jquery/js/jquery",
        bootstrap: "../../lib/bootstrap/js/bootstrap",
        knockout: "../../lib/knockout/knockout"
    },
    shims: {
        bootstrap: {
            deps: ['jquery']
        }
    },
});

define(function (require) {
    var $ = require('jquery');
    var ko = require('knockout');
    var bootstrap = require('bootstrap');
});

dropdown.js目录(〜/ modules / dropdown.js预建版本)

define(function () {
    console.log('dropdown initialized');
    return 'foo';
});

HTML页面

在页面的<head>中包含此脚本标记,用于加载需要config:

<script src="~/lib/requirejs/require.js" data-main="scripts/modules/global"></script>

在HTML页面的正文中,我有以下内容:

<script>
    require(['global'], function () {
        require(['dropdown'], function (dropdown) {
            console.log(dropdown);
        });
    });
</script>

问题

dropdown回调是undefined,而不是我从定义的模块返回的预期“foo”字符串。

实际上,控制台也没有包含“dropdown initialized”的日志项。这让我相信模块没有以某种方式被调用?但是,很奇怪dropdown.js作为加载到页面中的脚本存在于F12调试器中。因此,require需要调用加载它,但是没有运行define的内容吗?

值得注意的提及

  • 我正在使用r.js进行优化和构建。 global.js和dropdown.js都经过处理。
  • r.js处理分配给下拉模块的名称是“modules / dropdown / dropdown.js”。我不确定我是否应该以某种方式使用它,或者我是否正确地将模块称为dropdown并且依赖于具有正确路径的baseUrl配置。

编辑#1

我已经为每个评论者请求添加了与grunt一起使用的r.js构建配置。与此同时,我更新了文件结构以包含整体项目结构,而不仅仅是运行时公共wwwroot结构。

r.js流程将汇总来自源位置~/wwwroot/scripts/modules的{​​{1}}中的global.js +其他模块的构建形式。

~/modules

编辑#2

认为包含我正在使用的requirejs包的版本是个好主意:

function getRequireJsConfiguration() {
    var baseUrl = './';
    var paths = {
        jquery: "wwwroot/lib/jquery/js/jquery",
        bootstrap: "wwwroot/lib/bootstrap/js/bootstrap",
        knockout: "wwwroot/lib/knockout/knockout"
    };
    var shims = {
        bootstrap: {
            deps: ['jquery']
        }
    };
    var optimize = 'none';

    var configuration = {};

    var jsFilePaths = grunt.file.expand('modules/**/*.js');
    jsFilePaths.forEach(function (jsFilePath) {
        var fileName = jsFilePath.split('/').pop();

        if (configuration[fileName]) {
            throw 'Duplicate module name conflict: ' + fileName;
        }

        configuration[fileName] = {
            options: {
                baseUrl: './',
                name: jsFilePath,
                out: 'wwwroot/scripts/modules/' + fileName,
                paths: paths,
                shims: shims,
                optimize: optimize,
                exclude: ['jquery', 'knockout', 'bootstrap']
            }
        };
    });

    configuration['global'] = {
        options: {
            baseUrl: './',
            name: 'modules/global.js',
            out: 'wwwroot/scripts/modules/global.js',
            paths: paths,
            shims: shims,
            optimize: optimize,
        }
    };

    return configuration;
}

感谢。

3 个答案:

答案 0 :(得分:1)

  

r.js处理分配给下拉模块的名称是&#34; modules / dropdown / dropdown.js&#34;。我不确定我是否应该以某种方式使用它,或者我是否正确引用该模块只是下拉并依赖我的baseUrl配置具有正确的路径。

从某种意义上说,是的,你应该使用那条完整的道路。这就是Require所指的模块ID - &#34; modules / dropdown / dropdown&#34; (如果上面输出中的.js是真实的,我建议在&#34;名称中删除该扩展名&#34;配置.js由RequireJS承担,你不希望你的模块ID中的那个字符串) 。当给定ID时,使用basePath将一些未知ID转换为文件路径(例如&#39; bootstrap&#39; id - &gt;(应用路径配置) - &gt;&#39; ../../ lib / bootstrap / js / bootstrap&#39; - &gt;(应用基本URL) - &gt;&#39; scripts / modules /../../ lib / bootstrap / js / bootstrap&#39;)。

但是,真的,只允许r.js将所有内容连接到一个文件中 是首选的方式。您可以使用include选项将global.js未引用的模块包含在优化的包中(https://github.com/jrburke/r.js/blob/master/build/example.build.js#L438

至于您的具体问题:您的懒惰require(['dropdown'])电话会误导您。通过将请求的模块ID与basePath组合,RequireJS会提供您想要的URL - scripts/modules/dropdown - 它定义了模块标识为scripts/module/dropdown的模块 - 但是因为您请求了模块标识{{1}你什么也得不到。 (我猜想你会得到一个RuntimeError而不是undefined,但我想这就是事情的进展)。您需要以某种方式解决ID /路径不匹配问题。

答案 1 :(得分:1)

虽然我已经通过 wyantb 的提示解决了我的问题,但由于其带来的简单性,我已经将我的方法改为单个文件concat。我仍然希望发布我如何解决这个问题的具体细节,以便其他任何人能够解决这个问题。

在grunt构建配置选项中,我添加了onBuildWrite字段来转换内容,因此我分配的模块ID与我懒得加载它们的方式排成一行。

onBuildWrite: function (moduleName, path, contents) {
    return contents.replace(/modules\/global.js/, 'global');
}

此代码专门用于global.js文件。我为其他模块文件(在foreach循环中)实现了类似的onBuildWrite。转换将基本上从r.js指定的模块名称中删除路径和扩展名。

以下是之前和之后的一些示例:

Before                                After
/modules/global.js                    global
/modules/dropdown/dropdown.js         dropdown
/modules/loginButton/loginButton.js   loginButton

因此,当我使用原始问题中的HTML脚本加载模块时,requirejs会解析并找到匹配项。

答案 2 :(得分:-1)

要么按路径要求,要么在global.cs中定义globaldropdown

require(['./global'], function () {
    require(['./dropdown'], function (dropdown) {
        console.log(dropdown);
    });
});