Skip to content

Commit

Permalink
Added additional settings. Closes: #285 (#316)
Browse files Browse the repository at this point in the history
## 🎯 Aim

Added a new additional step setting when scaffolding a new project to
specify if the node version manager configuration file should be created
or not.

## 📷 Result

![image](https://github.com/user-attachments/assets/e99d1ee8-2c0a-4070-8252-40086a50b222)

![image](https://github.com/user-attachments/assets/bca41a6a-7247-49e0-a51c-adb77d86982b)

## ✅ What was done

- [X] Added a new project additional step to create or not the node
version manager configuration file.
- [X] Added new VSCode setting `createNodeVersionFileDefaultValue` to
define the default value of the new project additional step.
- [X] Added new VSCode setting `nodeVersionManagerFile` to specify which
configuration file to be created.

## 🔗 Related issue

Closes: #285
  • Loading branch information
GuidoZam authored Oct 14, 2024
1 parent e13b2a9 commit e842630
Show file tree
Hide file tree
Showing 15 changed files with 213 additions and 5 deletions.
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ Install additional dependencies with a single click straight from the scaffoldin

![Additional dependency step](./assets/images/scaffolding-additional-step.png)

When you can set the additional dependencies it's also possible to automatically create the node version manager file with the version of Node.js used when creating the project. These settings are available in the extension settings.

![Additional dependency step node version](./assets/images/scaffolding-additional-step-node-version.png)

[Check out our docs for more details](https://github.com/pnp/vscode-viva/wiki/5.2-Scaffolding#1-scaffold-a-new-spfx-project)

### 6️⃣ Sign in to your tenant & retrieve environment details
Expand Down Expand Up @@ -272,7 +276,17 @@ Check it out in action 👇

By default, the SharePoint Framework Toolkit will use the Node.js version that is installed on your machine. If you want to use a different version, you can use a Node.js Version Manager such as [nvm](https://github.com/nvm-sh/nvm) or [nvs](https://github.com/jasongin/nvs). The SharePoint Framework Toolkit will detect the preferred version of Node.js if a `.nvmrc` file is present in the root of your project, and will use that version for all the actions.

You can use the settings to change which Node.js version manager you want to use. You may choose between `nvm` and `nvs`. If you wish to avoid using a Node.js version manager, you can set the value to `none`
It's possible to use the settings to change which Node.js version manager you want to use. You may choose between `nvm` and `nvs`. If you wish to avoid using a Node.js version manager, you can set the value to `none`

![Settings Node version manager](./assets/images/settings-node-version-manager.png)

Other than selecting the Node.js version manager you may also select which file should be used to store the Node.js version. By default, the extension will use `.nvmrc` file, but you may change it to `.node-version` if you are using `nvs`.

![Settings Node version file](./assets/images/settings-node-version-manager-file.png)

It is also possible to set the default behavior when you're about to scaffold a new project. To do so there is a specific setting named `Create Node Version File Default Value`.

![Settings Node version file default value](./assets/images/settings-node-version-manager-file-default-value.png)

### 1️⃣3️⃣ SPFx Toolkit GitHub Chat Participant

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/settings-node-version-manager.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions data/sp-dev-fx-samples.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

{
"samples": [
{
Expand Down
16 changes: 16 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,22 @@
"type": "boolean",
"default": true,
"description": "Show the tenant-wide extensions in the account view."
},
"spfx-toolkit.createNodeVersionFileDefaultValue": {
"title": "Default value for the Node version file option",
"type": "boolean",
"default": false,
"description": "The default value for the new project's setting for creating the Node version file. If checked the default selected value will be YES."
},
"spfx-toolkit.nodeVersionManagerFile": {
"title": "Node version manager file to be used",
"type": "string",
"default": ".nvmrc",
"enum": [
".nvmrc",
".node-version"
],
"description": "The file to be used to store the Node version for the selected Node version manager. Remember that the .node-version file is supported only while using nvs."
}
}
},
Expand Down
2 changes: 2 additions & 0 deletions src/constants/ProjectFileContent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ export enum ProjectFileContent {
installReusablePropertyPaneControls = 'install-spfx-property-controls',
installReusableReactControls = 'install-spfx-controls-react',
installPnPJs = 'install-pnpjs',
createNVMRCFile = 'create-nvmrc-file',
createNodeVersionFile = 'create-node-version-file',
}
7 changes: 7 additions & 0 deletions src/constants/WebviewCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ export const WebviewCommand = {
folderPath: 'folder-path',
validateSolutionName: 'validate-solution-name',
validateComponentName: 'validate-component-name',
createNodeVersionFileDefaultValue: 'should-create-node-version-file',
nodeVersionManager: 'node-version-manager',
nodeVersionManagerFile: 'node-version-manager-file',
createNodeVersionManagerFile: 'node-version-manager-file',
},
toVSCode: {
useSample: 'use-sample',
Expand All @@ -17,5 +21,8 @@ export const WebviewCommand = {
validateComponentName: 'validate-component-name',
addSpfxComponent: 'add-spfx-component',
createAppReg: 'create-app-reg',
createNodeVersionFileDefaultValue: 'should-create-node-version-file',
nodeVersionManager: 'node-version-manager',
nodeVersionManagerFile: 'node-version-manager-file',
}
};
12 changes: 12 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,18 @@ export async function activate(context: vscode.ExtensionContext) {
if (fileContents.indexOf(ProjectFileContent.installPnPJs) > -1) {
await TerminalCommandExecuter.runCommand('npm install @pnp/sp @pnp/graph --save', [], terminalTitle, terminalIcon);
}

// If either of the following strings are found in the project file, run the command to get the node version
if (fileContents.indexOf(ProjectFileContent.createNVMRCFile) > -1 || fileContents.indexOf(ProjectFileContent.createNodeVersionFile) > -1) {
let nodeVersionCommand = 'node --version > ';
if (fileContents.indexOf(ProjectFileContent.createNVMRCFile) > -1) {
nodeVersionCommand += '.nvmrc';
}
else if (fileContents.indexOf(ProjectFileContent.createNodeVersionFile) > -1) {
nodeVersionCommand += '.node-version';
}
await TerminalCommandExecuter.runCommand(nodeVersionCommand, [], terminalTitle, terminalIcon);
}
}
}
});
Expand Down
3 changes: 3 additions & 0 deletions src/models/SpfxScaffoldCommandInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,7 @@ export interface SpfxScaffoldCommandInput extends SpfxAddComponentCommandInput {
shouldInstallReusablePropertyPaneControls: boolean;
shouldInstallReusableReactControls: boolean;
shouldInstallPnPJs: boolean;
shouldCreateNodeVersionFile: boolean;
nodeVersionManagerFile: '.nvmrc' | '.node-version';
nodeVersionManager: 'nvm' | 'nvs' | 'none';
}
66 changes: 65 additions & 1 deletion src/services/actions/Scaffolder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import * as glob from 'fast-glob';
import { Extension } from '../dataType/Extension';
import download from 'github-directory-downloader/esm';
import { CliExecuter } from '../executeWrappers/CliCommandExecuter';
import { getPlatform } from '../../utils';
import { getExtensionSettings, getPlatform } from '../../utils';
import { PnPWebview } from '../../webview/PnPWebview';
import { Executer } from '../executeWrappers/CommandExecuter';
import { TeamsToolkitIntegration } from '../dataType/TeamsToolkitIntegration';
Expand Down Expand Up @@ -147,6 +147,45 @@ export class Scaffolder {
PnPWebview.postMessage(WebviewCommand.toWebview.validateComponentName, true);
}

/**
* Returns the value of the createNodeVersionFileDefaultValue setting and sends it to the webview.
*/
public static async createNodeVersionFileDefaultValue() {
const value = getExtensionSettings<boolean>(
'createNodeVersionFileDefaultValue',
false
);

PnPWebview.postMessage(
WebviewCommand.toWebview.createNodeVersionFileDefaultValue,
value
);
}

/**
* Returns the value of the nodeVersionManagerFile setting and sends it to the webview.
*/
public static async nodeVersionManagerFile() {
const value = getExtensionSettings<string>('nodeVersionManagerFile', '.nvmrc');

PnPWebview.postMessage(
WebviewCommand.toWebview.createNodeVersionManagerFile,
value
);
}

/**
* Returns the value of the nodeVersionManager setting and sends it to the webview.
*/
public static async nodeVersionManager() {
const value = getExtensionSettings<string>('nodeVersionManager', 'nvm');

PnPWebview.postMessage(
WebviewCommand.toWebview.nodeVersionManager,
value
);
}

/**
* Scaffold method for creating a new project.
* @param input - The input for the scaffold command.
Expand Down Expand Up @@ -225,6 +264,31 @@ export class Scaffolder {
content += ` ${ProjectFileContent.installPnPJs}`;
}

if (newSolutionInput.shouldCreateNodeVersionFile) {
switch (newSolutionInput.nodeVersionManager) {
case 'nvm':
// If the node version manager is nvm, create the .nvmrc file even if the user has selected .node-version
content += ` ${ProjectFileContent.createNVMRCFile}`;
break;
case 'nvs':
// If the node version manager is nvs, create the file based on the user's settings
switch (newSolutionInput.nodeVersionManagerFile) {
case '.nvmrc':
content += ` ${ProjectFileContent.createNVMRCFile}`;
break;
case '.node-version':
content += ` ${ProjectFileContent.createNodeVersionFile}`;
break;
}
break;
// If the node version manager is none, do not create any file
case 'none':
// By default, do not create any file
default:
break;
}
}

Scaffolder.createProjectFileAndOpen(newFolderPath, content);
} else {
PnPWebview.close();
Expand Down
9 changes: 9 additions & 0 deletions src/webview/PnPWebview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,15 @@ export class PnPWebview {
case WebviewCommand.toVSCode.createAppReg:
EntraAppRegistration.createEntraAppRegistration();
break;
case WebviewCommand.toVSCode.createNodeVersionFileDefaultValue:
Scaffolder.createNodeVersionFileDefaultValue();
break;
case WebviewCommand.toVSCode.nodeVersionManagerFile:
Scaffolder.nodeVersionManagerFile();
break;
case WebviewCommand.toVSCode.nodeVersionManager:
Scaffolder.nodeVersionManager();
break;
}
});
}
Expand Down
73 changes: 71 additions & 2 deletions src/webview/view/components/forms/spfxProject/AdditionalStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { VSCodeCheckbox } from '@vscode/webview-ui-toolkit/react';
import * as React from 'react';
import { StepHeader } from './StepHeader';
import { PackageSelector } from './PackageSelector';

import { WebviewCommand } from '../../../../../constants';
import { Messenger } from '@estruyf/vscode/dist/client';

interface AdditionalStepProps {
shouldRunInit: boolean;
Expand All @@ -13,6 +14,11 @@ interface AdditionalStepProps {
setShouldInstallReusableReactControls: (value: boolean) => void;
shouldInstallPnPJs: boolean;
setShouldInstallPnPJs: (value: boolean) => void;
shouldCreateNodeVersionFile: boolean;
setShouldCreateNodeVersionFile: (value: boolean) => void;
nodeVersionManager: 'nvm' | 'nvs' | 'none';
setNodeVersionManager: (value: 'nvm' | 'nvs' | 'none') => void;
setNodeVersionManagerFile: (value: '.nvmrc' | '.node-version') => void;
}

export const AdditionalStep: React.FunctionComponent<AdditionalStepProps> = ({
Expand All @@ -23,7 +29,64 @@ export const AdditionalStep: React.FunctionComponent<AdditionalStepProps> = ({
shouldInstallReusableReactControls,
setShouldInstallReusableReactControls,
shouldInstallPnPJs,
setShouldInstallPnPJs }: React.PropsWithChildren<AdditionalStepProps>) => {
setShouldInstallPnPJs,
shouldCreateNodeVersionFile,
setShouldCreateNodeVersionFile,
setNodeVersionManagerFile,
nodeVersionManager,
setNodeVersionManager
}: React.PropsWithChildren<AdditionalStepProps>) => {
// Send a message to retrieve the default value for the create node version file
const getCreateNodeVersionFileDefaultValue = React.useCallback(() => {
Messenger.send(WebviewCommand.toVSCode.createNodeVersionFileDefaultValue, {});
}, []);

// Send a message to retrieve the node version manager file
const getNodeVersionManagerFile = React.useCallback(() => {
Messenger.send(WebviewCommand.toVSCode.nodeVersionManagerFile, {});
}, []);

// Send a message to retrieve the node version manager
const getNodeVersionManager = React.useCallback(() => {
Messenger.send(WebviewCommand.toVSCode.nodeVersionManager, {});
}, []);

// Listen for the response to the message/s
React.useEffect(() => {
const messageListener = (event: MessageEvent<any>) => {
const { command, payload } = event.data;
switch (command) {
case WebviewCommand.toWebview.nodeVersionManager:
setNodeVersionManager(payload);
break;
case WebviewCommand.toWebview.nodeVersionManagerFile:
setNodeVersionManagerFile(payload);
break;
case WebviewCommand.toWebview.createNodeVersionFileDefaultValue:
setShouldCreateNodeVersionFile(payload);
break;
default:
break;
}
};

Messenger.listen(messageListener);

return () => {
Messenger.unlisten(messageListener);
};
}, [setNodeVersionManager, setNodeVersionManagerFile, setShouldCreateNodeVersionFile]);

// Sends the requests to load the settings values only once
React.useEffect(() => {
// Get the default value for the create node version file
getCreateNodeVersionFileDefaultValue();
// Get the node version manager
getNodeVersionManager();
// Get the node version manager file
getNodeVersionManagerFile();
}, []);

return (
<div className={'spfx__form__step'}>
<StepHeader step={3} title='Additional steps' />
Expand All @@ -50,6 +113,12 @@ export const AdditionalStep: React.FunctionComponent<AdditionalStepProps> = ({
setValue={setShouldInstallPnPJs}
label='Install PnPjs (@pnp/sp, @pnp/graph)'
link='https://pnp.github.io/pnpjs/' />

{nodeVersionManager !== 'none' &&
<PackageSelector
value={shouldCreateNodeVersionFile}
setValue={setShouldCreateNodeVersionFile}
label='Create node version manager configuration file' />}
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ export const ScaffoldSpfxProjectView: React.FunctionComponent<IScaffoldSpfxProje
const [shouldInstallReusablePropertyPaneControls, setShouldInstallReusablePropertyPaneControls] = useState<boolean>(false);
const [shouldInstallReusableReactControls, setShouldInstallReusableReactControls] = useState<boolean>(false);
const [shouldInstallPnPJs, setShouldInstallPnPJs] = useState<boolean>(false);
const [shouldCreateNodeVersionFile, setShouldCreateNodeVersionFile] = useState<boolean>(false);
const [nodeVersionManager, setNodeVersionManager] = useState<'nvm' | 'nvs' | 'none'>('nvm');
const [nodeVersionManagerFile, setNodeVersionManagerFile] = useState<'.nvmrc' | '.node-version'>('.nvmrc');
const location: any = useLocation();

useEffect(() => {
Expand Down Expand Up @@ -78,7 +81,10 @@ export const ScaffoldSpfxProjectView: React.FunctionComponent<IScaffoldSpfxProje
shouldRunInit,
shouldInstallReusablePropertyPaneControls,
shouldInstallReusableReactControls,
shouldInstallPnPJs
shouldInstallPnPJs,
shouldCreateNodeVersionFile,
nodeVersionManagerFile,
nodeVersionManager
} as SpfxScaffoldCommandInput);
}
};
Expand Down Expand Up @@ -124,6 +130,11 @@ export const ScaffoldSpfxProjectView: React.FunctionComponent<IScaffoldSpfxProje
setShouldInstallReusableReactControls={setShouldInstallReusableReactControls}
shouldInstallPnPJs={shouldInstallPnPJs}
setShouldInstallPnPJs={setShouldInstallPnPJs}
shouldCreateNodeVersionFile={shouldCreateNodeVersionFile}
setShouldCreateNodeVersionFile={setShouldCreateNodeVersionFile}
setNodeVersionManagerFile={setNodeVersionManagerFile}
setNodeVersionManager={setNodeVersionManager}
nodeVersionManager={nodeVersionManager}
/>
}
</div>
Expand Down

0 comments on commit e842630

Please sign in to comment.