Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions 4 adev/src/content/guide/routing/data-resolvers.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,11 +205,11 @@ export class App {
map(event => {
if (event instanceof NavigationError) {
this.lastFailedUrl.set(event.url);

if (event.error) {
console.error('Navigation error', event.error)
}

return 'Navigation failed. Please try again.';
}
return '';
Expand Down
1 change: 1 addition & 0 deletions 1 goldens/public-api/compiler-cli/error_code.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export enum ErrorCode {
INLINE_TYPE_CTOR_REQUIRED = 8901,
INTERPOLATED_SIGNAL_NOT_INVOKED = 8109,
INVALID_BANANA_IN_BOX = 8101,
ISOLATED_SHADOW_DOM_INVALID_CONTENT_PROJECTION = 2028,
LET_USED_BEFORE_DEFINITION = 8016,
LOCAL_COMPILATION_UNRESOLVED_CONST = 11001,
LOCAL_COMPILATION_UNSUPPORTED_EXPRESSION = 11003,
Expand Down
2 changes: 2 additions & 0 deletions 2 goldens/public-api/platform-browser/errors.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ export const enum RuntimeErrorCode {
// (undocumented)
SANITIZATION_UNSAFE_SCRIPT = 5200,
// (undocumented)
SHADOWDOM_NOT_SUPPORTED_IN_SSR = 5106,
// (undocumented)
TESTABILITY_NOT_FOUND = 5103,
// (undocumented)
UNEXPECTED_SYNTHETIC_PROPERTY = 5105,
Expand Down
6 changes: 3 additions & 3 deletions 6 integration/cli-hello-world-lazy/size.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"dist/main.js": 108611,
"dist/polyfills.js": 34169,
"dist/lazy.routes-[hash].js": 361
"dist/main.js": 113764,
"dist/polyfills.js": 34585,
"dist/lazy.routes-[hash].js": 348
}
4 changes: 2 additions & 2 deletions 4 integration/defer/size.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"dist/main.js": 12709,
"dist/main.js": 16485,
"dist/polyfills.js": 35677,
"dist/defer.component-[hash].js": 345
"dist/defer.component-[hash].js": 331
}
6 changes: 3 additions & 3 deletions 6 integration/legacy-animations-async/size.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"dist/main.js": 97227,
"dist/main.js": 102215,
"dist/polyfills.js": 35677,
"dist/browser-[hash].js": 63949,
"dist/open-close.component-[hash].js": 1218
"dist/browser-[hash].js": 64236,
"dist/open-close.component-[hash].js": 1189
}
6 changes: 3 additions & 3 deletions 6 integration/legacy-animations/size.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"dist/main.js": 153915,
"dist/polyfills.js": 34023,
"dist/open-close.component-[hash].js": 1190
"dist/main.js": 159053,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is quite an increase, we should investigate better tree shaking when the feature isn't used

Copy link
Contributor Author

@ryan-bendel ryan-bendel Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I shall take a look @JeanMeche - but i am struggling to run the integration tests locally (i bumped all the size.json from the output in the gh test runner output),

I get:

ERROR  Failed to switch pnpm to v10.23.0. Looks like pnpm CLI is missing at "/var/folders/kj/cqmyhbyx0zv7mrtvpdlj19dw0000gp/T/ng-integration-test7nTJJM/tmp-env-0/Library/pnpm/.tools/pnpm/10.23.0/bin" or is incorrect
spawnSync /var/folders/kj/cqmyhbyx0zv7mrtvpdlj19dw0000gp/T/ng-integration-test7nTJJM/tmp-env-0/Library/pnpm/.tools/pnpm/10.23.0/bin/pnpm ENOENT
Command failed: `pnpm install`

🤔

"dist/polyfills.js": 35677,
"dist/open-close.component-[hash].js": 1131
}
4 changes: 2 additions & 2 deletions 4 integration/platform-server-hydration/size.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"dist/browser/main-[hash].js": 227093,
"dist/browser/polyfills-[hash].js": 34544,
"dist/browser/main-[hash].js": 234529,
"dist/browser/polyfills-[hash].js": 35677,
"dist/browser/event-dispatch-contract.min.js": 476
}
2 changes: 1 addition & 1 deletion 2 integration/standalone-bootstrap/size.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"dist/main.js": 89237,
"dist/main.js": 97201,
"dist/polyfills.js": 35677
}
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,24 @@ export class ComponentDecoratorHandler
}
}

