19

是否可以使用 requireJS 来“要求”整个文件夹。

例如,我有一个包含大量行为 js 文件的行为文件夹。我真的很想能够简单地使用 require(['behaviors/*'], function() {...}); 加载该文件夹中的所有内容,而不必使该列表保持最新。压缩和优化后,我会将所有这些文件放在一起,但对于开发来说,单独使用它们会更容易。

4

5 回答 5

24

浏览器中的 javascript 没有文件系统访问权限,因此无法扫描目录中的文件。如果您正在使用 php 或 ruby​​ 等脚本语言构建应用程序,您可以编写一个脚本来扫描目录并将文件名添加到 require() 调用中。

于 2011-05-05T05:35:28.167 回答
8

我不知道我是否可以再推荐这种方法。我认为更明确的方法是手动“要求”/“导出”您需要的功能。我认为的例外情况是,如果您有要导出的文件的“命名空间”,请参见下文“Babel 和 ES6 模块导入声明(export-namespace-from)或参见下文“Babel 和 ES6 模块导入声明。

这些解决方案还假设您有一个有意义的文件结构——其中文件名成为“需要”*定义的一部分。

但是,如果您仍然需要这样做,那么有一些现有的工具和方法可能会提供您正在寻找的行为。


可能的解决方案

Babel 和 ES6 模块导入声明(plugin-export-namespace-from)

  1. 有一个符合 ES6的设置。
  2. 您需要更新.babelrc文件以包含babel-plugin-proposal-export-namespace-from
  3. 通过编写如下语法来使用导出命名空间插件:

常见/index.js

export * from './common/a'; // export const a = false;
export * from './common/b'; // export const b = true;

main.js

import { a, b } from './common';

console.log(a); // false
console.log(b); // true

Babel 和 ES6 模块导入声明(插件通配符)

  1. 有一个符合 ES6的设置。
  2. 您需要更新.babelrc文件以包含babel-plugin-wildcard
  3. 通过编写如下语法来使用通配符命名空间插件:

main.js

import { a, b } from './common/*'; // imports './common/a.js' and './common/b.js'

console.log(a); // false
console.log(b); // true

RequireJS(现已过时)

  1. 下载并安装require-wild npm install require-wild
  2. 配置声明如下
    grunt.initConfig({
        requireWild: {
            app: {
                // Input files to look for wildcards (require|define)
                src: ["./**/*.js"], 

                // Output file contains generated namespace modules
                dest: "./namespaces.js", 

                // Load your require config file used to find baseUrl - optional
                options: { requireConfigFile: "./main.js" }
            }
        }
    }); 
    
    grunt.loadNpmTasks("require-wild");
    
    grunt.registerTask('default', ['requireWild']);
  1. 然后运行 ​​grunt 任务。您的文件将被生成。修改您的设置以加载namespaces.js

require(['namespaces'], function () { ... });

  1. 这现在允许下面src的模块使用依赖项 glob 模式匹配。

require(['behaviors/**/*'], function (behaviors) { }

于 2013-11-29T05:21:22.307 回答
5

我知道这是旧的,但我想分享我的解决方案:

对于此解决方案,您需要 JQuery

1) 创建一个bash 脚本,列出"MyDirectory/"中的所有 js 文件,并将其保存到 "directoryContents.txt"

#!/bin/bash
  #Find all the files in that directory...
  for file in $( find MyDirectory/ -type f -name "*.js" )
        do
          fileClean=${file%.js} #Must remove .js from the end!
          echo -n "$fileClean " >> MyDirectory/directoryContents.txt
        done
  • 文件将如下所示:

我的目录/FirstJavascriptFile 我的目录/SecondJavascriptFile 我的目录/ThirdJavascriptFile

  • 我的脚本有问题!最后多加一个“”,搞砸了!确保删除directoryContents.txt末尾的多余空间

2)然后在您的客户端JS代码中:

  • 执行“GET”请求以检索文本文件
  • 对于每个条目(由空格分隔),“需要”该文件:

.

$.get( "MyDirectory/directoryContents.txt", {}, function( data ) {
    var allJsFilesInFolder = data.split(" ");
    for(var a=0; a<allJsFilesInFolder.length; a++)
    {
        require([allJsFilesInFolder[a]], function(jsConfig) 
        {
            //Done loading this one file
        });
    }
}, "text");

我遇到了这个代码在我的其他代码之前没有完成的问题,所以这是我的扩展答案:

define([''], function() {

return {

    createTestMenu: function() 
    {
        this.loadAllJSFiles(function(){
            //Here ALL those files you need are loaded!
        });
    },

    loadAllJSFiles: function(callback)
    {   
        $.get( "MyDirectory/directoryContents.txt", {}, function( data ) {
            var allJsFilesInFolder = data.split(" ");
            var currentFileNum = 0;
            for(var a=0; a<allJsFilesInFolder.length; a++)
            {
                require([allJsFilesInFolder[a]], function(jsConfig) 
                {
                    currentFileNum++;
                    //If it's the last file that needs to be loaded, run the callback.
                    if (currentFileNum==allJsFilesInFolder.length)
                    {
                        console.log("Done loading all configuration files.");
                        if (typeof callback != "undefined"){callback();}
                    }
                });
            }
        }, "text");
    }
}
});

