Skip to content

Commit fc68dca

Browse files
committed
refactor(@angular/ssr): remove code that sets initialNavigation: enabledBlocking
This removes that code that was used to set `initialNavigation: enabledBlocking` as this is no longer needed to reduce flickering. This is because `initialNavigation: enabledBlocking` is not needed when enabling hydration via `provideClientHydration` which is done in the internal server schematic.
1 parent 6979eba commit fc68dca

File tree

2 files changed

+2
-222
lines changed

2 files changed

+2
-222
lines changed

packages/angular/ssr/schematics/ng-add/index.ts

Lines changed: 2 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,10 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import { dirname, join, normalize, strings } from '@angular-devkit/core';
9+
import { join, normalize, strings } from '@angular-devkit/core';
1010
import {
1111
Rule,
1212
SchematicsException,
13-
Tree,
1413
apply,
1514
applyTemplates,
1615
chain,
@@ -28,16 +27,9 @@ import { targetBuildNotFoundError } from '@schematics/angular/utility/project-ta
2827
import { getMainFilePath } from '@schematics/angular/utility/standalone/util';
2928
import { getWorkspace } from '@schematics/angular/utility/workspace';
3029
import { Builders } from '@schematics/angular/utility/workspace-models';
31-
import * as ts from 'typescript';
3230

3331
import { latestVersions } from '../utility/latest-versions';
34-
import {
35-
addInitialNavigation,
36-
findImport,
37-
getImportOfIdentifier,
38-
getOutputPath,
39-
getProject,
40-
} from '../utility/utils';
32+
import { getOutputPath, getProject } from '../utility/utils';
4133

4234
import { Schema as AddServerOptions } from './schema';
4335

@@ -199,109 +191,6 @@ function updateWebpackBuilderServerTsConfigRule(options: AddServerOptions): Rule
199191
};
200192
}
201193

