-
Notifications
You must be signed in to change notification settings - Fork 8
feat: add Blazor project scaffolding options and templates #1719
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
c66d7b5
f67a692
e027399
93e6807
be0a75b
cea62f1
a0cb226
a437b10
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| import { | ||
| ControlExtraConfiguration, ControlExtraConfigType, defaultDelimiters, | ||
| DotnetTemplateManager, ProjectTemplate, ScaffoldOptions | ||
| } from "@igniteui/cli-core"; | ||
|
|
||
| export class EmptyIgbProject implements ProjectTemplate { | ||
|
|
||
| public id: string = "empty"; | ||
| public name = "Blazor Web App"; | ||
| public description = "Ignite UI for Blazor Web App, scaffolded via the IgniteUI.Blazor.Templates package"; | ||
| public framework: string = "blazor"; | ||
| public projectType: string = "igb"; | ||
| public dependencies: string[] = []; | ||
| public hasExtraConfiguration: boolean = true; | ||
| public isHidden: boolean = false; | ||
| public delimiters = defaultDelimiters; | ||
| public templatePaths: string[] = []; | ||
|
|
||
| private extraConfiguration: { [key: string]: any } = {}; | ||
|
|
||
| public getExtraConfiguration(): ControlExtraConfiguration[] { | ||
| return [ | ||
| { | ||
| choices: ["Server", "Wasm", "Auto"], | ||
| default: "Server", | ||
| key: "Hosting", | ||
| message: "Choose the hosting model:", | ||
| type: ControlExtraConfigType.Choice | ||
| }, | ||
| { | ||
| choices: ["light", "dark"], | ||
| default: "light", | ||
| key: "Variant", | ||
| message: "Choose the theme variant:", | ||
| type: ControlExtraConfigType.Choice | ||
| } | ||
| ]; | ||
| } | ||
|
|
||
| public setExtraConfiguration(extraConfigKeys: {} | any[]) { | ||
| if (Array.isArray(extraConfigKeys)) { | ||
| // the wizard supplies answers positionally, matching getExtraConfiguration() order | ||
| const keys = this.getExtraConfiguration().map(c => c.key); | ||
| extraConfigKeys.forEach((value, i) => { | ||
| if (keys[i] !== undefined) { | ||
| this.extraConfiguration[keys[i]] = value; | ||
| } | ||
| }); | ||
| } else { | ||
| this.extraConfiguration = { ...this.extraConfiguration, ...extraConfigKeys }; | ||
| } | ||
| } | ||
|
|
||
| public scaffold(options: ScaffoldOptions): Promise<boolean> { | ||
| const extraConfig = { ...this.extraConfiguration, ...options.extraConfig }; | ||
| return Promise.resolve(DotnetTemplateManager.scaffold({ ...options, extraConfig })); | ||
| } | ||
|
|
||
| // Unused — the host calls scaffold() instead of the generateConfig pipeline when scaffold exists. | ||
| public installModules(): void { | ||
| throw new Error("Method not implemented."); | ||
| } | ||
| public upgradeIgniteUIPackages(_projectPath: string, _packagePath: string): Promise<boolean> { | ||
| throw new Error("Method not implemented."); | ||
| } | ||
| public generateConfig(_name: string, _theme: string, ..._options: any[]): { [key: string]: any; } { | ||
| throw new Error("Method not implemented."); | ||
| } | ||
| } | ||
| export default new EmptyIgbProject(); |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -2,7 +2,7 @@ import * as path from "path"; | |||||
| import { Separator } from "@inquirer/prompts"; | ||||||
| import { BaseTemplateManager } from "../templates"; | ||||||
| import { | ||||||
| Component, Config, ControlExtraConfigType, ControlExtraConfiguration, Framework, | ||||||
| BaseTemplate, Component, Config, ControlExtraConfigType, ControlExtraConfiguration, Framework, | ||||||
| FrameworkId, ProjectLibrary, ProjectTemplate, Template | ||||||
| } from "../types"; | ||||||
| import { App, ChoiceItem, GoogleAnalytics, ProjectConfig, Util } from "../util"; | ||||||
|
|
@@ -60,20 +60,44 @@ export abstract class BasePromptSession { | |||||
| // project options: | ||||||
| theme = await this.getTheme(projLibrary); | ||||||
|
|
||||||
| Util.log(" Generating project structure."); | ||||||
| const config = projTemplate.generateConfig(projectName, theme); | ||||||
| for (const templatePath of projTemplate.templatePaths) { | ||||||
| await Util.processTemplates(templatePath, path.join(process.cwd(), projectName), | ||||||
| config, projTemplate.delimiters, false); | ||||||
| if (projTemplate.hasExtraConfiguration) { | ||||||
| await this.customizeTemplateTask(projTemplate); | ||||||
| } | ||||||
|
|
||||||
| Util.log(Util.greenCheck() + " Project structure generated."); | ||||||
| if (!this.config.skipGit) { | ||||||
| Util.gitInit(process.cwd(), projectName); | ||||||
| if (typeof projTemplate.scaffold === "function") { | ||||||
| Util.log(" Generating project structure."); | ||||||
| const success = await projTemplate.scaffold({ | ||||||
| name: projectName, | ||||||
| theme, | ||||||
| skipInstall: false, | ||||||
| skipGit: this.config.skipGit | ||||||
| }); | ||||||
| if (!success) { | ||||||
| return; | ||||||
| } | ||||||
| // the scaffold service never touches git, so initialize git here when requested | ||||||
| if (!this.config.skipGit) { | ||||||
| Util.gitInit(process.cwd(), projectName); | ||||||
| } | ||||||
| // move cwd to project folder | ||||||
| process.chdir(projectName); | ||||||
| await this.configureAI(framework.id); | ||||||
|
Comment on lines
+79
to
+84
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was also flagged from copilot on my side. The whole point is that in new.ts: process.chdir(argv.name);
await configure(argv.framework, { ... }); // ← AI config written FIRST
process.chdir("..");
Util.gitInit(process.cwd(), argv.name); // ← then committed |
||||||
| } else { | ||||||
| Util.log(" Generating project structure."); | ||||||
| const config = projTemplate.generateConfig(projectName, theme); | ||||||
| for (const templatePath of projTemplate.templatePaths) { | ||||||
| await Util.processTemplates(templatePath, path.join(process.cwd(), projectName), | ||||||
| config, projTemplate.delimiters, false); | ||||||
| } | ||||||
|
|
||||||
| Util.log(Util.greenCheck() + " Project structure generated."); | ||||||
| if (!this.config.skipGit) { | ||||||
| Util.gitInit(process.cwd(), projectName); | ||||||
| } | ||||||
| // move cwd to project folder | ||||||
| process.chdir(projectName); | ||||||
| await this.configureAI(framework.id); | ||||||
| } | ||||||
| // move cwd to project folder | ||||||
| process.chdir(projectName); | ||||||
| await this.configureAI(framework.id); | ||||||
| } | ||||||
| await this.chooseActionLoop(projLibrary); | ||||||
| //TODO: restore cwd? | ||||||
|
|
@@ -302,7 +326,7 @@ export abstract class BasePromptSession { | |||||
| } | ||||||
|
|
||||||
| /** Create prompts from template extra configuration and assign user answers to the template */ | ||||||
| protected async customizeTemplateTask(template: Template) { | ||||||
| protected async customizeTemplateTask(template: BaseTemplate) { | ||||||
| const extraPrompt = this.createQuestions(template.getExtraConfiguration()); | ||||||
| const extraConfigAnswers = []; | ||||||
| for (const question of extraPrompt) { | ||||||
|
|
@@ -428,6 +452,27 @@ export abstract class BasePromptSession { | |||||
| case "Complete & Run": | ||||||
| const config = ProjectConfig.localConfig(); | ||||||
|
|
||||||
| if (!config.project) { | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
The current code is more like an assumption rather than a check if it's Blazor app |
||||||
| // Blazor (scaffolded via dotnet) has no cli-config — print next-steps instead of | ||||||
| // routing through completeAndRun (npm + start.start, which requires a cli-config). | ||||||
| const projectName = path.basename(process.cwd()); | ||||||
| if (Util.canPrompt() && await InquirerWrapper.confirm({ | ||||||
| message: "Run the app now (dotnet run)?", | ||||||
| default: false | ||||||
| })) { | ||||||
| const result = Util.spawnSync("dotnet", ["run", "--project", projectName], { stdio: "inherit" }); | ||||||
| if (result.error || result.status !== 0) { | ||||||
| Util.error("dotnet run failed (see dotnet output above).", "red"); | ||||||
| } | ||||||
| } else { | ||||||
| Util.log(""); | ||||||
| Util.log("Next Steps:"); | ||||||
| Util.log(` cd ${projectName}`); | ||||||
| Util.log(` dotnet run --project ${projectName}`); | ||||||
|
dkalinovInfra marked this conversation as resolved.
|
||||||
| } | ||||||
| break; | ||||||
| } | ||||||
|
|
||||||
| if (config.project.framework === "angular" && | ||||||
| config.project.projectType === "igx-ts" && | ||||||
| !config.packagesInstalled) { | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This regex doesn't allow spaces, apart from
isAlphanumericExt. So if a user creates project with spaces, he won't get the warning abbout the namespace namingThis is also related to a bigger problem with having spaces in app names, that is marked in
DotnetTemplateManager.scaffold()