web-dev-qa-db-fra.com

Comment gérer l'alias de chemin relatif dans plusieurs bundles grunt-browserify?

C'est un peu long mais j'aurai besoin de l'exemple de code pour illustrer ma confusion. Après quoi je suis intéressé par la réponse pour ce qui suit:

  1. Comment utiliser require('module') au lieu de require('../../src/module') ou require('./module')?
  2. Comment réutiliser ./index.js Dans spec/specs.js Sans dupliquer le travail? (Et empêchant src/app.js De fonctionner car c'est un module d'entrée).

J'ai déjà commencé plusieurs projets basés sur un navigateur et j'adore browserify et grognement. Mais chaque projet meurt au même point dans ma courbe de développement/apprentissage. Une fois que j'ajoute des tests au mélange et que je dois gérer deux browserify bundles (app.js Et spec/specs.js), Tout le système s'effondre. Je vais t'expliquer:

J'utilise grunt-browserify et définit mon répertoire initial:

.
├── Gruntfile.js
├── index.js  (generated via grunt-browserify)      [1]
├── lib
│   ├── jquery
│   │   └── jquery.js                               [2]
│   └── jquery-ui
│       └── jquery-ui.js                            [3]
├── spec
│   ├── specs.js  (generated via grunt-browserify)  [4]
│   └── src
│       ├── spec_helper.js  (entry)
│       └── module_spec.js  (entry)
└── src
    ├── app.js  (entry)
    └── module.js
  1. Utilise un fichier d'entrée (src/app.js) Et fait un tour de code pour regrouper tous les modules requis.
  2. Utilise browserify-shim pour alias jquery.
  3. Est simplement aliasé à jquery-ui Sans cale (requis après votre var $ = require('jquery')).
  4. Utilise tous les fichiers d'assistance et de spécification dans spec/src Comme modules d'entrée.

Je vais parcourir ma configuration:

browserify: {
  dist: {
    files: {
      'index.js': ['src/app.js']
    }
  }
}

// in app.js
var MyModule = require('./module'); // <-- relative path required?!

Heureux

Maintenant, ajoutez jquery:

browserify: {
  options: {
    shim: {
      jquery: {
        path: 'lib/jquery/jquery.js',
        exports: '$'
      }
    },
    noParse: ['lib/**/*.js'],
    alias: [
      'lib/jquery-ui/jquery-ui.js:jquery-ui'
    ]
  },
  dist: {
    files: {
      'index.js': ['src/app.js']
    }
  }
}

// in app.js
var $ = require('jquery');
require('jquery-ui');
var MyModule = require('./module');

Heureux

Ajoutez maintenant des spécifications:

options: {
  shim: {
    jquery: {
      path: 'lib/jquery/jquery.js',
      exports: '$'
    }
  },
  noParse: ['lib/**/*.js'],
  alias: [
    'lib/jquery-ui/jquery-ui.js:jquery-ui'
  ]
},
dist: {
  files: {
    'app.js': 'src/app.js'
  }
},
spec: {
  files: {
    'spec/specs.js': ['spec/src/**/*helper.js', 'spec/src/**/*spec.js']
  }
}

// in app.js
var $ = require('jquery');
require('jquery-ui');
var MyModule = require('./module');

// in spec/src/module_spec.js
describe("MyModule", function() {
  var MyModule = require('../../src/module'); // <-- This looks like butt!!!
});

Triste

Pour résumer: Comment puis-je ...

  1. Utilisez require('module') au lieu de require('../../src/module') ou require('./module')?
  2. réutiliser ./index.js dans spec/specs.js sans dupliquer le travail? (Et empêchant src/app.js De fonctionner car c'est un module d'entrée).
45
Sukima

Ces réponses dépendent de la configuration du reste de votre projet, mais c'est peut-être un bon point de départ. De plus, vous devrez utiliser la version bêta actuelle de grunt-browserify pour que cela fonctionne réellement (npm install grunt-browserify@2).

1.

Vous pouvez utiliser aliasMapping pour créer des alias dynamiques pour vos modules. Pour plus de clarté, permet de déplacer tous vos modules vers src/modules/. La configuration d'aliasMapping pourrait alors ressembler à ceci:

options: {
  aliasMappings: {
    cwd: 'src',
    src: ['modules/**/*.js']
  }
}

Supposons que vous ayez un module dans src/modules/magic/stuff.js, vous pouvez alors l'exiger comme ceci, quel que soit l'emplacement du fichier .js qui effectue l'exigence:

var magicStuff = require('modules/magic/stuff.js');

2.

Pas sûr de celui-ci. La structure de votre projet affiche un spec/index.js, mais vous mentionnez spec/specs.js. Sont-ils censés être le même fichier?

Quoi qu'il en soit, de quel travail en double parlez-vous? Car ./index.js a un fichier d'entrée différent de spec/index.js. Si vous cherchez un moyen d'inclure ./index.js dans specs/, alors vous pouvez peut-être le copier avant d'exécuter les tests au lieu de le construire à partir de zéro.

4
Joni Bekenstein

Réponse simple:

