diff --git a/01-intro.pptx b/01-intro.pptx index cd28037..742d5c4 100755 Binary files a/01-intro.pptx and b/01-intro.pptx differ diff --git a/02-dev-tools.pptx b/02-dev-tools.pptx index 1af0422..7541abf 100755 Binary files a/02-dev-tools.pptx and b/02-dev-tools.pptx differ diff --git a/Demos/01-appcatalog/README.md b/Demos/01-appcatalog/README.md index 090d982..be91ea6 100644 --- a/Demos/01-appcatalog/README.md +++ b/Demos/01-appcatalog/README.md @@ -4,7 +4,7 @@ This completed project is the result of the lab exercise **Create and Configure ## Prerequisites -- [Microsoft 365 tenant](https://developer.microsoft.com/en-us/microsoft-365/dev-program?ocid=MSlearn) +- [Microsoft 365 tenant](https://developer.microsoft.com/microsoft-365/dev-program?ocid=MSlearn) ## Instructions diff --git a/Demos/02-setup-env/README.md b/Demos/02-setup-env/README.md index 5ec1468..7bf9048 100644 --- a/Demos/02-setup-env/README.md +++ b/Demos/02-setup-env/README.md @@ -4,7 +4,7 @@ This completed project is the result of the lab exercise **Configure your ShareP ## Prerequisites -- [Microsoft 365 tenant](https://developer.microsoft.com/en-us/microsoft-365/dev-program?ocid=MSlearn) +- [Microsoft 365 tenant](https://developer.microsoft.com/microsoft-365/dev-program?ocid=MSlearn) - [Visual Studio Code](https://code.visualstudio.com/) ## Instructions diff --git a/Demos/03-webpart/.eslintrc.js b/Demos/03-webpart/.eslintrc.js deleted file mode 100644 index 562b8f6..0000000 --- a/Demos/03-webpart/.eslintrc.js +++ /dev/null @@ -1,319 +0,0 @@ -require('@rushstack/eslint-config/patch/modern-module-resolution'); -module.exports = { - extends: ['@microsoft/eslint-config-spfx/lib/profiles/default'], - parserOptions: { tsconfigRootDir: __dirname }, - overrides: [ - { - files: ['*.ts', '*.tsx'], - parser: '@typescript-eslint/parser', - 'parserOptions': { - 'project': './tsconfig.json', - 'ecmaVersion': 2018, - 'sourceType': 'module' - }, - rules: { - // Prevent usage of the JavaScript null value, while allowing code to access existing APIs that may require null. https://www.npmjs.com/package/@rushstack/eslint-plugin - '@rushstack/no-new-null': 1, - // Require Jest module mocking APIs to be called before any other statements in their code block. https://www.npmjs.com/package/@rushstack/eslint-plugin - '@rushstack/hoist-jest-mock': 1, - // Require regular expressions to be constructed from string constants rather than dynamically building strings at runtime. https://www.npmjs.com/package/@rushstack/eslint-plugin-security - '@rushstack/security/no-unsafe-regexp': 1, - // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json - '@typescript-eslint/adjacent-overload-signatures': 1, - // RATIONALE: Code is more readable when the type of every variable is immediately obvious. - // Even if the compiler may be able to infer a type, this inference will be unavailable - // to a person who is reviewing a GitHub diff. This rule makes writing code harder, - // but writing code is a much less important activity than reading it. - // - // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json - '@typescript-eslint/explicit-function-return-type': [ - 1, - { - 'allowExpressions': true, - 'allowTypedFunctionExpressions': true, - 'allowHigherOrderFunctions': false - } - ], - // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json - // Rationale to disable: although this is a recommended rule, it is up to dev to select coding style. - // Set to 1 (warning) or 2 (error) to enable. - '@typescript-eslint/explicit-member-accessibility': 0, - // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json - '@typescript-eslint/no-array-constructor': 1, - // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json - // - // RATIONALE: The "any" keyword disables static type checking, the main benefit of using TypeScript. - // This rule should be suppressed only in very special cases such as JSON.stringify() - // where the type really can be anything. Even if the type is flexible, another type - // may be more appropriate such as "unknown", "{}", or "Record". - '@typescript-eslint/no-explicit-any': 1, - // RATIONALE: The #1 rule of promises is that every promise chain must be terminated by a catch() - // handler. Thus wherever a Promise arises, the code must either append a catch handler, - // or else return the object to a caller (who assumes this responsibility). Unterminated - // promise chains are a serious issue. Besides causing errors to be silently ignored, - // they can also cause a NodeJS process to terminate unexpectedly. - '@typescript-eslint/no-floating-promises': 2, - // RATIONALE: Catches a common coding mistake. - '@typescript-eslint/no-for-in-array': 2, - // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json - '@typescript-eslint/no-misused-new': 2, - // RATIONALE: The "namespace" keyword is not recommended for organizing code because JavaScript lacks - // a "using" statement to traverse namespaces. Nested namespaces prevent certain bundler - // optimizations. If you are declaring loose functions/variables, it's better to make them - // static members of a class, since classes support property getters and their private - // members are accessible by unit tests. Also, the exercise of choosing a meaningful - // class name tends to produce more discoverable APIs: for example, search+replacing - // the function "reverse()" is likely to return many false matches, whereas if we always - // write "Text.reverse()" is more unique. For large scale organization, it's recommended - // to decompose your code into separate NPM packages, which ensures that component - // dependencies are tracked more conscientiously. - // - // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json - '@typescript-eslint/no-namespace': [ - 1, - { - 'allowDeclarations': false, - 'allowDefinitionFiles': false - } - ], - // RATIONALE: Parameter properties provide a shorthand such as "constructor(public title: string)" - // that avoids the effort of declaring "title" as a field. This TypeScript feature makes - // code easier to write, but arguably sacrifices readability: In the notes for - // "@typescript-eslint/member-ordering" we pointed out that fields are central to - // a class's design, so we wouldn't want to bury them in a constructor signature - // just to save some typing. - // - // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json - // Set to 1 (warning) or 2 (error) to enable the rule - '@typescript-eslint/parameter-properties': 0, - // RATIONALE: When left in shipping code, unused variables often indicate a mistake. Dead code - // may impact performance. - // - // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json - '@typescript-eslint/no-unused-vars': [ - 1, - { - 'vars': 'all', - // Unused function arguments often indicate a mistake in JavaScript code. However in TypeScript code, - // the compiler catches most of those mistakes, and unused arguments are fairly common for type signatures - // that are overriding a base class method or implementing an interface. - 'args': 'none' - } - ], - // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json - '@typescript-eslint/no-use-before-define': [ - 2, - { - 'functions': false, - 'classes': true, - 'variables': true, - 'enums': true, - 'typedefs': true - } - ], - // Disallows require statements except in import statements. - // In other words, the use of forms such as var foo = require("foo") are banned. Instead use ES6 style imports or import foo = require("foo") imports. - '@typescript-eslint/no-var-requires': 'error', - // RATIONALE: The "module" keyword is deprecated except when describing legacy libraries. - // - // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json - '@typescript-eslint/prefer-namespace-keyword': 1, - // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json - // Rationale to disable: it's up to developer to decide if he wants to add type annotations - // Set to 1 (warning) or 2 (error) to enable the rule - '@typescript-eslint/no-inferrable-types': 0, - // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json - // Rationale to disable: declaration of empty interfaces may be helpful for generic types scenarios - '@typescript-eslint/no-empty-interface': 0, - // RATIONALE: This rule warns if setters are defined without getters, which is probably a mistake. - 'accessor-pairs': 1, - // RATIONALE: In TypeScript, if you write x["y"] instead of x.y, it disables type checking. - 'dot-notation': [ - 1, - { - 'allowPattern': '^_' - } - ], - // RATIONALE: Catches code that is likely to be incorrect - 'eqeqeq': 1, - // STANDARDIZED BY: eslint\conf\eslint-recommended.js - 'for-direction': 1, - // RATIONALE: Catches a common coding mistake. - 'guard-for-in': 2, - // RATIONALE: If you have more than 2,000 lines in a single source file, it's probably time - // to split up your code. - 'max-lines': ['warn', { max: 2000 }], - // STANDARDIZED BY: eslint\conf\eslint-recommended.js - 'no-async-promise-executor': 2, - // RATIONALE: Deprecated language feature. - 'no-caller': 2, - // STANDARDIZED BY: eslint\conf\eslint-recommended.js - 'no-compare-neg-zero': 2, - // STANDARDIZED BY: eslint\conf\eslint-recommended.js - 'no-cond-assign': 2, - // STANDARDIZED BY: eslint\conf\eslint-recommended.js - 'no-constant-condition': 1, - // STANDARDIZED BY: eslint\conf\eslint-recommended.js - 'no-control-regex': 2, - // STANDARDIZED BY: eslint\conf\eslint-recommended.js - 'no-debugger': 1, - // STANDARDIZED BY: eslint\conf\eslint-recommended.js - 'no-delete-var': 2, - // RATIONALE: Catches code that is likely to be incorrect - // STANDARDIZED BY: eslint\conf\eslint-recommended.js - 'no-duplicate-case': 2, - // STANDARDIZED BY: eslint\conf\eslint-recommended.js - 'no-empty': 1, - // STANDARDIZED BY: eslint\conf\eslint-recommended.js - 'no-empty-character-class': 2, - // STANDARDIZED BY: eslint\conf\eslint-recommended.js - 'no-empty-pattern': 1, - // RATIONALE: Eval is a security concern and a performance concern. - 'no-eval': 1, - // RATIONALE: Catches code that is likely to be incorrect - // STANDARDIZED BY: eslint\conf\eslint-recommended.js - 'no-ex-assign': 2, - // RATIONALE: System types are global and should not be tampered with in a scalable code base. - // If two different libraries (or two versions of the same library) both try to modify - // a type, only one of them can win. Polyfills are acceptable because they implement - // a standardized interoperable contract, but polyfills are generally coded in plain - // JavaScript. - 'no-extend-native': 1, - // Disallow unnecessary labels - 'no-extra-label': 1, - // STANDARDIZED BY: eslint\conf\eslint-recommended.js - 'no-fallthrough': 2, - // STANDARDIZED BY: eslint\conf\eslint-recommended.js - 'no-func-assign': 1, - // RATIONALE: Catches a common coding mistake. - 'no-implied-eval': 2, - // STANDARDIZED BY: eslint\conf\eslint-recommended.js - 'no-invalid-regexp': 2, - // RATIONALE: Catches a common coding mistake. - 'no-label-var': 2, - // RATIONALE: Eliminates redundant code. - 'no-lone-blocks': 1, - // STANDARDIZED BY: eslint\conf\eslint-recommended.js - 'no-misleading-character-class': 2, - // RATIONALE: Catches a common coding mistake. - 'no-multi-str': 2, - // RATIONALE: It's generally a bad practice to call "new Thing()" without assigning the result to - // a variable. Either it's part of an awkward expression like "(new Thing()).doSomething()", - // or else implies that the constructor is doing nontrivial computations, which is often - // a poor class design. - 'no-new': 1, - // RATIONALE: Obsolete language feature that is deprecated. - 'no-new-func': 2, - // RATIONALE: Obsolete language feature that is deprecated. - 'no-new-object': 2, - // RATIONALE: Obsolete notation. - 'no-new-wrappers': 1, - // RATIONALE: Catches code that is likely to be incorrect - // STANDARDIZED BY: eslint\conf\eslint-recommended.js - 'no-octal': 2, - // RATIONALE: Catches code that is likely to be incorrect - 'no-octal-escape': 2, - // RATIONALE: Catches code that is likely to be incorrect - // STANDARDIZED BY: eslint\conf\eslint-recommended.js - 'no-regex-spaces': 2, - // RATIONALE: Catches a common coding mistake. - 'no-return-assign': 2, - // RATIONALE: Security risk. - 'no-script-url': 1, - // STANDARDIZED BY: eslint\conf\eslint-recommended.js - 'no-self-assign': 2, - // RATIONALE: Catches a common coding mistake. - 'no-self-compare': 2, - // RATIONALE: This avoids statements such as "while (a = next(), a && a.length);" that use - // commas to create compound expressions. In general code is more readable if each - // step is split onto a separate line. This also makes it easier to set breakpoints - // in the debugger. - 'no-sequences': 1, - // RATIONALE: Catches code that is likely to be incorrect - // STANDARDIZED BY: eslint\conf\eslint-recommended.js - 'no-shadow-restricted-names': 2, - // RATIONALE: Obsolete language feature that is deprecated. - // STANDARDIZED BY: eslint\conf\eslint-recommended.js - 'no-sparse-arrays': 2, - // RATIONALE: Although in theory JavaScript allows any possible data type to be thrown as an exception, - // such flexibility adds pointless complexity, by requiring every catch block to test - // the type of the object that it receives. Whereas if catch blocks can always assume - // that their object implements the "Error" contract, then the code is simpler, and - // we generally get useful additional information like a call stack. - 'no-throw-literal': 2, - // RATIONALE: Catches a common coding mistake. - 'no-unmodified-loop-condition': 1, - // STANDARDIZED BY: eslint\conf\eslint-recommended.js - 'no-unsafe-finally': 2, - // RATIONALE: Catches a common coding mistake. - 'no-unused-expressions': 1, - // STANDARDIZED BY: eslint\conf\eslint-recommended.js - 'no-unused-labels': 1, - // STANDARDIZED BY: eslint\conf\eslint-recommended.js - 'no-useless-catch': 1, - // RATIONALE: Avoids a potential performance problem. - 'no-useless-concat': 1, - // RATIONALE: The "var" keyword is deprecated because of its confusing "hoisting" behavior. - // Always use "let" or "const" instead. - // - // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json - 'no-var': 2, - // RATIONALE: Generally not needed in modern code. - 'no-void': 1, - // RATIONALE: Obsolete language feature that is deprecated. - // STANDARDIZED BY: eslint\conf\eslint-recommended.js - 'no-with': 2, - // RATIONALE: Makes logic easier to understand, since constants always have a known value - // @typescript-eslint\eslint-plugin\dist\configs\eslint-recommended.js - 'prefer-const': 1, - // RATIONALE: Catches a common coding mistake where "resolve" and "reject" are confused. - 'promise/param-names': 2, - // RATIONALE: Catches code that is likely to be incorrect - // STANDARDIZED BY: eslint\conf\eslint-recommended.js - 'require-atomic-updates': 2, - // STANDARDIZED BY: eslint\conf\eslint-recommended.js - 'require-yield': 1, - // "Use strict" is redundant when using the TypeScript compiler. - 'strict': [ - 2, - 'never' - ], - // RATIONALE: Catches code that is likely to be incorrect - // STANDARDIZED BY: eslint\conf\eslint-recommended.js - 'use-isnan': 2, - // STANDARDIZED BY: eslint\conf\eslint-recommended.js - // Set to 1 (warning) or 2 (error) to enable. - // Rationale to disable: !!{} - 'no-extra-boolean-cast': 0, - // ==================================================================== - // @microsoft/eslint-plugin-spfx - // ==================================================================== - '@microsoft/spfx/import-requires-chunk-name': 1, - '@microsoft/spfx/no-require-ensure': 2, - '@microsoft/spfx/pair-react-dom-render-unmount': 1 - } - }, - { - // For unit tests, we can be a little bit less strict. The settings below revise the - // defaults specified in the extended configurations, as well as above. - files: [ - // Test files - '*.test.ts', - '*.test.tsx', - '*.spec.ts', - '*.spec.tsx', - - // Facebook convention - '**/__mocks__/*.ts', - '**/__mocks__/*.tsx', - '**/__tests__/*.ts', - '**/__tests__/*.tsx', - - // Microsoft convention - '**/test/*.ts', - '**/test/*.tsx' - ], - rules: {} - } - ] -}; \ No newline at end of file diff --git a/Demos/03-webpart/.gitignore b/Demos/03-webpart/.gitignore index 51ca7b9..5de8473 100644 --- a/Demos/03-webpart/.gitignore +++ b/Demos/03-webpart/.gitignore @@ -9,6 +9,10 @@ node_modules # Build generated files dist lib +lib-dts +lib-commonjs +lib-esm +jest-output release solution temp diff --git a/Demos/03-webpart/.npmignore b/Demos/03-webpart/.npmignore index ae0b487..b2625b8 100644 --- a/Demos/03-webpart/.npmignore +++ b/Demos/03-webpart/.npmignore @@ -1,16 +1,22 @@ -!dist -config +# Ignore everything by default +** -gulpfile.js +# Use negative patterns to bring back the specific things we want to publish +!/bin/** +!/dist/** +!/EULA/** +!/lib/** +!ThirdPartyNotice.txt -release -src -temp +# Ignore certain files in the above folders +/dist/*.stats.* +/dist/**/*.js.map +/lib/**/*.js.map +/lib/**/test/** -tsconfig.json -tslint.json - -*.log - -.yo-rc.json -.vscode +# NOTE: These don't need to be specified, because NPM includes them automatically. +# +# package.json +# README (and its variants) +# CHANGELOG (and its variants) +# LICENSE / LICENCE diff --git a/Demos/03-webpart/.yo-rc.json b/Demos/03-webpart/.yo-rc.json index f3be714..e0fd39b 100644 --- a/Demos/03-webpart/.yo-rc.json +++ b/Demos/03-webpart/.yo-rc.json @@ -1,15 +1,13 @@ { "@microsoft/generator-sharepoint": { + "useGulp": false, "plusBeta": false, "isCreatingSolution": true, - "nodeVersion": "18.20.4", - "sdksVersions": { - "@microsoft/microsoft-graph-client": "3.0.2", - "@microsoft/teams-js": "2.24.0" - }, - "version": "1.20.0", + "nodeVersion": "22.15.0", + "sdksVersions": {}, + "version": "1.23.0", "libraryName": "hello-world", - "libraryId": "58d1a1d0-097b-4d7f-8d8d-b4de9f45c2bf", + "libraryId": "bc092361-0ea2-42f1-b439-d362bcbd5301", "environment": "spo", "packageManager": "npm", "solutionName": "hello-world", diff --git a/Demos/03-webpart/README.md b/Demos/03-webpart/README.md index 885c5b2..3bba72a 100644 --- a/Demos/03-webpart/README.md +++ b/Demos/03-webpart/README.md @@ -8,12 +8,12 @@ Short summary on functionality and used technologies. ## Used SharePoint Framework Version -![version](https://img.shields.io/badge/version-1.20.0-green.svg) +![version](https://img.shields.io/badge/version-1.23.0-green.svg) ## Applies to - [SharePoint Framework](https://aka.ms/spfx) -- [Microsoft 365 tenant](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/set-up-your-developer-tenant) +- [Microsoft 365 tenant](https://docs.microsoft.com/sharepoint/dev/spfx/set-up-your-developer-tenant) > Get your own free development tenant by subscribing to [Microsoft 365 developer program](http://aka.ms/o365devprogram) @@ -45,11 +45,14 @@ Short summary on functionality and used technologies. - Clone this repository - Ensure that you are at the solution folder - in the command-line run: - - **npm install** - - **gulp serve** + - `npm install -g @rushstack/heft` + - `npm install` + - `heft start` > Include any additional steps as needed. +Other build commands can be listed using `heft --help`. + ## Features Description of the extension that expands upon high-level summary above. @@ -66,8 +69,9 @@ This extension illustrates the following concepts: ## References -- [Getting started with SharePoint Framework](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/set-up-your-developer-tenant) -- [Building for Microsoft teams](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/build-for-teams-overview) -- [Use Microsoft Graph in your solution](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/get-started/using-microsoft-graph-apis) -- [Publish SharePoint Framework applications to the Marketplace](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/publish-to-marketplace-overview) +- [Getting started with SharePoint Framework](https://docs.microsoft.com/sharepoint/dev/spfx/set-up-your-developer-tenant) +- [Building for Microsoft teams](https://docs.microsoft.com/sharepoint/dev/spfx/build-for-teams-overview) +- [Use Microsoft Graph in your solution](https://docs.microsoft.com/sharepoint/dev/spfx/web-parts/get-started/using-microsoft-graph-apis) +- [Publish SharePoint Framework applications to the Marketplace](https://docs.microsoft.com/sharepoint/dev/spfx/publish-to-marketplace-overview) - [Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp) - Guidance, tooling, samples and open-source controls for your Microsoft 365 development +- [Heft Documentation](https://heft.rushstack.io/) \ No newline at end of file diff --git a/Demos/03-webpart/config/deploy-azure-storage.json b/Demos/03-webpart/config/deploy-azure-storage.json index 705d20a..e832924 100644 --- a/Demos/03-webpart/config/deploy-azure-storage.json +++ b/Demos/03-webpart/config/deploy-azure-storage.json @@ -4,4 +4,4 @@ "account": "", "container": "hello-world", "accessKey": "" -} \ No newline at end of file +} diff --git a/Demos/03-webpart/config/package-solution.json b/Demos/03-webpart/config/package-solution.json index 59d35b9..615f754 100644 --- a/Demos/03-webpart/config/package-solution.json +++ b/Demos/03-webpart/config/package-solution.json @@ -2,7 +2,7 @@ "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json", "solution": { "name": "hello-world-client-side-solution", - "id": "58d1a1d0-097b-4d7f-8d8d-b4de9f45c2bf", + "id": "bc092361-0ea2-42f1-b439-d362bcbd5301", "version": "1.0.0.0", "includeClientSideAssets": true, "skipFeatureDeployment": true, @@ -12,7 +12,7 @@ "websiteUrl": "", "privacyUrl": "", "termsOfUseUrl": "", - "mpnId": "Undefined-1.20.0" + "mpnId": "Undefined-1.23.0" }, "metadata": { "shortDescription": { @@ -29,7 +29,7 @@ { "title": "hello-world Feature", "description": "The feature that activates elements of the hello-world solution.", - "id": "b7da0188-127d-4b48-af45-e743ca28383f", + "id": "8a2d192f-9cb0-4644-9098-4cea320dafec", "version": "1.0.0.0" } ] diff --git a/Demos/03-webpart/config/rig.json b/Demos/03-webpart/config/rig.json new file mode 100644 index 0000000..99e3431 --- /dev/null +++ b/Demos/03-webpart/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "@microsoft/spfx-web-build-rig" +} diff --git a/Demos/03-webpart/config/sass.json b/Demos/03-webpart/config/sass.json index 5e78c98..1cfc17b 100644 --- a/Demos/03-webpart/config/sass.json +++ b/Demos/03-webpart/config/sass.json @@ -1,3 +1,5 @@ { - "$schema": "https://developer.microsoft.com/json-schemas/core-build/sass.schema.json" + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-sass-plugin.schema.json", + + "extends": "@microsoft/spfx-web-build-rig/profiles/default/config/sass.json" } \ No newline at end of file diff --git a/Demos/03-webpart/config/typescript.json b/Demos/03-webpart/config/typescript.json new file mode 100644 index 0000000..ce4cc73 --- /dev/null +++ b/Demos/03-webpart/config/typescript.json @@ -0,0 +1,9 @@ +{ + "extends": "@microsoft/spfx-web-build-rig/profiles/default/config/typescript.json", + + "staticAssetsToCopy": { + "fileExtensions": [".resx", ".jpg", ".png", ".woff", ".eot", ".ttf", ".svg", ".gif"], + + "includeGlobs": ["webparts/*/loc/*.js"] + } +} diff --git a/Demos/03-webpart/eslint.config.js b/Demos/03-webpart/eslint.config.js new file mode 100644 index 0000000..1501506 --- /dev/null +++ b/Demos/03-webpart/eslint.config.js @@ -0,0 +1,14 @@ +const spfxProfile = require('@microsoft/eslint-config-spfx/lib/flat-profiles/react'); + +module.exports = [ + ...spfxProfile, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname, + project: './tsconfig.json' + } + } + } +]; diff --git a/Demos/03-webpart/gulpfile.js b/Demos/03-webpart/gulpfile.js deleted file mode 100644 index be29187..0000000 --- a/Demos/03-webpart/gulpfile.js +++ /dev/null @@ -1,16 +0,0 @@ -'use strict'; - -const build = require('@microsoft/sp-build-web'); - -build.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`); - -var getTasks = build.rig.getTasks; -build.rig.getTasks = function () { - var result = getTasks.call(build.rig); - - result.set('serve', result.get('serve-deprecated')); - - return result; -}; - -build.initialize(require('gulp')); diff --git a/Demos/03-webpart/package.json b/Demos/03-webpart/package.json index 78117d2..fe53241 100644 --- a/Demos/03-webpart/package.json +++ b/Demos/03-webpart/package.json @@ -3,35 +3,46 @@ "version": "0.0.1", "private": true, "engines": { - "node": ">=18.17.1 <19.0.0" + "node": ">=22.14.0 < 23.0.0" }, - "main": "lib/index.js", "scripts": { - "build": "gulp bundle", - "clean": "gulp clean", - "test": "gulp test" + "build": "heft test --clean --production && heft package-solution --production", + "clean": "heft clean", + "eject-webpack": "heft eject-webpack", + "start": "heft start --clean" }, "dependencies": { "tslib": "2.3.1", - "@microsoft/sp-core-library": "1.20.0", - "@microsoft/sp-component-base": "1.20.0", - "@microsoft/sp-property-pane": "1.20.0", - "@microsoft/sp-webpart-base": "1.20.0", - "@microsoft/sp-lodash-subset": "1.20.0", - "@microsoft/sp-office-ui-fabric-core": "1.20.0" + "react": "17.0.1", + "react-dom": "17.0.1", + "@fluentui/react": "^8.106.4", + "@microsoft/sp-core-library": "1.23.0", + "@microsoft/sp-component-base": "1.23.0", + "@microsoft/sp-property-pane": "1.23.0", + "@microsoft/sp-webpart-base": "1.23.0", + "@microsoft/sp-lodash-subset": "1.23.0", + "@microsoft/sp-office-ui-fabric-core": "1.23.0" }, "devDependencies": { - "@microsoft/rush-stack-compiler-4.7": "0.1.0", - "@rushstack/eslint-config": "4.0.1", - "@microsoft/eslint-plugin-spfx": "1.20.2", - "@microsoft/eslint-config-spfx": "1.20.2", - "@microsoft/sp-build-web": "1.20.2", + "@microsoft/eslint-plugin-spfx": "1.23.0", + "@microsoft/eslint-config-spfx": "1.23.0", + "@microsoft/spfx-web-build-rig": "1.23.0", + "@microsoft/spfx-heft-plugins": "1.23.0", + "@rushstack/heft": "1.2.17", + "@types/jest": "30.0.0", "@types/webpack-env": "~1.15.2", - "ajv": "^6.12.5", - "eslint": "8.57.0", - "gulp": "4.0.2", - "typescript": "4.7.4", - "@microsoft/sp-module-interfaces": "1.20.2", - "@fluentui/react": "^8.106.4" + "css-loader": "~7.1.2", + "eslint": "9.37.0", + "typescript": "~5.8.0", + "@types/react": "17.0.45", + "@types/react-dom": "17.0.17", + "eslint-plugin-react-hooks": "5.2.0", + "@microsoft/sp-module-interfaces": "1.23.0" + }, + "overrides": { + "@rushstack/heft": "1.2.17" + }, + "resolutions": { + "@types/react": "17.0.45" } } diff --git a/Demos/03-webpart/src/index.ts b/Demos/03-webpart/src/index.ts deleted file mode 100644 index fb81db1..0000000 --- a/Demos/03-webpart/src/index.ts +++ /dev/null @@ -1 +0,0 @@ -// A file is required to be in the root of the /src directory by the TypeScript compiler diff --git a/Demos/03-webpart/src/webparts/helloWorld/HelloWorldWebPart.manifest.json b/Demos/03-webpart/src/webparts/helloWorld/HelloWorldWebPart.manifest.json index 982f04e..c7ab4c9 100644 --- a/Demos/03-webpart/src/webparts/helloWorld/HelloWorldWebPart.manifest.json +++ b/Demos/03-webpart/src/webparts/helloWorld/HelloWorldWebPart.manifest.json @@ -1,6 +1,6 @@ { "$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json", - "id": "4f305338-fac1-4515-b720-5d606f2b5d45", + "id": "c2383027-3a06-4fcd-9917-44654da9f78c", "alias": "HelloWorldWebPart", "componentType": "WebPart", diff --git a/Demos/03-webpart/src/webparts/helloWorld/HelloWorldWebPart.ts b/Demos/03-webpart/src/webparts/helloWorld/HelloWorldWebPart.ts index c7a03db..e0c367c 100644 --- a/Demos/03-webpart/src/webparts/helloWorld/HelloWorldWebPart.ts +++ b/Demos/03-webpart/src/webparts/helloWorld/HelloWorldWebPart.ts @@ -1,14 +1,16 @@ +import * as React from 'react'; +import * as ReactDom from 'react-dom'; import { Version } from '@microsoft/sp-core-library'; import { type IPropertyPaneConfiguration, PropertyPaneTextField } from '@microsoft/sp-property-pane'; import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base'; -import type { IReadonlyTheme } from '@microsoft/sp-component-base'; -import { escape } from '@microsoft/sp-lodash-subset'; +import { IReadonlyTheme } from '@microsoft/sp-component-base'; -import styles from './HelloWorldWebPart.module.scss'; import * as strings from 'HelloWorldWebPartStrings'; +import HelloWorld from './components/HelloWorld'; +import { IHelloWorldProps } from './components/IHelloWorldProps'; export interface IHelloWorldWebPartProps { description: string; @@ -20,31 +22,18 @@ export default class HelloWorldWebPart extends BaseClientSideWebPart -
- -

