angular-server-side-configuration
Version:
Configure an angular application on the server
170 lines (168 loc) • 7.47 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.ngAdd = ngAdd;
const core_1 = require("@angular-devkit/core");
const schematics_1 = require("@angular-devkit/schematics");
const change_1 = require("@schematics/angular/utility/change");
const workspace_1 = require("@schematics/angular/utility/workspace");
function ngAdd(options) {
return (0, schematics_1.chain)([
addNgsscTargetToWorkspace(options),
addDescriptionToMainFile(options),
addNgsscToPackageScripts(options),
addPlaceholderToIndexHtml(options),
]);
}
function addNgsscTargetToWorkspace(options) {
return (_host, context) => (0, workspace_1.updateWorkspace)((workspace) => {
const project = workspace.projects.get(options.project);
if (!project) {
return;
}
const ngsscOptions = {
additionalEnvironmentVariables: options.additionalEnvironmentVariables
? options.additionalEnvironmentVariables.split(',').map((e) => e.trim())
: [],
};
if (options.experimentalBuilders) {
const buildTarget = project.targets.get('build');
buildTarget.builder = 'angular-server-side-configuration:browser';
buildTarget.options = { ...buildTarget.options, ...ngsscOptions };
const serveTarget = project.targets.get('serve');
serveTarget.builder = 'angular-server-side-configuration:dev-server';
const target = project.targets.get('ngsscbuild');
if (target) {
project.targets.delete('ngsscbuild');
}
return;
}
const target = project.targets.get('ngsscbuild');
if (target) {
context.logger.info(`Skipping adding ngsscbuild target to angular.json, as it already exists in project ${options.project}.`);
return;
}
project.targets.add({
name: 'ngsscbuild',
builder: 'angular-server-side-configuration:ngsscbuild',
options: {
...ngsscOptions,
buildTarget: `${options.project}:build`,
},
configurations: {
production: {
buildTarget: `${options.project}:build:production`,
},
},
});
});
}
function addDescriptionToMainFile(options) {
const noAppropriateInsertFileWarning = 'Unable to resolve appropriate file to insert import. Please follow documentation.';
return async (host, context) => {
const { project } = await resolveWorkspace(options, host);
const buildTarget = project.targets.get('build');
const mainFile = (0, core_1.normalize)(buildTarget?.options?.['main'] ??
buildTarget?.options?.['browser'] ??
'');
if (!mainFile) {
context.logger.warn(noAppropriateInsertFileWarning);
return;
}
const insertFile = [
(0, core_1.join)((0, core_1.dirname)(mainFile), 'environments/environment.prod.ts'),
(0, core_1.join)((0, core_1.dirname)(mainFile), 'environments/environment.ts'),
(0, core_1.join)((0, core_1.dirname)(mainFile), 'app/app.config.ts'),
(0, core_1.join)((0, core_1.dirname)(mainFile), 'app/app.module.ts'),
(0, core_1.join)((0, core_1.dirname)(mainFile), 'app/app.component.ts'),
mainFile,
].find((f) => host.exists(f));
if (!insertFile) {
context.logger.warn(noAppropriateInsertFileWarning);
return;
}
const file = host.get(insertFile);
if (!file) {
context.logger.warn(noAppropriateInsertFileWarning);
return;
}
else if (file.content.includes('angular-server-side-configuration')) {
context.logger.info(`Skipping adding import to ${file.path}, since import was already detected.`);
return;
}
const insertContent = `import 'angular-server-side-configuration/process';
/**
* How to use angular-server-side-configuration:
*
* Use process.env['NAME_OF_YOUR_ENVIRONMENT_VARIABLE']
*
* const stringValue = process.env['STRING_VALUE'];
* const stringValueWithDefault = process.env['STRING_VALUE'] || 'defaultValue';
* const numberValue = Number(process.env['NUMBER_VALUE']);
* const numberValueWithDefault = Number(process.env['NUMBER_VALUE'] || 10);
* const booleanValue = process.env['BOOLEAN_VALUE'] === 'true';
* const booleanValueInverted = process.env['BOOLEAN_VALUE_INVERTED'] !== 'false';
* const complexValue = JSON.parse(process.env['COMPLEX_JSON_VALUE]);
*
* Please note that process.env[variable] cannot be resolved. Please directly use strings.
*/
`;
const insertion = new change_1.InsertChange(file.path, 0, insertContent);
const recorder = host.beginUpdate(file.path);
recorder.insertLeft(insertion.pos, insertion.toAdd);
host.commitUpdate(recorder);
};
}
function addNgsscToPackageScripts(options) {
return (host, context) => {
if (options.experimentalBuilders) {
return;
}
const pkgPath = '/package.json';
const buffer = host.read(pkgPath);
if (buffer === null) {
throw new schematics_1.SchematicsException('Could not find package.json');
}
const pkg = { scripts: {}, ...JSON.parse(buffer.toString()) };
if ('build:ngssc' in pkg.scripts) {
context.logger.info(`Skipping adding script to package.json, as it already exists.`);
return;
}
pkg.scripts['build:ngssc'] = `ng run ${options.project}:ngsscbuild:production`;
host.overwrite(pkgPath, JSON.stringify(pkg, null, 2));
};
}
function addPlaceholderToIndexHtml(options) {
return async (host, context) => {
const { project } = await resolveWorkspace(options, host);
const build = project.targets.get('build');
if (!build) {
throw new schematics_1.SchematicsException(`Expected a build target in project ${options.project}!`);
}
const indexPath = build.options?.['index'] || 'src/index.html';
const indexHtml = host.get(indexPath);
if (!indexHtml) {
throw new schematics_1.SchematicsException(`Expected index html ${indexPath} to exist!`);
}
const indexHtmlContent = indexHtml.content.toString();
if (/<!--\s*CONFIG\s*-->/.test(indexHtmlContent)) {
context.logger.info(`Skipping adding placeholder to ${indexHtml.path}, as it already contains it.`);
return;
}
const insertIndex = indexHtmlContent.includes('</title>')
? indexHtmlContent.indexOf('</title>') + 9
: indexHtmlContent.indexOf('</head>');
const insertion = new change_1.InsertChange(indexHtml.path, insertIndex, ' <!--CONFIG-->\n');
const recorder = host.beginUpdate(indexHtml.path);
recorder.insertLeft(insertion.pos, insertion.toAdd);
host.commitUpdate(recorder);
};
}
async function resolveWorkspace(options, host) {
const workspace = await (0, workspace_1.getWorkspace)(host);
const project = workspace.projects.get(options.project);
if (!project) {
throw new schematics_1.SchematicsException(`Project ${options.project} not found!`);
}
return { workspace, project };
}
//# sourceMappingURL=index.js.map
;