// Check for ng-content in IsolatedShadowDom components
if (encapsulation === ViewEncapsulation.ExperimentalIsolatedShadowDom) {
const contentNode = findContentNode(template.nodes);
if (contentNode !== null) {
if (diagnostics === undefined) {
diagnostics = [];
}
diagnostics.push(
makeDiagnostic(
ErrorCode.ISOLATED_SHADOW_DOM_INVALID_CONTENT_PROJECTION,
component.get('template') ?? node.name,
`ng-content projection is not supported with ViewEncapsulation.ExperimentalIsolatedShadowDom. ` +
`Use native <slot> elements instead. Content will remain in the light DOM and be projected via slots.`,
),
);
}
}

// If inline styles were preprocessed use those
let inlineStyles: string[] | null = null;
if (this.preanalyzeStylesCache.has(node)) {
Expand Down Expand Up @@ -2637,3 +2655,24 @@ function validateStandaloneImports(
function isDefaultImport(node: ts.ImportDeclaration): boolean {
return node.importClause !== undefined && node.importClause.namedBindings === undefined;
}

/**
* Recursively searches through template nodes to find a Content node (ng-content).
* Returns the first Content node found, or null if none exist.
*/
function findContentNode(nodes: any[]): any | null {
for (const node of nodes) {
// Check if this is a Content node (ng-content)
if (node.name === 'ng-content') {
return node;
}
// Recursively check children
if (node.children && node.children.length > 0) {
const found = findContentNode(node.children);
if (found !== null) {
return found;
}
}
}
return null;
}
6 changes: 6 additions & 0 deletions 6 packages/compiler-cli/src/ngtsc/diagnostics/src/error_code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,12 @@ export enum ErrorCode {
*/
COMPONENT_ANIMATIONS_CONFLICT = 2027,

/**
* Raised when a component with `ViewEncapsulation.ExperimentalIsolatedShadowDom` uses `<ng-content>`.
* ExperimentalIsolatedShadowDom components must use native `<slot>` elements instead.
*/
ISOLATED_SHADOW_DOM_INVALID_CONTENT_PROJECTION = 2028,

SYMBOL_NOT_EXPORTED = 3001,
/**
* Raised when a relationship between directives and/or pipes would cause a cyclic import to be
Expand Down
4 changes: 4 additions & 0 deletions 4 packages/core/src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ export {createComponent, reflectComponentType, ComponentMirror} from './render3/
export {isStandalone} from './render3/def_getters';
export {AfterRenderRef} from './render3/after_render/api';
export {publishExternalGlobalUtil as ɵpublishExternalGlobalUtil} from './render3/util/global_utils';
export {readPatchedData as eReadPatchedData} from './render3/context_discovery';
export {unwrapRNode as ɵunwrapRNode} from './render3/util/view_utils';
export {HOST as ɵHOST, PARENT as ɵPARENT} from './render3/interfaces/view';
export {enableProfiling} from './render3/debug/chrome_dev_tools_performance';
export {
AfterRenderOptions,
Expand All @@ -126,6 +129,7 @@ export {
} from './animation/interfaces';

import {global} from './util/global';

if (typeof ngDevMode !== 'undefined' && ngDevMode) {
// This helper is to give a reasonable error message to people upgrading to v9 that have not yet
// installed `@angular/localize` in their app.
Expand Down
21 changes: 20 additions & 1 deletion 21 packages/core/src/render3/instructions/projection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {newArray} from '../../util/array_utils';
import {assertLContainer, assertTNode} from '../assert';
import {ComponentTemplate} from '../interfaces/definition';
import {TAttributes, TElementNode, TNode, TNodeType} from '../interfaces/node';
import {ViewEncapsulation} from '../../metadata/view';
import {ProjectionSlots} from '../interfaces/projection';
import {
DECLARATION_COMPONENT_VIEW,
Expand All @@ -32,6 +33,7 @@ import {addLViewToLContainer} from '../view/container';
import {createAndRenderEmbeddedLView, shouldAddViewToDom} from '../view_manipulation';

import {declareNoDirectiveHostTemplate} from './template';
import {getDeclarationComponentDef} from '../../render3/instructions/element_validation';

/**
* Checks a given node against matching projection slots and returns the
Expand Down Expand Up @@ -94,7 +96,24 @@ export function matchingProjectionSlotIndex(
* @codeGenApi
*/
export function ɵɵprojectionDef(projectionSlots?: ProjectionSlots): void {
const componentNode = getLView()[DECLARATION_COMPONENT_VIEW][T_HOST] as TElementNode;
const lView = getLView();
const declarationComponentView = lView[DECLARATION_COMPONENT_VIEW];
const componentNode = declarationComponentView[T_HOST] as TElementNode;

// Check if this is an IsolatedShadowDom component
// The component instance is stored in CONTEXT
const componentDef = getDeclarationComponentDef(declarationComponentView);

if (componentDef?.encapsulation === ViewEncapsulation.ExperimentalIsolatedShadowDom) {
if (typeof ngDevMode !== 'undefined' && ngDevMode) {
throw new Error(
`ng-content projection is not supported with ViewEncapsulation.IsolatedShadowDom. ` +
`Use native <slot> elements instead. Content will remain in the light DOM and be projected via slots.`,
);
}
// Don't setup projection for IsolatedShadowDom
return;
}

if (!componentNode.projection) {
// If no explicit projection slots are defined, fall back to a single
Expand Down
4 changes: 4 additions & 0 deletions 4 packages/core/test/acceptance/renderer_factory_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
ɵDomRendererFactory2 as DomRendererFactory2,
EventManager,
ɵSharedStylesHost,
ɵStyleScopeService as StyleScopeService,
} from '@angular/platform-browser';
import {isBrowser, isNode} from '@angular/private/testing';
import {expect} from '@angular/private/testing/matchers';
Expand Down Expand Up @@ -396,6 +397,7 @@ function getRendererFactory2(document: Document): RendererFactory2 {
const fakeNgZone: NgZone = new NoopNgZone();
const eventManager = new EventManager([], fakeNgZone);
const appId = 'app-id';
const styleScopeService = new StyleScopeService();
const rendererFactory = new DomRendererFactory2(
eventManager,
new ɵSharedStylesHost(document, appId),
Expand All @@ -404,6 +406,8 @@ function getRendererFactory2(document: Document): RendererFactory2 {
document,
fakeNgZone,
null,
null, // tracingService
styleScopeService,
);
const origCreateRenderer = rendererFactory.createRenderer;
rendererFactory.createRenderer = function (element: any, type: RendererType2 | null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@
"InjectionToken",
"Injector",
"InputFlags",
"IsolatedStyleScopeService",
"KeyEventsPlugin",
"LEAVE_CLASSNAME",
"LEAVE_TOKEN",
Expand Down Expand Up @@ -508,6 +509,7 @@
"getInsertInFrontOfRNode",
"getInsertInFrontOfRNodeWithNoI18n",
"getLView",
"getLViewById",
"getLViewParent",
"getNameOnlyMarkerIndex",
"getNamespace",
Expand Down Expand Up @@ -742,6 +744,7 @@
"providerToRecord",
"publishSignalConfiguration",
"queueEnterAnimations",
"readPatchedData",
"refreshContentQueries",
"refreshView",
"registerFailed",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
"InjectionToken",
"Injector",
"InputFlags",
"IsolatedStyleScopeService",
"KeyEventsPlugin",
"LOCALE_ID",
"LOCALE_ID",
Expand Down Expand Up @@ -406,6 +407,7 @@
"getInsertInFrontOfRNode",
"getInsertInFrontOfRNodeWithNoI18n",
"getLView",
"getLViewById",
"getLViewParent",
"getNativeByIndex",
"getNativeByTNode",
Expand Down Expand Up @@ -588,6 +590,7 @@
"providerToRecord",
"publishSignalConfiguration",
"queueEnterAnimations",
"readPatchedData",
"refreshContentQueries",
"refreshView",
"registerHostBindingOpCodes",
Expand Down
3 changes: 3 additions & 0 deletions 3 packages/core/test/bundling/defer/bundle.golden_symbols.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"EventManagerPlugin",
"HOST_ATTR",
"INTERNAL_BROWSER_PLATFORM_PROVIDERS",
"IsolatedStyleScopeService",
"KeyEventsPlugin",
"MODIFIER_KEYS",
"MODIFIER_KEY_GETTERS",
Expand Down Expand Up @@ -456,6 +457,7 @@
"getInsertInFrontOfRNodeWithNoI18n",
"getLDeferBlockDetails",
"getLView",
"getLViewById",
"getLViewParent",
"getLoadingBlockAfter",
"getMinimumDurationForState",
Expand Down Expand Up @@ -644,6 +646,7 @@
"providerToRecord",
"publishSignalConfiguration",
"queueEnterAnimations",
"readPatchedData",
"refreshContentQueries",
"refreshView",
"registerHostBindingOpCodes",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@
"InjectionToken",
"Injector",
"InputFlags",
"IsolatedStyleScopeService",
"IterableChangeRecord_",
"IterableDiffers",
"KeyEventsPlugin",
Expand Down Expand Up @@ -574,6 +575,7 @@
"getInsertInFrontOfRNode",
"getInsertInFrontOfRNodeWithNoI18n",
"getLView",
"getLViewById",
"getLViewParent",
"getNameOnlyMarkerIndex",
"getNamespace",
Expand Down Expand Up @@ -859,6 +861,7 @@
"providersResolver",
"publishSignalConfiguration",
"queueEnterAnimations",
"readPatchedData",
"readableStreamLikeToAsyncGenerator",
"refreshContentQueries",
"refreshView",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@
"InjectionToken",
"Injector",
"InputFlags",
"IsolatedStyleScopeService",
"IterableChangeRecord_",
"IterableDiffers",
"KeyEventsPlugin",
Expand Down Expand Up @@ -575,6 +576,7 @@
"getInsertInFrontOfRNode",
"getInsertInFrontOfRNodeWithNoI18n",
"getLView",
"getLViewById",
"getLViewParent",
"getNameOnlyMarkerIndex",
"getNamespace",
Expand Down Expand Up @@ -857,6 +859,7 @@
"providersResolver",
"publishSignalConfiguration",
"queueEnterAnimations",
"readPatchedData",
"readableStreamLikeToAsyncGenerator",
"refreshContentQueries",
"refreshView",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@
"InjectionToken",
"Injector",
"InputFlags",
"IsolatedStyleScopeService",
"JSON_CONTENT_TYPE",
"KeyEventsPlugin",
"LOCALE_ID",
Expand Down Expand Up @@ -477,6 +478,7 @@
"getInsertInFrontOfRNodeWithNoI18n",
"getLNodeForHydration",
"getLView",
"getLViewById",
"getLViewParent",
"getNamespace",
"getNativeByTNode",
Expand Down Expand Up @@ -683,6 +685,7 @@
"providerToRecord",
"publishSignalConfiguration",
"queueEnterAnimations",
"readPatchedData",
"readableStreamLikeToAsyncGenerator",
"refreshContentQueries",
"refreshView",
Expand Down
3 changes: 3 additions & 0 deletions 3 packages/core/test/bundling/router/bundle.golden_symbols.json
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@
"InjectionToken",
"Injector",
"InputFlags",
"IsolatedStyleScopeService",
"ItemComponent",
"KeyEventsPlugin",
"LOCALE_ID",
Expand Down Expand Up @@ -665,6 +666,7 @@
"getInsertInFrontOfRNode",
"getInsertInFrontOfRNodeWithNoI18n",
"getLView",
"getLViewById",
"getLViewParent",
"getNameOnlyMarkerIndex",
"getNamespace",
Expand Down Expand Up @@ -967,6 +969,7 @@
"providerToRecord",
"publishSignalConfiguration",
"queueEnterAnimations",
"readPatchedData",
"readableStreamLikeToAsyncGenerator",
"recognize",
"recognize",
Expand Down
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.