Well done, ${escape(this.context.pageContext.user.displayName)}!

-
${this._environmentMessage}
-
Web part property value: ${escape(this.properties.description)}
-
-
-

Welcome to SharePoint Framework!

-

- The SharePoint Framework (SPFx) is a extensibility model for Microsoft Viva, Microsoft Teams and SharePoint. It's the easiest way to extend Microsoft 365 with automatic Single Sign On, automatic hosting and industry standard tooling. -

-

Learn more about SPFx development:

- -
- `; + const element: React.ReactElement = React.createElement( + HelloWorld, + { + description: this.properties.description, + isDarkTheme: this._isDarkTheme, + environmentMessage: this._environmentMessage, + hasTeamsContext: !!this.context.sdks.microsoftTeams, + userDisplayName: this.context.pageContext.user.displayName + } + ); + + ReactDom.render(element, this.domElement); } protected onInit(): Promise { @@ -100,6 +89,10 @@ export default class HelloWorldWebPart extends BaseClientSideWebPart { + public render(): React.ReactElement { + const { + description, + isDarkTheme, + environmentMessage, + hasTeamsContext, + userDisplayName + } = this.props; + + return ( +
+
+ +

Well done, {escape(userDisplayName)}!

+
{environmentMessage}
+
Web part property value: {escape(description)}
+
+
+

Welcome to SharePoint Framework!

+

+ The SharePoint Framework (SPFx) is a extensibility model for Microsoft Viva, Microsoft Teams and SharePoint. It's the easiest way to extend Microsoft 365 with automatic Single Sign On, automatic hosting and industry standard tooling. +

+

Learn more about SPFx development:

+ +
+
+ ); + } +} diff --git a/Demos/03-webpart/src/webparts/helloWorld/components/IHelloWorldProps.ts b/Demos/03-webpart/src/webparts/helloWorld/components/IHelloWorldProps.ts new file mode 100644 index 0000000..f7fdb82 --- /dev/null +++ b/Demos/03-webpart/src/webparts/helloWorld/components/IHelloWorldProps.ts @@ -0,0 +1,7 @@ +export interface IHelloWorldProps { + description: string; + isDarkTheme: boolean; + environmentMessage: string; + hasTeamsContext: boolean; + userDisplayName: string; +} diff --git a/Demos/03-webpart/teams/4f305338-fac1-4515-b720-5d606f2b5d45_color.png b/Demos/03-webpart/teams/c2383027-3a06-4fcd-9917-44654da9f78c_color.png similarity index 100% rename from Demos/03-webpart/teams/4f305338-fac1-4515-b720-5d606f2b5d45_color.png rename to Demos/03-webpart/teams/c2383027-3a06-4fcd-9917-44654da9f78c_color.png diff --git a/Demos/03-webpart/teams/4f305338-fac1-4515-b720-5d606f2b5d45_outline.png b/Demos/03-webpart/teams/c2383027-3a06-4fcd-9917-44654da9f78c_outline.png similarity index 100% rename from Demos/03-webpart/teams/4f305338-fac1-4515-b720-5d606f2b5d45_outline.png rename to Demos/03-webpart/teams/c2383027-3a06-4fcd-9917-44654da9f78c_outline.png diff --git a/Demos/03-webpart/tsconfig.json b/Demos/03-webpart/tsconfig.json index c4cd392..ee582d5 100644 --- a/Demos/03-webpart/tsconfig.json +++ b/Demos/03-webpart/tsconfig.json @@ -1,35 +1,3 @@ { - "extends": "./node_modules/@microsoft/rush-stack-compiler-4.7/includes/tsconfig-web.json", - "compilerOptions": { - "target": "es5", - "forceConsistentCasingInFileNames": true, - "module": "esnext", - "moduleResolution": "node", - "jsx": "react", - "declaration": true, - "sourceMap": true, - "experimentalDecorators": true, - "skipLibCheck": true, - "outDir": "lib", - "inlineSources": false, - "noImplicitAny": true, - - "typeRoots": [ - "./node_modules/@types", - "./node_modules/@microsoft" - ], - "types": [ - "webpack-env" - ], - "lib": [ - "es5", - "dom", - "es2015.collection", - "es2015.promise" - ] - }, - "include": [ - "src/**/*.ts", - "src/**/*.tsx" - ] + "extends": "./node_modules/@microsoft/spfx-web-build-rig/profiles/default/tsconfig-base.json" } diff --git a/Demos/README.md b/Demos/README.md deleted file mode 100644 index acbab0c..0000000 --- a/Demos/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Microsoft SharePoint Framework Training Module - Getting Started with the SharePoint Framework - -This folder contains demos associated with the slide decks in this module. - -## Demos - -* [Create & Configure your SharePoint Online Developer Tenant](./01-appcatalog) -* [Setup your local SPFx Developer Environment](./02-setup-env) -* [Interact with SPFx Client-Side Web Parts in Modern Sites](./03-webpart) - -## Running demonstrations - -Each demonstration is included as source code for convenience. diff --git a/README.md b/README.md index 222bba5..48e18c4 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,8 @@ This module has been recorded and is available in the SharePoint Development You | Version | Date | Comments | | ------- | ------------------ | -------------------------------------------------- | -| 1.21 | December 13, 2024 | FY2025Q2 content refresh; update to SPFx v1.20.0 | +| 1.22 | May 24, 2026 | FY2026Q4 content refresh; update to SPFx v1.23.0 | +| 1.21 | December 13, 2024 | FY2025Q2 content refresh | | 1.20 | June 12, 2024 | FY2024Q4 content refresh; update to SPFx v1.19.0 | | 1.19 | May 5, 2023 | FY2023Q4 content refresh; update to SPFx v1.17.1 | | 1.18 | February 28, 2023 | FY2023Q3 content refresh; update to SPFx v1.16.1 |