202-
function routingInitialNavigationRule(options: ServerOptions): Rule {
203-
return async (host) => {
204-
const project = await getProject(host, options.project);
205-
const serverTarget = project.targets.get('server');
206-
if (!serverTarget || !serverTarget.options) {
207-
return;
208-
}
209-
210-
const tsConfigPath = serverTarget.options.tsConfig;
211-
if (!tsConfigPath || typeof tsConfigPath !== 'string' || !host.exists(tsConfigPath)) {
212-
// No tsconfig path
213-
return;
214-
}
215-
216-
const parseConfigHost: ts.ParseConfigHost = {
217-
useCaseSensitiveFileNames: ts.sys.useCaseSensitiveFileNames,
218-
readDirectory: ts.sys.readDirectory,
219-
fileExists: function (fileName: string): boolean {
220-
return host.exists(fileName);
221-
},
222-
readFile: function (fileName: string): string {
223-
return host.readText(fileName);
224-
},
225-
};
226-
const { config } = ts.readConfigFile(tsConfigPath, parseConfigHost.readFile);
227-
const parsed = ts.parseJsonConfigFileContent(
228-
config,
229-
parseConfigHost,
230-
dirname(normalize(tsConfigPath)),
231-
);
232-
const tsHost = ts.createCompilerHost(parsed.options, true);
233-
// Strip BOM as otherwise TSC methods (Ex: getWidth) will return an offset,
234-
// which breaks the CLI UpdateRecorder.
235-
// See: https://github.com/angular/angular/pull/30719
236-
tsHost.readFile = function (fileName: string): string {
237-
return host.readText(fileName).replace(/^\uFEFF/, '');
238-
};
239-
tsHost.directoryExists = function (directoryName: string): boolean {
240-
// When the path is file getDir will throw.
241-
try {
242-
const dir = host.getDir(directoryName);
243-
244-
return !!(dir.subdirs.length || dir.subfiles.length);
245-
} catch {
246-
return false;
247-
}
248-
};
249-
tsHost.fileExists = function (fileName: string): boolean {
250-
return host.exists(fileName);
251-
};
252-
tsHost.realpath = function (path: string): string {
253-
return path;
254-
};
255-
tsHost.getCurrentDirectory = function () {
256-
return host.root.path;
257-
};
258-
259-
const program = ts.createProgram(parsed.fileNames, parsed.options, tsHost);
260-
const typeChecker = program.getTypeChecker();
261-
const sourceFiles = program
262-
.getSourceFiles()
263-
.filter((f) => !f.isDeclarationFile && !program.isSourceFileFromExternalLibrary(f));
264-
const printer = ts.createPrinter();
265-
const routerModule = 'RouterModule';
266-
const routerSource = '@angular/router';
267-
268-
sourceFiles.forEach((sourceFile) => {
269-
const routerImport = findImport(sourceFile, routerSource, routerModule);
270-
if (!routerImport) {
271-
return;
272-
}
273-
274-
ts.forEachChild(sourceFile, function visitNode(node: ts.Node) {
275-
if (
276-
ts.isCallExpression(node) &&
277-
ts.isPropertyAccessExpression(node.expression) &&
278-
ts.isIdentifier(node.expression.expression) &&
279-
node.expression.name.text === 'forRoot'
280-
) {
281-
const imp = getImportOfIdentifier(typeChecker, node.expression.expression);
282-
283-
if (imp && imp.name === routerModule && imp.importModule === routerSource) {
284-
const print = printer.printNode(
285-
ts.EmitHint.Unspecified,
286-
addInitialNavigation(node),
287-
sourceFile,
288-
);
289-
290-
const recorder = host.beginUpdate(sourceFile.fileName);
291-
recorder.remove(node.getStart(), node.getWidth());
292-
recorder.insertRight(node.getStart(), print);
293-
host.commitUpdate(recorder);
294-
295-
return;
296-
}
297-
}
298-
299-
ts.forEachChild(node, visitNode);
300-
});
301-
});
302-
};
303-
}
304-
305194
function addDependencies(): Rule {
306195
return chain([
307196
addDependency('express', latestVersions['express'], {
@@ -369,7 +258,6 @@ export default function (options: AddServerOptions): Rule {
369258
updateWebpackBuilderServerTsConfigRule(options),
370259
updateWebpackBuilderWorkspaceConfigRule(options),
371260
]),
372-
isStandalone ? noop() : routingInitialNavigationRule(options),
373261
addServerFile(options, isStandalone),
374262
addDependencies(),
375263
]);

packages/angular/ssr/schematics/utility/utils.ts

Lines changed: 0 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import { workspaces } from '@angular-devkit/core';
1010
import { SchematicsException, Tree } from '@angular-devkit/schematics';
1111
import { readWorkspace } from '@schematics/angular/utility';
12-
import * as ts from 'typescript';
1312

1413
export async function getProject(
1514
host: Tree,
@@ -25,10 +24,6 @@ export async function getProject(
2524
return project;
2625
}
2726

28-
export function stripTsExtension(file: string): string {
29-
return file.replace(/\.ts$/, '');
30-
}
31-
3227
export async function getOutputPath(
3328
host: Tree,
3429
projectName: string,
@@ -50,106 +45,3 @@ export async function getOutputPath(
5045

5146
return outputPath;
5247
}
53-
54-
export function findImport(
55-
sourceFile: ts.SourceFile,
56-
moduleName: string,
57-
symbolName: string,
58-
): ts.NamedImports | null {
59-
// Only look through the top-level imports.
60-
for (const node of sourceFile.statements) {
61-
if (
62-
!ts.isImportDeclaration(node) ||
63-
!ts.isStringLiteral(node.moduleSpecifier) ||
64-
node.moduleSpecifier.text !== moduleName
65-
) {
66-
continue;
67-
}
68-
69-
const namedBindings = node.importClause && node.importClause.namedBindings;
70-
71-
if (!namedBindings || !ts.isNamedImports(namedBindings)) {
72-
continue;
73-
}
74-
75-
if (namedBindings.elements.some((element) => element.name.text === symbolName)) {
76-
return namedBindings;
77-
}
78-
}
79-
80-
return null;
81-
}
82-
83-
export type Import = {
84-
name: string;
85-
importModule: string;
86-
node: ts.ImportDeclaration;
87-
};
88-
89-
/** Gets import information about the specified identifier by using the Type checker. */
90-
export function getImportOfIdentifier(
91-
typeChecker: ts.TypeChecker,
92-
node: ts.Identifier,
93-
): Import | null {
94-
const symbol = typeChecker.getSymbolAtLocation(node);
95-
96-
if (!symbol || !symbol.declarations?.length) {
97-
return null;
98-
}
99-
100-
const decl = symbol.declarations[0];
101-
102-
if (!ts.isImportSpecifier(decl)) {
103-
return null;
104-
}
105-
106-
const importDecl = decl.parent.parent.parent;
107-
108-
if (!ts.isStringLiteral(importDecl.moduleSpecifier)) {
109-
return null;
110-
}
111-
112-
return {
113-
// Handles aliased imports: e.g. "import {Component as myComp} from ...";
114-
name: decl.propertyName ? decl.propertyName.text : decl.name.text,
115-
importModule: importDecl.moduleSpecifier.text,
116-
node: importDecl,
117-
};
118-
}
119-
120-
export function addInitialNavigation(node: ts.CallExpression): ts.CallExpression {
121-
const existingOptions = node.arguments[1] as ts.ObjectLiteralExpression | undefined;
122-
123-
// If the user has explicitly set initialNavigation, we respect that
124-
if (
125-
existingOptions &&
126-
existingOptions.properties.some(
127-
(exp) =>
128-
ts.isPropertyAssignment(exp) &&
129-
ts.isIdentifier(exp.name) &&
130-
exp.name.text === 'initialNavigation',
131-
)
132-
) {
133-
return node;
134-
}
135-
136-
const enabledLiteral = ts.factory.createStringLiteral('enabledBlocking');
137-
// TypeScript will emit the Node with double quotes.
138-
// In schematics we usually write code with a single quotes
139-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
140-
(enabledLiteral as any).singleQuote = true;
141-
142-
const initialNavigationProperty = ts.factory.createPropertyAssignment(
143-
'initialNavigation',
144-
enabledLiteral,
145-
);
146-
const routerOptions = existingOptions
147-
? ts.factory.updateObjectLiteralExpression(
148-
existingOptions,
149-
ts.factory.createNodeArray([...existingOptions.properties, initialNavigationProperty]),
150-
)
151-
: ts.factory.createObjectLiteralExpression([initialNavigationProperty], true);
152-
const args = [node.arguments[0], routerOptions];
153-
154-
return ts.factory.createCallExpression(node.expression, node.typeArguments, args);
155-
}

0 commit comments

Comments
 (0)