web-dev-qa-db-fra.com

Chemins relatifs avec les modules/packages RequireJS

Je suis assez nouveau dans RequireJS et j'ai rencontré un petit problème. J'ai écrit un petit framework construit sur Backbone en utilisant RequireJS et je souhaite qu'il soit réutilisable dans différents projets. Donc, avec certaines recherches que j'ai apprises et qui nécessitent des paquets. Cela semblait être ce que je cherchais. J'ai un fichier main.js pour lancer mon application qui ressemble essentiellement à ceci:

require.config({
  packages: ['framework']
});

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

Ensuite, dans le même répertoire que mon main.js, j'ai un autre répertoire appelé "framework" qui contient un autre main.js qui ressemble à ceci:

define(function(require, exports, module) {
  exports.createDash = function(dash, element) {
    require(['dash/dash.model', 'dash/dash.view'], function(DashModel, DashView) {
      return new DashView({
        model: new DashModel(dash),
        el: element ? element : window
      });
    });
  };
});

En cherchant, j'ai trouvé cette page qui indique que l'argument 'require' doit être associé au sous-module. Cependant, lorsque j'essaie d'exiger des choses, elles sont toujours relatives à mon main.js. original. J'ai essayé un certain nombre de choses et cherché pendant des heures sans succès. Existe-t-il un moyen de faire inclure les appels requis/définir dans mon paquet par rapport au fichier main.js dans sa racine?

27
Justin Warkentin

Vous devez définir votre sous-module en tant que package dans la configuration requise:

require.config({
  packages: [
    { name: 'packagename',
      location: 'path/to/your/package/root',  // default 'packagename'
      main: 'scriptfileToLoad'                // default 'main' 
    }]
  ... some other stuff ...
});

Pour charger votre module, il vous suffit d'utiliser votre nom de fichier aux conditions requises:

define(['jquery', 'packagename'], function($, MyPackage) {
  MyPackage.useIt()
});

Dans votre package, vous devez utiliser le préfixe ./ pour charger vos fichiers par rapport à votre sous-module:

define(['globalDependency', './myLocalFile'], function(Asdf, LocalFile) {
  LocalFile.finallyLoaded();
});

Il existe un raccourci utile: si le nom de votre paquet est égal à votre emplacement et que votre fichier principal s'appelle 'main.js', vous pouvez alors le remplacer.

  packages: [
    { name: 'packagename',
      location: 'packagename',
      main: 'main'
    }]

pour ça:

  packages: ['packagename']

Autant que je sache, vous avez déjà essayé de définir un paquet, mais avez-vous également utilisé le préfixe ./? Sans ce préfixe, require tentera de trouver les fichiers dans son chemin racine global. Et sans paquet, ./ sera inutile car le chemin relatif est le même que le chemin racine global.


À votre santé

51
Simon Goller

J'ai compris la réponse à ma question et la solution (apparemment, ce n'était pas la même chose). Je suppose que je vais le poster ici au cas où cela pourrait aider quelqu'un d'autre à l'avenir.

Ce que je voulais essentiellement, c’était de charger mon framework dans son propre contexte. J'ai trouvé l'option de contexte dans la section section de configuration sur le site Web de require et un exemple d'utilisation de . A l'origine, j'ai essayé ceci en faisant quelque chose comme:

var req = require.config({
    baseUrl: 'framework',
    context: 'framework',

    paths: {
        jQuery: 'lib/jquery/jquery-1.7.min.js',
        Underscore: 'lib/underscore/underscore.min.js',
        Backbone: 'lib/backbone/backbone.min.js',
        etc...
    }
});

req(['main'], function() {});

Cela posait deux problèmes. Premièrement, ma variable 'req' était en cours de définition en dehors du cadre, mais je voulais que le cadre définisse ses propres chemins. Et deuxièmement, chaque fois qu'un fichier hors du cadre nécessiterait un fichier dans le cadre, ce qui nécessiterait à son tour "jQuery", par exemple, alors jQuery (ou autre chose) ne serait pas requis dans le contexte de l'instance de cadre. d'exiger et donc il n'a pas pu trouver le fichier.

Ce que j'ai fini par faire, c'est de définir le fichier main.js de mon framework comme suit:

var paths = {
    jQuery: 'lib/jquery/jquery-1.7.min.js',
    Underscore: 'lib/underscore/underscore.min.js',
    Backbone: 'lib/backbone/backbone.min.js',
    etc...
};

define(function() {
    var exports = {};

    exports.initialize = function(baseUrl, overridePaths, callback) {
        if(!overridePaths) {
        overridePaths = {};
        }
        if(baseUrl && baseUrl[baseUrl.length - 1] != '/') {
            baseUrl = baseUrl + '/';
        }

        var fullpaths = {};
        for(var path in paths) {
            // Don't add baseUrl to anything that looks like a full URL like 'http://...' or anything that begins with a forward slash
            if(paths[path].match(/^(?:.*:\/\/|\/)/)) {
                fullpaths[path] = paths[path];
            }
            else {
                fullpaths[path] = baseUrl + paths[path];
            }
        }

        var config = {paths: fullpaths};
        for(var pathName in overridePaths) {
            config.paths[pathName] = overridePaths[pathName];
        }
        require.config(config);

        // Do anything else you need to do such as defining more functions for exports

        if(callback) {
            callback();
        }
    }

    return exports;
});

Et puis dans le fichier main.js de mon projet, je fais juste ceci:

require(['framework/main'], function(framework) {
    // NOTE: This setTimeout() call is used because, for whatever reason, if you make
    //       a 'require' call in here or in the framework without it, it will just hang
    //       and never actually go fetch the files in the browser. There's probably a
    //       better way to handle this, but I don't know what it is.
    setTimeout(function() {
        framework.initialize('framework', null, function() {
            // Do stuff here
        }
    }, 0);
});

Cela prend tout ce qui est passé dans la méthode initialize () du framework pour 'baseURL' et le précède pour tous les chemins définis par le framework qui ne commencent pas par une barre oblique ni par 'rien: //', à moins qu'il s'agisse de chemins de substitution. Cela permet au paquet utilisant le framework de remplacer des choses comme 'jQuery'.

5
Justin Warkentin

Cela a fonctionné pour moi, en ajoutant un préfixe "./" aux noms de modules:

define(function (require, exports, module) {
    exports.createDash = function (dash, element) {
        require([ './dash/dash.model', './dash/dash.view' ], function (DashModel, DashView) {
            return new DashView({
                model : new DashModel(dash),
                el : element ? element : window
            });
        });
    };
});
2
Paul Grime

Un processus qui fonctionnait bien pour moi pour autoriser l’utilisation directe d’un paquet contenant des sous-modules à partir de data-main ou d’un cadre externe, en supposant qu’un main.js (ou un autre paquet principal) est appelé par un nom particulier, devait utiliser var baseUrl = require.toUrl('packageName') + '/../' comme préfixe d'un fichier de configuration require.config({ paths: { ... } }). Par exemple:

var music21Base = require.toUrl('music21') + '/../';

require.config({ paths: {
                          'jquery': music21Base + 'ext/jquery/jquery.2.1.10.min';
                          'subModuleLoader': music21Base + 'src/subModuleLoader';
                         }  });

La configuration de context: "xxx" a bien fonctionné pour appeler des modules normaux avec ./modName, mais n'a pas fonctionné pour l'argument paths pour moi.

1