sp-dev-fx-webparts/samples/react-rhythm-of-business-ca.../build/gulpfile.ts

479 lines
18 KiB
TypeScript

import * as path from 'path';
import * as gulp from 'gulp';
import * as build from '@microsoft/sp-build-web';
import { IBuildConfig } from '@microsoft/gulp-core-build';
import { IPackageSolutionConfig } from "@microsoft/spfx-heft-plugins/lib/plugins/packageSolutionPlugin/SolutionPackager";
import IFeature from "@microsoft/spfx-heft-plugins/lib/plugins/packageSolutionPlugin/packageSolution/models/packageDefinition/IFeature";
import { obj as through2obj } from 'through2';
const AliasPlugin = require('enhanced-resolve/lib/AliasPlugin');
const JSON5 = require('json5');
const zip = require('gulp-zip');
const StatefulProcessCommandProxy = require('stateful-process-command-proxy');
const environmentArgName = "env";
const defaultEnvironment = "local";
interface IEnvironment {
deploySiteUrl: string;
deployScope: "Tenant" | "Site";
skipFeatureDeployment: boolean;
environmentSymbol: string;
package: {
name: string;
id: string;
filename: string;
features: {
matchLocalId: string,
title: string,
id: string,
elementManifests: string[]
}[];
};
webparts: {
manifest: string;
id: string;
alias: string;
title: string;
}[];
extensions: {
manifest: string;
id: string;
alias: string;
}[];
libraries: {
manifest: string;
id: string;
alias: string;
}[];
}
interface IEnvironmentConfiguration {
dependencies: {
spfxLibraries: string[];
nodePackages: string[];
};
environments: {
[name: string]: IEnvironment;
};
}
const environmentConfigurations = require('./environments.json') as IEnvironmentConfiguration;
const { spfxLibraries, nodePackages } = environmentConfigurations.dependencies;
const getEnvironmentConfig = (buildOptions: IBuildConfig): IEnvironment => {
return (environmentConfigurations.environments[buildOptions.args[environmentArgName] as string || defaultEnvironment]);
};
const createPowershellProxy = () => new StatefulProcessCommandProxy({
name: 'PowerShell proxy',
min: 1,
max: 1,
processCommand: 'powershell.exe',
processArgs: ['-Command', '-'],
processInvalidateOnRegex:
{
'any': [{ regex: '.*error.*', flags: 'ig' }],
'stdout': [{ regex: '.*error.*', flags: 'ig' }],
'stderr': [{ regex: '.*error.*', flags: 'ig' }]
},
logFunction: () => { }
});
const logResult = (result: any) => {
if (result.stdout) build.log(result.stdout);
if (result.stderr) build.error(result.stderr);
};
const modifyFile = (fn: (contents: string, path: string, file: any) => string) => {
return through2obj((file, enc, cb) => {
const contents = fn(String(file.contents), file.path, file) || file.contents;
if (file.isBuffer() === true) {
file.contents = Buffer.from(contents);
}
cb(null, file);
});
};
build.configureWebpack.mergeConfig({
additionalConfiguration: (generatedConfiguration) => {
const solutionFolders = ['apps', 'assets', 'common', 'components', 'domain', 'model', 'schema', 'services'];
const createPaths = (importPath: string) => {
const paths = [path.resolve(__dirname, 'lib', importPath)];
if (nodePackages) {
for (const dependency of nodePackages) {
paths.push(path.resolve(__dirname, dependency, 'lib', importPath));
}
}
return paths;
};
const resolveAliasPlugin = new AliasPlugin('described-resolve',
solutionFolders.map(folder => {
return {
name: folder,
alias: createPaths(folder)
};
}), 'resolve');
generatedConfiguration.resolve ||= {};
generatedConfiguration.resolve.plugins ||= [];
generatedConfiguration.resolve.plugins.unshift(resolveAliasPlugin);
return generatedConfiguration;
}
});
if (nodePackages) {
for (const dependency of nodePackages) {
build.serveWatchFilter.push(`${dependency}/src/**/*.{ts,tsx,scss,resx,js,json,html}`);
build.serveWatchFilter.push(`!${dependency}/src/**/*.{scss.ts,resx.ts}`);
}
}
if (spfxLibraries) {
for (const dependency of spfxLibraries) {
build.serveWatchFilter.push(`${dependency}/dist/*.{json}`);
}
}
const buildDependency_NodePackages_Subtask = build.subTask('build-dependency-nodepackages-subtask', async (_gulp, buildOptions) => {
if (nodePackages) {
for (const nodePackage of nodePackages) {
const powershellProxy = createPowershellProxy();
const gulpCommand = `cmd.exe /c "cd ${nodePackage} && gulp build ${buildOptions.production ? '--production' : ''}"`;
build.log("Executing ", gulpCommand);
await powershellProxy.executeCommand(gulpCommand).then(logResult);
await powershellProxy.shutdown();
}
}
return {};
});
build.task('build-dependency-nodepackages', buildDependency_NodePackages_Subtask);
const modifyPackageSolutionJsonSubtask = build.subTask('modify-package-solution-json-subtask', (_gulp, buildOptions, done) => {
const config = getEnvironmentConfig(buildOptions);
if (config) {
return gulp.src('config/package-solution.json', { base: '.' })
.pipe(gulp.dest(buildOptions.tempFolder + '/perEnvConfig'))
.pipe(modifyFile((content: string) => {
build.log("Modifying package-solution.json");
const json = JSON5.parse(content) as IPackageSolutionConfig;
json.solution!.id = config.package.id;
json.solution!.name = config.package.name;
json.solution!.features = json.solution!.features && json.solution!.features.map(originalFeature => {
const configFeature = (config.package.features || []).filter(f => f.matchLocalId == originalFeature.id)[0];
if (configFeature) {
const modifiedFeature: IFeature = Object.assign({}, originalFeature);
modifiedFeature.id = configFeature.id;
modifiedFeature.title = configFeature.title;
modifiedFeature.assets!.elementManifests = configFeature.elementManifests;
return modifiedFeature;
} else {
return originalFeature;
}
});
json.paths!.zippedPackage = `solution/${config.package.filename}`;
return JSON.stringify(json, undefined, 4);
}))
.pipe(gulp.dest('.'));
}
else {
done!();
}
});
const modifyWebPartManifestsSubtask = build.subTask('modify-webpart-manifests-subtask', (_gulp, buildOptions, done) => {
const config = getEnvironmentConfig(buildOptions);
if (config) {
return gulp.src('src/webparts/*/*WebPart.manifest.json', { base: '.' })
.pipe(gulp.dest(buildOptions.tempFolder + '/perEnvConfig'))
.pipe(modifyFile((content: string, filePath: string) => {
const filename = filePath.split('\\').pop()?.split('/').pop()!;
const webpartConfig = config.webparts.filter(wp => wp.manifest == filename)[0];
build.log("Examining ", filename);
if (webpartConfig) {
build.log("Modifying ", filename);
const json = JSON5.parse(content);
json.id = webpartConfig.id;
json.alias = webpartConfig.alias;
json.preconfiguredEntries[0].title.default = webpartConfig.title;
return JSON.stringify(json, undefined, 4);
} else {
build.log("No modifications specified ", filename);
return content;
}
}))
.pipe(gulp.dest('.'));
} else {
done!();
}
});
const modifyExtensionManifestsSubtask = build.subTask('modify-extension-manifests-subtask', (_gulp, buildOptions, done) => {
const config = getEnvironmentConfig(buildOptions);
if (config && config.extensions) {
return gulp.src('src/extensions/*/*ApplicationCustomizer.manifest.json', { base: '.' })
.pipe(gulp.dest(buildOptions.tempFolder + '/perEnvConfig'))
.pipe(modifyFile((content: string, filePath: string) => {
const filename = filePath.split('\\').pop()?.split('/').pop()!;
const extensionConfig = config.extensions.filter(ext => ext.manifest == filename)[0];
build.log("Examining ", filename);
if (extensionConfig) {
build.log("Modifying ", filename);
const json = JSON5.parse(content);
json.id = extensionConfig.id;
json.alias = extensionConfig.alias;
return JSON.stringify(json, undefined, 4);
} else {
build.log("No modifications specified ", filename);
return content;
}
}))
.pipe(gulp.dest('.'));
} else {
done!();
}
});
const modifyLibraryManifestsSubtask = build.subTask('modify-library-manifests-subtask', (_gulp, buildOptions, done) => {
const config = getEnvironmentConfig(buildOptions);
if (config) {
return gulp.src('src/**/*Library.manifest.json', { base: '.' })
.pipe(gulp.dest(buildOptions.tempFolder + '/perEnvConfig'))
.pipe(modifyFile((content: string, filePath: string) => {
const filename = filePath.split('\\').pop()?.split('/').pop()!;
const libraryConfig = config.libraries.filter(wp => wp.manifest == filename)[0];
build.log("Examining ", filename);
if (libraryConfig) {
build.log("Modifying ", filename);
const json = JSON5.parse(content);
json.id = libraryConfig.id;
json.alias = libraryConfig.alias;
return JSON.stringify(json, undefined, 4);
} else {
build.log("No modifications specified ", filename);
return content;
}
}))
.pipe(gulp.dest('.'));
} else {
done!();
}
});
const modifySchemaDefaultsSubtask = build.subTask('modify-schema-defaults-subtask', (_gulp, buildOptions, done) => {
const config = getEnvironmentConfig(buildOptions);
if (config) {
return gulp.src('src/**{,/*/**}/Defaults.ts', { base: '.' })
.pipe(gulp.dest(buildOptions.tempFolder + '/perEnvConfig'))
.pipe(modifyFile((content: string, filePath: string) => {
build.log("Modifying ", filePath.split('\\src\\').pop()!);
const lines = content.split('\n');
return lines.map(line => {
if (line.startsWith("const Environment ="))
return `const Environment = ${config.environmentSymbol};`;
else
return line;
}).join('\n');
}))
.pipe(gulp.dest('.'));
} else {
done!();
}
});
const modifySchemaDefaults_NodePackages_Subtask = build.subTask('modify-schema-defaults-nodepackages-subtask', (_gulp, buildOptions, done) => {
const config = getEnvironmentConfig(buildOptions);
if (config && nodePackages) {
return Promise.all(nodePackages.map(nodePackage => {
return new Promise<void>((resolve, reject) => {
gulp.src(`${nodePackage}/src/**{,/*/**}/Defaults.ts`, { base: `./${nodePackage}` })
.pipe(gulp.dest(`${nodePackage}/temp/perEnvConfig`))
.on('error', reject)
.pipe(modifyFile((content: string, filePath: string) => {
build.log("Modifying ", nodePackage, ' ', filePath.split('\\src\\').pop()!);
const lines = content.split('\n');
return lines.map(line => {
if (line.startsWith("const Environment ="))
return `const Environment = ${config.environmentSymbol};`;
else
return line;
}).join('\n');
}))
.pipe(gulp.dest(`./${nodePackage}`))
.on('end', resolve);
});
}));
} else {
done!();
}
});
const modifyConfig_SPFxLibraries_Subtask = build.subTask('modify-config-spfxlibs-subtask', async (_gulp, buildOptions) => {
if (spfxLibraries) {
for (const spfxLibrary of spfxLibraries) {
const powershellProxy = createPowershellProxy();
const gulpCommand = `cmd.exe /c "cd ${spfxLibrary} && gulp modify-env-config --env ${buildOptions.args[environmentArgName]}"`;
build.log("Executing ", gulpCommand);
await powershellProxy.executeCommand(gulpCommand).then(logResult);
await powershellProxy.shutdown();
}
}
return {};
});
const restoreConfig_Subtask = build.subTask('restore-config-subtask', (_gulp, buildOptions) => {
return gulp
.src(buildOptions.tempFolder + '/perEnvConfig/**/*')
.pipe(gulp.dest('.'));
});
const restoreDependencyConfig_NodePackages_Subtask = build.subTask('restore-dependency-config-nodepackages-subtask', (_gulp, _buildOptions, done) => {
if (nodePackages) {
return Promise.all(nodePackages.map(nodePackage => {
return new Promise<void>((resolve, reject) => {
return gulp
.src(`${nodePackage}/temp/perEnvConfig/**/*`)
.on('error', reject)
.pipe(gulp.dest(`./${nodePackage}`))
.on('end', resolve);
});
}));
} else {
done!();
}
});
const restoreDependencyConfig_SPFxLibraries_Subtask = build.subTask('restore-dependency-config-spfxlibs-subtask', async (_gulp, _buildOptions) => {
if (spfxLibraries) {
for (const spfxLibrary of spfxLibraries) {
const powershellProxy = createPowershellProxy();
const gulpCommand = `cmd.exe /c "cd ${spfxLibrary} && gulp restore-original-config"`;
build.log("Executing ", gulpCommand);
await powershellProxy.executeCommand(gulpCommand).then(logResult);
await powershellProxy.shutdown();
}
}
return {};
});
const zipSourceCodeSubtask = build.subTask('zip-sourcecode-subtask', (_gulp, buildOptions, done) => {
const config = getEnvironmentConfig(buildOptions);
if (config) {
return gulp.src(['*.*', 'build/**/*.*', 'config/**/*.*', 'mock_modules/**/*.*', 'release/assets/**/*.*', 'src/**{,/*/**}/*.*'], { base: '.' })
.pipe(zip(`${config.package.filename.replace('.sppkg', '')}-src.zip`))
.pipe(gulp.dest('sharepoint/solution'));
} else {
done!();
}
});
build.task('zip-sourcecode', zipSourceCodeSubtask);
const publishSolutionSubtask = build.subTask('publish-solution-subtask', async (_gulp, buildOptions) => {
const config = getEnvironmentConfig(buildOptions);
if (config && config.deploySiteUrl) {
const powershellProxy = createPowershellProxy();
const scope = config.deployScope || "Site";
const connectCommand = `Connect-PnPOnline -Interactive -Url ${config.deploySiteUrl}`;
const addPackageCommand = `Add-PnPApp -Path .\\sharepoint\\solution\\${config.package.filename} -Scope ${scope} -Publish -Overwrite ${config.skipFeatureDeployment ? '-SkipFeatureDeployment' : ''}`;
build.log("Executing ", connectCommand);
await powershellProxy.executeCommand(connectCommand).then(logResult);
build.log("Executing ", addPackageCommand);
await powershellProxy.executeCommand(addPackageCommand).then(logResult);
await powershellProxy.shutdown();
}
return {};
});
build.task('publish', publishSolutionSubtask);
const modifyEnvConfigTask = build.task('modify-env-config',
build.parallel(
modifyConfig_SPFxLibraries_Subtask,
modifyPackageSolutionJsonSubtask,
modifySchemaDefaults_NodePackages_Subtask,
modifySchemaDefaultsSubtask,
modifyWebPartManifestsSubtask,
modifyExtensionManifestsSubtask,
modifyLibraryManifestsSubtask
)
);
const restoreOriginalConfigTask = build.task('restore-original-config',
build.parallel(
restoreDependencyConfig_SPFxLibraries_Subtask,
restoreDependencyConfig_NodePackages_Subtask,
restoreConfig_Subtask
)
);
build.rig.addPreBuildTask(buildDependency_NodePackages_Subtask);
const buildTask = build.serial(
build.preCopy,
buildDependency_NodePackages_Subtask,
build.parallel(build.sass, build.copyStaticAssets),
build.parallel(build.lintCmd, build.tscCmd),
build.postCopy
);
const bundleTask = build.serial(
buildTask,
build.configureWebpack,
build.webpack
);
const packageTask = build.task('package',
build.serial(
build.clean,
modifyEnvConfigTask,
bundleTask,
zipSourceCodeSubtask,
build.packageSolution,
restoreOriginalConfigTask
)
);
build.task('deploy',
build.serial(
packageTask,
publishSolutionSubtask
)
);
build.task('serve',
build.serial(
build.serve,
build.watch(build.serveWatchFilter,
build.serial(
bundleTask,
build.reload
)
)
)
);
build.addSuppression(/^Warning - \[sass\].*$/);
build.initialize(gulp);