Closed ghost closed 4 years ago
Seems duplicate of https://github.com/jhipster/generator-jhipster/issues/10663
Suggested fix at: https://github.com/jhipster/generator-jhipster/pull/10664
@mshima thanks, I read that. But is it more simple to overwrite the yeoman generator name function in the app index jhipster generator? In this way it is compatibility with the standard jhipster code in case of no main app customization.
Changing rootGeneratorName is exactly the same of this.config = this._getStorage('generator-jhipster');
https://github.com/jhipster/generator-jhipster/pull/10664 Is about migrating old projects.
See https://github.com/yeoman/generator/pull/1122/files
This was merged at yeoman-generator 4.1.0. Jhipster depends on 3.2.0. So, it will not work with 6.6.0 blueprints.
rootGeneratorVersion does nothing here. It’s used at global config only.
https://github.com/yeoman/generator/search?utf8=✓&q=rootGeneratorVersion&type=
rootGeneratorVersion does nothing here. It’s used at global config only.
https://github.com/yeoman/generator/search?utf8=✓&q=rootGeneratorVersion&type=
Yes in jhipster is not used, I added that only because it is associated with the generator name, so if I change the name function sequentially is usefull to specify the related version
See https://github.com/yeoman/generator/pull/1122/files
This was merged at yeoman-generator 4.1.0. Jhipster depends on 3.2.0. So, it will not work with 6.6.0 blueprints.
It's not mandatory to update yeoman-generator for 4.x version. The rootGeneratorName method is already added in the 3.2.0 version : https://github.com/yeoman/generator/blob/3bbeef0f8eebd02e9459734c9a3d9c6732a47d14/lib/index.js#L597 . From yeoman-generator 4.1.0 is been only modified the getStorage() method with the generator name argument. So it works for jhipster 6.6.0, because my suggestion is only to overwrite that method, used in the storage class, in the jhipster app index generator (and not use the getStorage method passing the generator name as argument directly in the jhipster app).
Please don’t change rootGeneratorName(). It’s a bad workaround and will break my blueprint.
This can be done at the blueprint, doesn’t need to be at generator-jhipster.
Please don’t change rootGeneratorName(). It’s a bad workaround and will break my blueprint.
This can be done at the blueprint, doesn’t need to be at generator-jhipster.
Why will break your blueprint? It is an override only for the app index generator to use its standard config (and not of the blueprint). For me it's a function to add in the main app generator (and not in the blueprint), because it resolve a break of the jhipster extension not due to the blueprint itself but for jhipster configuration mode.
It is an override only for the app index generator to use its standard config (and not of the blueprint)
Currently there isn’t a standard config (generator-jhipster namespace) and a blueprint config (generator-jhipster-something namespace). There is only a standard config for not blueprinted generators and blueprint config for blueprinted generators.
For me it's a function to add in the main app generator (and not in the blueprint)
When you blueprint a generator, the main generator doesn’t run the normal cycle. It only instantiate the blueprinted version and stop.
The main generator and blueprinted generator doesn’t run together. So you are proposing to change a main generator function with the purpose to change the blueprint config object. This will unnecessary change rootGeneratorName behavior (my blueprint uses it) for every blueprint.
When you blueprint a generator, the main generator doesn’t run the normal cycle. It only instantiate the blueprinted version and stop.
It's not totally exact, because initially, creating a blueprint with the generator-jhipster-blueprint , I have classes for every subgenerator that inherit the standard jhipster phases. For example:
/* eslint-disable consistent-return */ const chalk = require('chalk'); const ServerGenerator = require('generator-jhipster/generators/server'); module.exports = class extends ServerGenerator { constructor(args, opts) { super(args, { fromBlueprint: true, ...opts }); // fromBlueprint variable is important const jhContext = (this.jhipsterContext = this.options.jhipsterContext); if (!jhContext) { this.error(`This is a JHipster blueprint and should be used only like ${chalk.yellow('jhipster --blueprint test')}`); } this.configOptions = jhContext.configOptions || {}; // This sets up options for this sub generator and is being reused from JHipster jhContext.setupServerOptions(this, jhContext); } get initializing() { /** * Any method beginning with _ can be reused from the superclass `ServerGenerator` * * There are multiple ways to customize a phase from JHipster. * * 1. Let JHipster handle a phase, blueprint doesnt override anything. * ``` * return super._initializing(); * ``` * * 2. Override the entire phase, this is when the blueprint takes control of a phase * ``` * return { * myCustomInitPhaseStep() { * // Do all your stuff here * }, * myAnotherCustomInitPhaseStep(){ * // Do all your stuff here * } * }; * ``` * * 3. Partially override a phase, this is when the blueprint gets the phase from JHipster and customizes it. * ``` * const phaseFromJHipster = super._initializing(); * const myCustomPhaseSteps = { * displayLogo() { * // override the displayLogo method from the _initializing phase of JHipster * }, * myCustomInitPhaseStep() { * // Do all your stuff here * }, * } * return Object.assign(phaseFromJHipster, myCustomPhaseSteps); * ``` */ // Here we are not overriding this phase and hence its being handled by JHipster return super._initializing(); } get prompting() { // Here we are not overriding this phase and hence its being handled by JHipster return super._prompting(); } get configuring() { // Here we are not overriding this phase and hence its being handled by JHipster return super._configuring(); } get default() { // Here we are not overriding this phase and hence its being handled by JHipster return super._default(); } get writing() { // Here we are not overriding this phase and hence its being handled by JHipster return super._writing(); } get install() { // Here we are not overriding this phase and hence its being handled by JHipster return super._install(); } get end() { // Here we are not overriding this phase and hence its being handled by JHipster return super._end(); } };
So in my blueprint I can choose to leave the class in that way, and my generator executes the standard jhipster lifecycle for the server subgenerator. And all works well, also If I customize, for example only the initializing phase entirely or merging with the super._initializing():
const phaseFromJHipster = super._initializing();
return Object.assign(phaseFromJHipster, myCustomPhaseSteps);
But If I add an extension, without customize anything, in my blueprint for the app index in the same way:
/* eslint-disable consistent-return */ const chalk = require('chalk'); const AppGenerator = require('generator-jhipster/generators/app'); module.exports = class extends AppGenerator { constructor(args, opts) { super(args, { fromBlueprint: true, ...opts }); // fromBlueprint variable is important const jhContext = (this.jhipsterContext = this.options.jhipsterContext); if (!jhContext) { this.error(`This is a JHipster blueprint and should be used only like ${chalk.yellow('jhipster --blueprint test')}`); } this.configOptions = jhContext.configOptions || {}; // This sets up options for this sub generator and is being reused from JHipster jhContext.setupServerOptions(this, jhContext); } get initializing() { /** * Any method beginning with _ can be reused from the superclass `AppGenerator` * * There are multiple ways to customize a phase from JHipster. * * 1. Let JHipster handle a phase, blueprint doesnt override anything. * ``` * return super._initializing(); * ``` * * 2. Override the entire phase, this is when the blueprint takes control of a phase * ``` * return { * myCustomInitPhaseStep() { * // Do all your stuff here * }, * myAnotherCustomInitPhaseStep(){ * // Do all your stuff here * } * }; * ``` * * 3. Partially override a phase, this is when the blueprint gets the phase from JHipster and customizes it. * ``` * const phaseFromJHipster = super._initializing(); * const myCustomPhaseSteps = { * displayLogo() { * // override the displayLogo method from the _initializing phase of JHipster * }, * myCustomInitPhaseStep() { * // Do all your stuff here * }, * } * return Object.assign(phaseFromJHipster, myCustomPhaseSteps); * ``` */ // Here we are not overriding this phase and hence its being handled by JHipster return super._initializing(); } get prompting() { // Here we are not overriding this phase and hence its being handled by JHipster return super._prompting(); } get configuring() { // Here we are not overriding this phase and hence its being handled by JHipster return super._configuring(); } get default() { // Here we are not overriding this phase and hence its being handled by JHipster return super._default(); } get writing() { // Here we are not overriding this phase and hence its being handled by JHipster return super._writing(); } get install() { // Here we are not overriding this phase and hence its being handled by JHipster return super._install(); } get end() { // Here we are not overriding this phase and hence its being handled by JHipster return super._end(); } };
My blueprint generator already breaks. The reason is that the jhipster app generator does not manage well blueprint extension in the same way of server, client, entity subgenerators. Why? Because it set its variables with the yeaman this.config method with the namespace of the blueprint. It's the same thing done for every subgenerator, but for the app generator does not work because the standard jhipster phase app, inherited by the blueprint, want to read configuration in its namespace ("generator-jhipster") and therefore the variables retrivied are undefined: https://github.com/jhipster/generator-jhipster/blob/57ea50ad7d3654c5308690d6e8bd43e3932dae97/generators/app/index.js#L292
And raise after the error:
events.js:174
throw er; // Unhandled 'error' event
^
TypeError: Cannot read property 'blueprints' of undefined
at loadBlueprintsFromConfiguration (C:\Users\Sweet\Desktop\github\generator-
jhipster-nodejs\node_modules\generator-jhipster\generators\utils.js:565:38)
So to resolve this just add this method in the jhipster main index app generator:
/**
* Override yeoman standard storage function for yo-rc.json.
* @return {String} The name of the root generator
*/
rootGeneratorName() {
return packagejs.name;
}
Where packagejs.name is "generator-jhipster" string. In this way the blueprint app class, that inherited this, does not break. Also if you don't add an app extension class in your blueprint, your blueprint does not break because in all cases the configuration (for the app generator) are retrivied well in the "generator-jhipster" key from the .yo-rc.json (and it works also if you run jhipster without blueprint).
So it is not a problem of the blueprint, but an error beheviour of the jhipster app generator when it is used as inherited class ( but for the other subgenerator all works well).
So you are proposing to change a main generator function with the purpose to change the blueprint config object.
No, because I'm not changing the blueprint config object and I'm not customizing anything yet, it's the jhipster app generator that wants to keep to read variables with its namespace, when they are stored from yeoman in the blueprint namespace by its default behavior.
Besides the rootGeneratorName is used only in the storage class to save and read configuration by yeoman, changing it the result is only in that class, that not affect the classes of the other subgenerators (server, client, entity...).
The others generators works because of: https://github.com/jhipster/generator-jhipster/blob/7b2f6dd6cac86633879898f3b693f170e9e2e682/generators/client/index.js#L86
But current getAllJhipsterConfig implementation reads blueprints from generator-jhipster namespace. https://github.com/jhipster/generator-jhipster/blob/7b2f6dd6cac86633879898f3b693f170e9e2e682/generators/utils.js#L501
The other generators work because the values read by the getAllJhipsterConfig in the "generator-jhipster" key are defined and stored in the .yo-rc.json by the generator app before running the subgenerators. But if you extend the main app, as I have said before, all is stored under blueprint namespace in the .yo-rc.json (nothing exist under "generator-jhipster" key). So after all will break.
Overview of the issue
From the jhipster 6.6.0 version due to the #10752 PR , it's possible to extend the app generator in the blueprint. It is a great thing, but the problem is that the variables saved by the yeoman config.set method, add all under the blueprint key name in the .yo-rc.json file. So in the re-generation (or the import-jdl command with the config specified in the jdl model), the variables retrieved in the .yo-rc.json file by the this.config.get(variableName) method of the jhipster standard app index.js, are undefined because they are not saved under the "generator-jhipster" key of the yo-rc.json file.
Motivation for or Use Case
The motivation is that the yeoman-generator standard class uses a storage class to save configuration in the .yo-rc.json file. For this, it uses a method to define the key name using the package.json name field of the project class that extends that class. So these variables saved by the jhipster app generator, are stored in the blueprint name key instead of "generator-jhipster" key name.
Reproduce the error
In my scenario, the blueprint name is generator-jhipster-nodejs. Run the following command without a yo-rc.json file in the root folder:
jhipster --blueprints nodejs
After answering all the questions, I have:
.yo-rc.json file
I rerun the previous command, and the first error is the 'blueprints' properties undefined:
Suggest a Fix
In the nodejs blueprint I overwrote the yeoman rootGeneratorName method in the custom app generator. In my opinion this method must be added in the jhipster main app together the rootGeneratorVersion method, using the jhipster package name and version:
In that way the .yo-rc.json stored will be:
.yo-rc.json file
And it doesn't raise any errors, in addition to be compatible with the standard jhipster configuration.
JHipster configuration
JHpster: 6.6.0
JHipster configuration, a
.yo-rc.json
file generated in the root folder.yo-rc.json file
**JDL for the Entity configuration(s)
entityName.json
files generated inthe
.jhipster
directory**JDL entity definitions
Environment and Tools
java version "1.8.0_65" Java(TM) SE Runtime Environment (build 1.8.0_65-b17) Java HotSpot(TM) 64-Bit Server VM (build 25.65-b01, mixed mode)
git version 2.9.3.windows.2
node: v10.15.3
npm: 5.3.0
yeoman: 3.1.0
yarn: 1.3.2
Browsers and Operating System
OS: Windows and linux