我最终做的是每次我的节点服务器启动时,它将运行 bash 脚本,填充 directoryContents.txt。然后我的客户端只是读取 directoryContents.txt 的文件列表,并需要该列表中的每个。

希望这可以帮助!

于 2013-11-19T02:01:43.127 回答
1

实际上并没有一种方法可以在概念上即时执行此操作(据我所知)。

不过有一些解决方法:

使用grunt然后concat只需要那个庞然大物......我知道,有点糟糕。

我认为是一个更好的解决方案......使用这样的要求层次结构:

require('/js/controllers/init', function(ctrls){
    ctrls(app, globals);
});

// /js/controllers/init.js
define('js/controllers/index', 'js/controllers/posts', function(index, posts){
    return function protagonist(app, globals){
        var indexModule = index(app, globals);
        var indexModule = posts(app, globals);

        return app || someModule;
    };
});

// /js/controllers/index.js
define('js/controllers/index', 'js/controllers/posts', function(index, posts){
    return function protagonist(app, globals){
        function method1(){}
        function method2(){}

        return {
           m1: method1,
           m2: method2
        };
    };
});

请注意“ protagonistfunction。这允许您在使用模块之前对其进行初始化,因此现在您可以传入一个 ' sandbox' - 在这种情况下appglobals.

实际上,你不会有/js/controllers/index.js......它可能应该是这样的东西/js/controllers/index/main.js/js/controllers/index/init.js有一个与(兄弟)相邻的目录,/js/controllers/init.js称为“索引”。这将使您的模块可扩展到给定的接口——您可以简单地交换模块并保持您的接口相同。

希望这可以帮助!快乐编码!

于 2013-12-23T23:32:26.987 回答
1

我写了一个库来解决这个问题。最终其他人出现并改进了我的图书馆,这里是:

https://github.com/smartprocure/directory-metagen

您可以将我的库与 Gulp 或其他任何东西一起使用 - 它为您的项目生成元数据,而 RequireJS 可以使用该元数据从文件系统中获取所需的文件。

使用这个库将生成一个 RequireJS 模块,看起来像这样:

define(
    [
        "text!app/templates/dashboardTemplate.ejs",
        "text!app/templates/fluxCartTemplate.ejs",
        "text!app/templates/footerTemplate.ejs",
        "text!app/templates/getAllTemplate.ejs",
        "text!app/templates/headerTemplate.ejs",
        "text!app/templates/homeTemplate.ejs",
        "text!app/templates/indexTemplate.ejs",
        "text!app/templates/jobsTemplate.ejs",
        "text!app/templates/loginTemplate.ejs",
        "text!app/templates/overviewTemplate.ejs",
        "text!app/templates/pictureTemplate.ejs",
        "text!app/templates/portalTemplate.ejs",
        "text!app/templates/registeredUsersTemplate.ejs",
        "text!app/templates/userProfileTemplate.ejs"
    ],
    function(){

        return {

            "templates/dashboardTemplate.ejs": arguments[0],
            "templates/fluxCartTemplate.ejs": arguments[1],
            "templates/footerTemplate.ejs": arguments[2],
            "templates/getAllTemplate.ejs": arguments[3],
            "templates/headerTemplate.ejs": arguments[4],
            "templates/homeTemplate.ejs": arguments[5],
            "templates/indexTemplate.ejs": arguments[6],
            "templates/jobsTemplate.ejs": arguments[7],
            "templates/loginTemplate.ejs": arguments[8],
            "templates/overviewTemplate.ejs": arguments[9],
            "templates/pictureTemplate.ejs": arguments[10],
            "templates/portalTemplate.ejs": arguments[11],
            "templates/registeredUsersTemplate.ejs": arguments[12],
            "templates/userProfileTemplate.ejs": arguments[13]
        }
    });

然后,您可以像这样在前端 require 模块:

var footerView = require("app/js/jsx/standardViews/footerView");

但是,正如您所看到的,这太冗长了,所以神奇的方式是这样的:

将上面的依赖项命名为 allViews!

现在你可以这样做:

var allViews = require('allViews');
var footerView = allViews['standardViews/footerView'];

要求整个目录有两个优点:

(1) 在生产环境中,使用 r.js 优化器,您可以指向一个依赖项(模块 A),然后它可以轻松跟踪 A 的所有代表整个目录的依赖项

(2) 在开发中,您可以预先要求整个目录,然后使用同步语法来要求依赖项,因为您知道它们已经被加载

享受“RequireJS-Metagen”

https://github.com/smartprocure/directory-metagen

https://www.npmjs.com/package/requirejs-metagen

https://github.com/ORESoftware/requirejs-metagen

于 2015-09-15T00:18:05.037 回答