Skip to content

Commit

Permalink
fix(@schematics/angular): remove bootstrapping wrapping in universal …
Browse files Browse the repository at this point in the history
…schematic

The bootstrapping wrapping is no longer necessary as of 15.1.3. See: angular/angular#48868
  • Loading branch information
alan-agius4 authored and angular-robot[bot] committed Feb 7, 2023
1 parent bf3be56 commit 88fddc0
Show file tree
Hide file tree
Showing 2 changed files with 1 addition and 110 deletions.
81 changes: 1 addition & 80 deletions packages/schematics/angular/universal/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
getPackageJsonDependency,
} from '../utility/dependencies';
import { latestVersions } from '../utility/latest-versions';
import { findBootstrapModuleCall, findBootstrapModulePath } from '../utility/ng-ast-utils';
import { findBootstrapModulePath } from '../utility/ng-ast-utils';
import { relativePathToWorkspaceRoot } from '../utility/paths';
import { targetBuildNotFoundError } from '../utility/project-targets';
import { getWorkspace, updateWorkspace } from '../utility/workspace';
Expand Down Expand Up @@ -109,84 +109,6 @@ function findBrowserModuleImport(host: Tree, modulePath: string): ts.Node {
return browserModuleNode;
}

function wrapBootstrapCall(mainFile: string): Rule {
return (host: Tree) => {
const mainPath = normalize('/' + mainFile);
let bootstrapCall: ts.Node | null = findBootstrapModuleCall(host, mainPath);
if (bootstrapCall === null) {
throw new SchematicsException('Bootstrap module not found.');
}

let bootstrapCallExpression: ts.Node | null = null;
let currentCall = bootstrapCall;
while (bootstrapCallExpression === null && currentCall.parent) {
currentCall = currentCall.parent;
if (ts.isExpressionStatement(currentCall) || ts.isVariableStatement(currentCall)) {
bootstrapCallExpression = currentCall;
}
}
bootstrapCall = currentCall;

// In case the bootstrap code is a variable statement
// we need to determine it's usage
if (bootstrapCallExpression && ts.isVariableStatement(bootstrapCallExpression)) {
const declaration = bootstrapCallExpression.declarationList.declarations[0];
const bootstrapVar = (declaration.name as ts.Identifier).text;
const sf = bootstrapCallExpression.getSourceFile();
bootstrapCall = findCallExpressionNode(sf, bootstrapVar) || currentCall;
}

// indent contents
const triviaWidth = bootstrapCall.getLeadingTriviaWidth();
const beforeText =
`function bootstrap() {\n` + ' '.repeat(triviaWidth > 2 ? triviaWidth + 1 : triviaWidth);
const afterText =
`\n${triviaWidth > 2 ? ' '.repeat(triviaWidth - 1) : ''}};\n` +
`
if (document.readyState === 'complete') {
bootstrap();
} else {
document.addEventListener('DOMContentLoaded', bootstrap);
}
`;

// in some cases we need to cater for a trailing semicolon such as;
// bootstrap().catch(err => console.log(err));
const lastToken = bootstrapCall.parent.getLastToken();
let endPos = bootstrapCall.getEnd();
if (lastToken && lastToken.kind === ts.SyntaxKind.SemicolonToken) {
endPos = lastToken.getEnd();
}

const recorder = host.beginUpdate(mainPath);
recorder.insertLeft(bootstrapCall.getStart(), beforeText);
recorder.insertRight(endPos, afterText);
host.commitUpdate(recorder);
};
}

function findCallExpressionNode(node: ts.Node, text: string): ts.Node | null {
if (
ts.isCallExpression(node) &&
ts.isIdentifier(node.expression) &&
node.expression.text === text
) {
return node;
}

let foundNode: ts.Node | null = null;
ts.forEachChild(node, (childNode) => {
foundNode = findCallExpressionNode(childNode, text);

if (foundNode) {
return true;
}
});

return foundNode;
}

function addServerTransition(
options: UniversalOptions,
mainFile: string,
Expand Down Expand Up @@ -292,7 +214,6 @@ export default function (options: UniversalOptions): Rule {
mergeWith(rootSource),
addDependencies(),
updateConfigFile(options, tsConfigDirectory),
wrapBootstrapCall(clientBuildOptions.main),
addServerTransition(options, clientBuildOptions.main, clientProject.root),
]);
};
Expand Down
30 changes: 0 additions & 30 deletions packages/schematics/angular/universal/index_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,36 +191,6 @@ describe('Universal Schematic', () => {
expect(contents).not.toContain(`withServerTransition({ appId: 'foo' })`);
});

it('should wrap the bootstrap call in a DOMContentLoaded event handler', async () => {
const tree = await schematicRunner.runSchematic('universal', defaultOptions, appTree);
const filePath = '/projects/bar/src/main.ts';
const contents = tree.readContent(filePath);
expect(contents).toContain(`document.addEventListener('DOMContentLoaded', bootstrap);`);
});

it('should wrap the bootstrap declaration in a DOMContentLoaded event handler', async () => {
const filePath = '/projects/bar/src/main.ts';
appTree.overwrite(
filePath,
`
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
import { hmrBootstrap } from './hmr';
const bootstrap = () => platformBrowserDynamic().bootstrapModule(AppModule);
if (!hmrBootstrap) {
bootstrap().catch(err => console.log(err));
}
`,
);

const tree = await schematicRunner.runSchematic('universal', defaultOptions, appTree);
const contents = tree.readContent(filePath);
expect(contents).toContain(`document.addEventListener('DOMContentLoaded', bootstrap);`);
});

it('should install npm dependencies', async () => {
await schematicRunner.runSchematic('universal', defaultOptions, appTree);
expect(schematicRunner.tasks.length).toBe(1);
Expand Down

0 comments on commit 88fddc0

Please sign in to comment.