Skip to content

Commit b2d2762

Browse files
Extension section gulp to heft migration (#10565)
* Migrate extension tutorials from gulp to heft build system * Minor changes * Changed heft command to bold * Updated building-simple-field-customizer.md to heft * Fix command formatting.
1 parent a2eb986 commit b2d2762

File tree

3 files changed

+41
-31
lines changed

3 files changed

+41
-31
lines changed

docs/spfx/extensions/get-started/building-form-customizer.md

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: Build your first Form customizer extension
33
description: Form customizers are SharePoint Framework components giving you an option to override the form experience at a list or library level by associating the component with the used content type.
4-
ms.date: 11/14/2025
4+
ms.date: 01/06/2025
55
ms.custom: scenarios:getting-started
66
---
77

@@ -15,8 +15,6 @@ Form customizers are SharePoint Framework components that give you an option to
1515
> [!TIP]
1616
> You can find the output from this tutorial from [GitHub](https://github.com/pnp/spfx-reference-scenarios/tree/main/samples/spfx-formcustomizer-basics).
1717
18-
[!INCLUDE [spfx-gulp-heft-migration-wip](../../../../includes/snippets/spfx-gulp-heft-migration-wip.md)]
19-
2018
## Create an extension project
2119

2220
1. Create a new project directory in your favorite location.
@@ -144,7 +142,7 @@ You can test and debug your Form Customizer within a live SharePoint Online site
144142

145143
Let's call out a few specific topics from the **serve.json** file
146144

147-
- You can see multiple different configurations that can be used to debug new, edit, and view forms with specific query parameter differences. You can define the used configuration in your gulp serve command, for example, as `gulp serve --config=helloWorld_EditForm`
145+
- You can see multiple different configurations that can be used to debug new, edit, and view forms with specific query parameter differences. You can define the used configuration in your **heft start** command, for example, as **heft start --serve-config helloWorld_EditForm**.
148146
- componentId is automatically associated to be the first list formatting component in your solution (if you have multiple components)
149147
- To simplify the debugging, you do not need to define the target content type `id` to which the component is associated, but in the runtime, the association is performed in the content type level by updating at least one of the following properties in the content type:
150148
- ContentType.**NewFormClientSideComponentId** - component id for new form
@@ -157,7 +155,7 @@ You can test and debug your Form Customizer within a live SharePoint Online site
157155
1. Compile your code and host the compiled files from the local machine by running this command:
158156

159157
```console
160-
gulp serve
158+
heft start
161159
```
162160

163161
When the code compiles without errors, it serves the resulting manifest from **https://localhost:4321**.
@@ -187,6 +185,11 @@ Now that we have created the baseline component and tested that it works properl
187185
Close: string;
188186
Title: string;
189187
}
188+
189+
declare module 'HelloWorldFormCustomizerStrings' {
190+
const strings: IHelloWorldFormCustomizerStrings;
191+
export = strings;
192+
}
190193
```
191194

192195
1. Open the **./src/extensions/helloWorld/loc/en-us.js** file, and add new **Title** string to the file. File content should be as follows after your edits.
@@ -205,7 +208,7 @@ Now that we have created the baseline component and tested that it works properl
205208
1. Open the **./src/extensions/helloWorld/HelloWorldFormCustomizer.module.scss** file, and update the styling definition as follows. We are adding error styling for the component.
206209

207210
```scss
208-
.helloWorld {
211+
.basics {
209212
background-color: "[theme:white, default:#ffffff]";
210213
color: "[theme:themePrimary, default:#0078d4]";
211214
padding: 0.5rem;
@@ -225,6 +228,7 @@ Now that we have created the baseline component and tested that it works properl
225228
SPHttpClient,
226229
SPHttpClientResponse
227230
} from '@microsoft/sp-http';
231+
import * as strings from 'HelloWorldFormCustomizerStrings';
228232
```
229233

230234
1. Include **_item** and **_etag** private types inside of the **HelloWorldFormCustomizer** class as shown in this code snippet. Notice that the class definition already exists in your code.
@@ -237,7 +241,7 @@ Now that we have created the baseline component and tested that it works properl
237241
// Added for the item to show in the form; use with edit and view form
238242
private _item: {
239243
Title?: string;
240-
};
244+
} = {};
241245
// Added for item's etag to ensure integrity of the update; used with edit form
242246
private _etag?: string;
243247
```
@@ -261,7 +265,7 @@ Now that we have created the baseline component and tested that it works properl
261265
.then(res => {
262266
if (res.ok) {
263267
// store etag in case we'll need to update the item
264-
this._etag = res.headers.get('ETag');
268+
this._etag = res.headers.get('ETag') || undefined;
265269
return res.json();
266270
}
267271
else {
@@ -292,7 +296,7 @@ Now that we have created the baseline component and tested that it works properl
292296
<input type="button" id="cancel" value="${strings.Close}" />
293297
</div>`;
294298

295-
document.getElementById('cancel').addEventListener('click', this._onClose.bind(this));
299+
document.getElementById('cancel')?.addEventListener('click', this._onClose.bind(this));
296300
}
297301
// render new/edit form
298302
else {
@@ -309,8 +313,8 @@ Now that we have created the baseline component and tested that it works properl
309313
<div class="${styles.error}"></div>
310314
</div>`;
311315

312-
document.getElementById('save').addEventListener('click', this._onSave.bind(this));
313-
document.getElementById('cancel').addEventListener('click', this._onClose.bind(this));
316+
document.getElementById('save')?.addEventListener('click', this._onSave.bind(this));
317+
document.getElementById('cancel')?.addEventListener('click', this._onClose.bind(this));
314318
}
315319
}
316320
```
@@ -322,17 +326,23 @@ Now that we have created the baseline component and tested that it works properl
322326
// disable all input elements while we're saving the item
323327
this.domElement.querySelectorAll('input').forEach(el => el.setAttribute('disabled', 'disabled'));
324328
// reset previous error message if any
325-
this.domElement.querySelector(`.${styles.error}`).innerHTML = '';
329+
const errorElement = this.domElement.querySelector(`.${styles.error}`);
330+
if (errorElement) {
331+
errorElement.innerHTML = '';
332+
}
326333

327-
let request: Promise<SPHttpClientResponse>;
328334
const title: string = (document.getElementById('title') as HTMLInputElement).value;
329-
335+
336+
let request: Promise<SPHttpClientResponse>;
330337
switch (this.displayMode) {
331338
case FormDisplayMode.New:
332339
request = this._createItem(title);
333340
break;
334341
case FormDisplayMode.Edit:
335342
request = this._updateItem(title);
343+
break;
344+
default:
345+
return;
336346
}
337347

338348
const res: SPHttpClientResponse = await request;
@@ -344,7 +354,10 @@ Now that we have created the baseline component and tested that it works properl
344354
else {
345355
const error: { error: { message: string } } = await res.json();
346356

347-
this.domElement.querySelector(`.${styles.error}`).innerHTML = `An error has occurred while saving the item. Please try again. Error: ${error.error.message}`;
357+
const errorElement = this.domElement.querySelector(`.${styles.error}`);
358+
if (errorElement) {
359+
errorElement.innerHTML = `An error has occurred while saving the item. Please try again. Error: ${error.error.message}`;
360+
}
348361
this.domElement.querySelectorAll('input').forEach(el => el.removeAttribute('disabled'));
349362
}
350363
}
@@ -374,7 +387,7 @@ Now that we have created the baseline component and tested that it works properl
374387
.post(this.context.pageContext.web.absoluteUrl + `/_api/web/lists/getByTitle('${this.context.list.title}')/items(${this.context.itemId})`, SPHttpClient.configurations.v1, {
375388
headers: {
376389
'content-type': 'application/json;odata.metadata=none',
377-
'if-match': this._etag,
390+
'if-match': this._etag || '*',
378391
'x-http-method': 'MERGE'
379392
},
380393
body: JSON.stringify({

docs/spfx/extensions/get-started/building-simple-cmdset-with-dialog-api.md

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: Build your first ListView Command Set extension
33
description: Create an extension project, and then code and debug your extension by using SharePoint Framework (SPFx) Extensions.
4-
ms.date: 12/14/2023
4+
ms.date: 01/06/2025
55
ms.custom: scenarios:getting-started
66
---
77
# Build your first ListView Command Set extension
@@ -12,8 +12,6 @@ You can follow these steps by watching the video on the Microsoft 365 Platform C
1212

1313
> [!Video https://www.youtube.com/embed/uaUGtLrNbRA]
1414
15-
[!INCLUDE [spfx-gulp-heft-migration-wip](../../../../includes/snippets/spfx-gulp-heft-migration-wip.md)]
16-
1715
## Create an extension project
1816

1917
1. Create a new project directory in your favorite location.
@@ -186,7 +184,7 @@ You cannot currently use the local Workbench to test SharePoint Framework Extens
186184
1. Compile your code and host the compiled files from the local machine by running this command:
187185

188186
```console
189-
gulp serve
187+
heft start
190188
```
191189

192190
When the code compiles without errors, it serves the resulting manifest from **https://localhost:4321**.
@@ -248,7 +246,7 @@ The default solution takes advantage of a new Dialog API, which can be used to s
248246
1. In your console window, ensure that you do not have any exceptions. If you do not already have the solution running in localhost, execute the following command:
249247

250248
```console
251-
gulp serve
249+
heft start
252250
```
253251

254252
1. Accept the loading of debug manifests by selecting **Load debug scripts** when prompted.
@@ -363,13 +361,13 @@ Since solutions will by default use the **asset packaging** capability, your Jav
363361
1. In the console window, enter the following command to package your client-side solution that contains the extension so that we get the basic structure ready for packaging:
364362

365363
```console
366-
gulp bundle --ship
364+
heft build --production
367365
```
368366

369367
1. Execute the following command so that the solution package is created:
370368

371369
```console
372-
gulp package-solution --ship
370+
heft package-solution --production
373371
```
374372

375373
The command creates the following package: **./sharepoint/solution/command-extension.sppkg** folder:

docs/spfx/extensions/get-started/building-simple-field-customizer.md

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: Build your first Field Customizer extension
33
description: Extensions are client-side components that run inside the context of a SharePoint page. Extensions can be deployed to SharePoint Online, and you can use modern JavaScript tools and libraries to build them.
4-
ms.date: 09/18/2025
4+
ms.date: 01/09/2026
55
ms.custom: scenarios:getting-started
66
---
77
# Build your first Field Customizer extension
@@ -12,8 +12,6 @@ You can follow these steps by watching the video on the Microsoft 365 Platform C
1212

1313
> [!Video https://www.youtube.com/embed/mBZ7Sq_KfDA]
1414
15-
[!INCLUDE [spfx-gulp-heft-migration-wip](../../../../includes/snippets/spfx-gulp-heft-migration-wip.md)]
16-
1715
## Create an extension project
1816

1917
1. Create a new project directory in your favorite location.
@@ -165,7 +163,7 @@ You can't use the local Workbench to test SharePoint Framework Extensions. You n
165163
1. Compile your code and host the compiled files from the local machine by running this command:
166164

167165
```console
168-
gulp serve
166+
heft start
169167
```
170168

171169
When the code compiles without errors, it serves the resulting manifest from **https://localhost:4321**.
@@ -220,10 +218,10 @@ Now that we've successfully tested the out-of-the-box starting point of the Fiel
220218
1. In the console window, ensure that you don't have any errors. If the solution isn't running, execute the following task:
221219

222220
```console
223-
gulp serve
221+
heft start
224222
```
225223

226-
1. In your previously created list, refresh the browser window with the debugging query parameters or restart the browser with **gulp serve**.
224+
1. In your previously created list, refresh the browser window with the debugging query parameters or restart the browser with **heft start**.
227225
1. Accept the loading of debug manifests by selecting **Load debug scripts** when prompted.
228226

229227
![Accept loading debug scripts](../../../images/ext-field-accept-debug-scripts.png)
@@ -320,13 +318,13 @@ Now you're ready to deploy the solution to a SharePoint site and get the field a
320318
1. In the console window, enter the following command to package your client-side solution that contains the extension so that we get the basic structure ready for packaging:
321319

322320
```console
323-
gulp bundle --ship
321+
heft build --production
324322
```
325323

326324
1. Execute the following command so that the solution package is created:
327325

328326
```console
329-
gulp package-solution --ship
327+
heft package-solution --production
330328
```
331329

332330
The command creates the package: **./sharepoint/solution/field-extension.sppkg**:
@@ -374,3 +372,4 @@ The process for publishing your app is identical among the different extension t
374372

375373
- [Build your first ListView Command Set extension](building-simple-cmdset-with-dialog-api.md)
376374
- [Overview of SharePoint Framework Extensions](../overview-extensions.md)
375+

0 commit comments

Comments
 (0)