Le plus simple est d'utiliser l'option paths de browserify. Je l'utilise depuis quelques mois avec beaucoup de succès. J'ai même créé un kit de démarrage qui utilise cette fonctionnalité: https://github.com/stample/gulp-browserify-react-phonegap-starter

var b = browserify('./app', {paths: ['./node_modules','./src/js']});

chemins - tableau require.paths à utiliser si rien n'est trouvé sur la marche récursive normale de node_modules

Si vous avez un fichier dans src/js/modulePath/myModule.js, Cela ne vous permettra pas d'écrire require("myModule") partout, mais plutôt require("modulePath/myModule"), à partir de n'importe lequel de vos autres fichiers source.

Option obsolète?

Cela ne semble pas ainsi!

L'algorithme de résolution du module Browserify reflète le algorithme de résolution dans NodeJS . L'option paths de Browserify est donc le miroir du comportement de la variable env NODE_PATH Pour NodeJS. L'auteur de Browserify (sous-pile) affirme dans cette rubrique SO que l'option NODE_PATH Est déconseillée dans NodeJS et qu'elle est donc également déconseillée dans Browserify et pourrait être supprimée dans les prochaines versions.

Je ne suis pas d'accord avec cette affirmation.

Voir la documentation NODE_PATH . Il n'est pas mentionné que l'option est déconseillée. Cependant, il y a encore une mention intéressante qui va dans le sens de la revendication de substack:

Vous êtes fortement encouragé à placer vos dépendances localement dans les dossiers node_modules. Ils seront chargés plus rapidement et de manière plus fiable.

Et cette question a été publiée en 2012 sur la liste de diffusion.

Oliver Leics: is NODE_PATH deprecated? 
Ben Noordhuis (ex core NodeJS contributor): No. Why do you ask? 

Et si quelque chose n'est pas supprimé dans l'algorithme de résolution NodeJS, je ne pense pas qu'il sera supprimé de sitôt de Browserify :)

Conclusion

Vous pouvez utiliser l'option paths ou mettre votre code dans node_modules Comme la documentation officielle et l'auteur Browserify recommande .

Personnellement, je n'aime pas l'idée de mettre mon propre code dans node_modules Car je garde tout ce dossier hors de mon contrôle de source. J'utilise l'option paths depuis quelques mois maintenant et je n'ai eu aucun problème du tout, et ma vitesse de construction est plutôt bonne.

La solution de la sous-pile de mettre un lien symbolique à l'intérieur de node_modules Pourrait être pratique mais malheureusement, nous avons des développeurs travaillant avec Windows ici ...

Je pense qu'il y a cependant un cas où vous ne voulez pas utiliser l'option paths: lorsque vous développez une bibliothèque publiée sur un Référentiel NPM qui sera requis par d'autres applications. Vous ne voulez vraiment pas que ces clients de bibliothèque aient à configurer une configuration de construction spéciale simplement parce que vous vouliez éviter l'enfer de chemin relatif dans votre bibliothèque.

Une autre option possible consiste à utiliser remapify

30
Sebastien Lorber

Toutes les réponses ici sur les alias et opts.paths/$NODE_PATH Ne sont pas bonnes car cette approche est une partie obsolète du système de modules dans node et browserify, elle pourrait donc cesser de fonctionner à tout moment.

Vous devez apprendre comment fonctionne l'algorithme node_modules afin de pouvoir organiser efficacement votre code de manière à bien jouer avec les répertoires imbriqués node_modules.

Il y a une section dans le manuel browserify qui couvre en évitant ../../../../../../.. les problèmes de chemin relatif. Il peut être résumé comme suit:

  • Mettez votre code modulaire interne dans node_modules/ Ou node_modules/app Afin que vous puissiez require('yourmodule') ou require('app/yourmodule') selon ce que vous préférez.
  • Vous pouvez utiliser un lien symbolique si vous développez pour des plates-formes non Windows et c'est ce que vous préférez.

N'utilisez pas opts.path/$NODE_PATH. Cela rend votre projet:

  • dépendent implicitement d'une configuration ou d'un paramètre d'environnement non évident
  • plus difficile de faire fonctionner à la fois le nœud et le navigateur
  • vulnérable aux modifications du système de modules car les chemins d'accès aux tableaux sont déconseillés dans le nœud et la navigateur
7
substack

Je pense que la meilleure façon de procéder est, comme le note Sébastien Lorber, de définir le chemin dans votre appel de browserify à travers une pipe.

Mais avec la dernière version de browserify, (à partir de ce moment, c'est [email protected]) la variable path stocke les chemins niquement que Browserify utilisera pour son processus. Donc, la définition de la variable des chemins exclura, disons ... vos dossiers globaux pour le nœud, pour autant que je sache. En conséquence, vous aurez besoin d'une tâche Gulp qui ressemble un peu à ceci:

gulp.task('reactBuild', function() {
  return gulp.src(newThemeJSX)
    .pipe(browserify({
        debug: true,
        extensions: ['.jsx', '.js', '.json'],
        transform: [reactify],
        paths: ['../base_folder/node_modules', '/usr/lib/node_modules']
    }))
    .pipe(gulp.dest(newThemeBuilt))
    .on('error', function(error) {
        console.log(error);
    });
});
1
Chronotope