Kusi's SPFx Knowledgebase¶
Project structure¶
Package configuration¶
Package Solution¶
Path: <Projectpath>/config/package-solution.json
The name and the name of the file can be adjusted in the package-solution.json file. The version can also be defined.
Package¶
Path: <Projectpath>/package.json
The package.json file also has the version, it should be the same as the version above.
Additional modules that can be used in the package can be entered in the dependencies section. The same can be achieved with:
In the devDependencies section, additional modules can be entered that are only used for development and should not be compiled into the package. The same can be achieved with:
If the packages were added manually in the package.json file, the packages can be downloaded with the following command:
Gulpfile¶
Path: <Projectpath>/gulpfile.js
So that the package can be created directly using gulp dist, gulp-sequence must first be installed:
'use strict';
if (process.argv.indexOf('dist') !== -1){
process.argv.push('--ship');
}
const gulp = require('gulp');
const build = require('@microsoft/sp-build-web');
const gulpSequence = require('gulp-sequence');
build.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`);
gulp.task('dist', gulpSequence('clean', 'bundle', 'package-solution'));
build.initialize(gulp);
Under SP2019 there was the problem that the package got bigger with each build. It is therefore advisable to delete the old temp files there:
'use strict';
if (process.argv.indexOf('dist') !== -1){
process.argv.push('--ship');
}
const gulp = require('gulp');
const build = require('@microsoft/sp-build-web');
const gulpSequence = require('gulp-sequence');
const del = require('del');
gulp.task('cleanup', function(){
return del(['dist/**','lib/**','release/**','sharepoint/**','temp/**'], {force:true});
});
build.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`);
gulp.task('dist', gulpSequence('clean', 'cleanup', 'bundle', 'package-solution'));
build.initialize(gulp);
The release package can then be created using the following command:
WebPart¶
Manifest¶
Path: <Projectpath>/webparts/<WebPartName>/<WebPartName>WebPart.manifest.json
The groupid value can be a new GUID and given a name in the group value. This name is then used as a category in the classic design.
With the value officeFabricIconFontName the icon can be defined in modern design.
Styling¶
Path: <Projectpath>/webparts/<WebPartName>/components/<WebPartName>.module.scss
The styles can be defined in this file, they can be nested and then converted into a correct CSS when compiling. The name can then be accessed using styles.<Name>. Global CSS classes can be defined using global keyword.
Example:
Interfaces¶
Path: <Projectpath>/webparts/<WebPartName>/components/I<WebPartName>.ts
This file contains the interfaces for this WebPart.
Example:
export interface I<WebPartName>State {
error?: undefined;
isLoaded?: boolean;
items?: IItem[];
selectedItem?: IItem;
}
export interface IItem {
ID: number;
Title: string;
}
Properties¶
Path: <Projectpath>/webparts/<WebPartName>/components/I<WebPartName>Props.ts
Props contains global variables and properties from the settings panel Example:
import { SPHttpClient } from '@microsoft/sp-http';
export interface I<WebPartName>Props {
siteurl: string;
spHttpClient: SPHttpClient;
}
Init file¶
Path: <Projectpath>/webparts/<WebPartName>/<WebPartName>WebPart.ts
The global values of props are defined here Example:
public render(): void {
const element: React.ReactElement<I<WebPartName>Props > = React.createElement(
<WebPartName>,
{
siteurl: this.context.pageContext.web.absoluteUrl,
spHttpClient: this.context.spHttpClient
}
);
ReactDom.render(element, this.domElement);
}
Code¶
Path: <Projectpath>/webparts/<WebPartName>/components/I<WebPartName>.tsx
Example:
import * as React from 'react';
import styles from './<WebPartName>.module.scss';
import { I<WebPartName>Props } from './I<WebPartName>Props';
import { SPHttpClient } from '@microsoft/sp-http';
import { Spinner, SpinnerSize } from 'office-ui-fabric-react';
import { I<WebPartName>State, IItem } from './I<WebPartName>';
export default class <WebPartName> extends React.Component<I<WebPartName>Props, I<WebPartName>State> {
public constructor(props: I<WebPartName>Props) {
super(props);
this.state = {
error: undefined,
isLoaded: false,
items: [],
selectedItem: undefined
};
}
public componentDidMount(): void {
let items: IItem[] = [];
this.props.spHttpClient.get(`${this.props.siteurl}/_api/web/lists/getbytitle('<ListName>')/Items` +
`?$select=Id,Title`,
SPHttpClient.configurations.v1)
.then(resType => resType.json())
.then(resType => {
if (resType.value) {
items = resType.value;
}
this.setState({
items: items,
isLoaded: true
});
});
}
public render(): React.ReactElement<IKnowledgeBaseProps> {
const { items, selectedItem, error, isLoaded } = this.state;
let retValue: JSX.Element = <div>{strings.NoData}</div>;
if (error) {
retValue = <div className={styles.error}>{strings.Error}: {error}</div>;
} else if (!isLoaded) {
if (SpinnerSize && SpinnerSize.large) {
retValue = <div className={styles.loadingWrapper}>
<Spinner size={SpinnerSize.large} label={strings.OnLoading} />
</div>;
} else {
retValue = <div>{strings.OnLoading}</div>;
}
} else if (selectedItem) {
retValue = <div className={styles.container}>
<div className={styles.grouptext}>{selectedItem.Title}</div>
</div>;
} else {
retValue = <div className={styles.container}>{items.map(g =>
<div><div className={styles.grouptext}>{g.Title}</div></div>
)}
</div>;
}
return (
<div className={styles.KnowledgeBase}>{retValue}</div>
);
}
}