J'écris mon premier générateur Yeoman, qui déclenche l'utilisateur pour diverses entrées et crée de manière conditionnelle des fichiers en fonction de leurs réponses. Je dois pouvoir appeler un sous-programme (pourrait être un sous-générateur Yeoman) en fonction de l'entrée de l'utilisateur et lui transmettre des arguments.
La raison pour laquelle je veux utiliser les fonctions nommées (qui ne s'exécute pas automatiquement) est que parfois la réponse de l'utilisateur devrait invoquer un certain nombre de fonctions combinées, et parfois la fonction doit être exécutée seule.
Ce que j'ai essayé:
Je pensais que les sous-générateurs étaient le chemin à parcourir, puisque je crée des jeux de fichiers uniquement si l'utilisateur les demande. Mais j'ai du mal à les appeler conditionnellement et à leur transmettre l'entrée fournie par l'utilisateur. J'ai essayé d'utiliser hookFor
, mais je reçois l'erreur d'assertion: hookFor must be used within the constructor only
. (Parce que je ne veux pas qu'il soit exécuté par défaut, j'appelle le sous-générateur de mon this.prompt(prompts, function (props)
).
La question:
Comment puis-je appeler une routine uniquement si l'utilisateur la demande (via une invite) et transmet cette routine à certaines informations fournies par l'utilisateur?
Si vous avez la gentillesse de répondre, n'assumez pas que j'ai essayé quelque chose d'évident ;-).
Considérons que vous avez un générateur de generator-blog
(BlogGenerator) avec deux sous-générateurs (blog-serveur et blog-client):
app\index.js client\index.js server\index.js
Donc, lorsque vous vous dirigez yo blog
ce que vous demandez à l'utilisateur pour certaines options et exécutez (éventuellement) les sous-générateurs, n'est-ce pas?
Pour exécuter un sous- this.invoke("generator_namespace", {options: {}})
vous devez appeler this.invoke("generator_namespace", {options: {}})
. Le deuxième argument que nous avons passé peut avoir un champ d' options
– c'est l'objet d'options qui sera transmis au générateur.
Dans app \ index.js:
BlogGenerator.prototype.askFor = function askFor() { var cb = this.async(); // have Yeoman greet the user. console.log(this.yeoman); var prompts = [{ name: 'appName', message: 'Enter your app name', default: 'MyBlog' }, { type: 'confirm', name: 'createServer', message: 'Would you like to create server project?', default: true }, { type: 'confirm', name: 'createClient', message: 'Whould you like to create client project?', default: true }]; this.prompt(prompts, function (props) { this.appName = props.appName; this.createServer = props.createServer; this.createClient = props.createClient; cb(); }.bind(this)); } BlogGenerator.prototype.main = function app() { if (this.createClient) { // Here: we'are calling the nested generator (via 'invoke' with options) this.invoke("blog:client", {options: {nested: true, appName: this.appName}}); } if (this.createServer) { this.invoke("blog:server", {options: {nested: true, appName: this.appName}}); } };
Dans client \ index.js:
var BlogGenerator = module.exports = function BlogGenerator(args, options, config) { var that = this; yeoman.Base.apply(this, arguments); // in this.options we have the object passed to 'invoke' in app/index.js: this.appName = that.options.appName; this.nested = that.options.nested; }; BlogGenerator .prototype.askFor = function askFor() { var cb = this.async(); if (!this.options.nested) { console.log(this.yeoman); } }
MISE À JOUR 2015-12-21 :
L'utilisation d' invoke
est obsolète maintenant et doit être remplacée par une composeWith
. Mais ce n'est pas aussi facile que possible. La principale différence entre invoke
et composeWith
est que maintenant vous n'avez aucune capacité à contrôler les sous-générateurs. Vous ne pouvez que déclarer les utiliser.
Voici comment main
méthode main
de ci-dessus devrait ressembler à:
BlogGenerator.prototype.main = function app() { if (this.createClient) { this.composeWith("blog:client", { options: { nested: true, appName: this.appName } }, { local: require.resolve("./../client") }); } if (this.createServer) { this.composeWith("blog:server", { options: { nested: true, appName: this.appName } }, { local: require.resolve("./../server") }); } };
J'ai également remplacé yeoman.generators.Base
with yeoman.Base
.
Mise à jour 2015-04: l'apman Yeoman comprend maintenant this.composeWith
comme la méthode préférée pour lier les générateurs.
Vous pouvez couvrir tous les scénarios d'exécution possibles, la vérification des conditions, les invites lors de la composition des générateurs ensemble si vous découpler les générateurs et utiliser un «générateur principal», la boucle du contexte de l'exécution vous aidera. Utilisez les options
de .composeWith('my-genertor', { 'options' : options })
pour passer des configurations aux générateurs composés.
Lors de l'utilisation de .composeWith
une fonction de groupe de priorité (p. Ex.: prompting
, writing
…) sera exécuté pour tous les générateurs, puis le groupe de priorité suivant. Si vous appelez .composeWith
au generatorB de l'intérieur d'un generatorA , l'exécution sera, par exemple:
GeneratorA.prompting => generatorB.prompting => generatorA.writing => generatorB.writing
Si vous souhaitez contrôler l'exécution entre différents générateurs, je vous conseille de créer un générateur "principal" qui les compose, comme écrit sur http://yeoman.io/authoring/composability.html#order :
// In my-generator/generators/turbo/index.js module.exports = require('yeoman-generator').Base.extend({ 'prompting' : function () { console.log('prompting - turbo'); }, 'writing' : function () { console.log('prompting - turbo'); } }); // In my-generator/generators/electric/index.js module.exports = require('yeoman-generator').Base.extend({ 'prompting' : function () { console.log('prompting - zap'); }, 'writing' : function () { console.log('writing - zap'); } }); // In my-generator/generators/app/index.js module.exports = require('yeoman-generator').Base.extend({ 'initializing' : function () { this.composeWith('my-generator:turbo'); this.composeWith('my-generator:electric'); } });