Skip to content

Standalone core implementation#45687

Closed
alxhub wants to merge 6 commits intomasterfrom
standalone
Closed

Standalone core implementation#45687
alxhub wants to merge 6 commits intomasterfrom
standalone

Conversation

@alxhub
Copy link
Member

@alxhub alxhub commented Apr 19, 2022

This PR is based on #45672, and adds JIT compilation as well as the actual public API for standalone components 🎉

There's still work to be done after this:

  • bootstrap API
  • Router lazy-loading updates
  • TestBed validation
  • documentation
  • lots more testing
  • etc.

@josephperrott josephperrott added the area: core Issues related to the framework runtime label Apr 19, 2022
@ngbot ngbot bot added this to the Backlog milestone Apr 19, 2022
@alxhub alxhub force-pushed the standalone branch 3 times, most recently from a0ddeba to 74b9350 Compare April 20, 2022 13:37
*/
jit?: true;

standalone?: boolean;

Choose a reason for hiding this comment

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

needs APIs docs

*/
preserveWhitespaces?: boolean;

standalone?: boolean;

Choose a reason for hiding this comment

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

needs APIs docs

standalone?: boolean;

// TODO: better type here!
imports?: (Type<any>|any[])[];

Choose a reason for hiding this comment

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

needs APIs docs

*/
pure?: boolean;

standalone?: boolean;

Choose a reason for hiding this comment

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

needs APIs docs

const dep = resolveForwardRef(rawDep);
if (!dep) {
// TODO: real error
throw new Error(`ForwardRef issue?`);

Choose a reason for hiding this comment

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

needs proper error

if (anyDef) {
if (!anyDef.standalone) {
// TODO: real error
throw new Error(`What are you doing? You imported a non-standalone thing!`);

Choose a reason for hiding this comment

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

needs proper error

viewQueries: extractQueriesMetadata(type, propMetadata, isViewQuery),
// TODO(alxhub): pass through the standalone flag from the directive metadata once standalone
// functionality is fully rolled out.
isStandalone: false,

Choose a reason for hiding this comment

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

I guess the above comment is no longer relevant?

}

// TODO: change the error message to be more user-facing and take standalone into account
throw new Error(`${type.name} does not have a module def (ɵmod property)`);

Choose a reason for hiding this comment

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

needs better error?

@pkozlowski-opensource pkozlowski-opensource force-pushed the standalone branch 4 times, most recently from 3eff87a to 1af65d9 Compare April 20, 2022 18:05
@alxhub alxhub added the target: minor This PR is targeted for the next minor release label Apr 20, 2022
// TODO: real error
throw new Error(`ForwardRef issue?`);
}
const ngModuleDef: NgModuleDef<any>|null = getNgModuleDef(dep);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
const ngModuleDef: NgModuleDef<any>|null = getNgModuleDef(dep);
const ngModuleDef = getNgModuleDef<Type<unknown>>(dep);

Should this have a more restrictive type?

if (ngModuleDef) {
dependencies.push({
kind: R3TemplateDependencyKind.NgModule,
type: dep as any,
Copy link
Contributor

Choose a reason for hiding this comment

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

Is the as any needed here?

importingModule?: NgModuleType): void {
if (verifiedNgModule.get(moduleType)) return;

// skip verifications of standalone components, direcrtives and pipes
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: this comment is "what" but not why. It's mostly obvious that if (isStandalone(moduleType)) return; skips the verification. This comment should be updated to explain why or deleted. Also "direcrtives" is misspelled.

flatten(imports).map(unwrapModuleWithProvidersImports).forEach(mod => {
verifySemanticsOfNgModuleImport(mod, moduleType);
verifySemanticsOfNgModuleDef(mod, false, moduleType);
flatten(imports).map(unwrapModuleWithProvidersImports).forEach(modOrStandaloneCmpt => {
Copy link
Contributor

Choose a reason for hiding this comment

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

uber(!!) nit: We generally use Cmp for the shorthand of "component" if we're doing that. The "t" almost looks like a typo to me.

Comment on lines +413 to +418
const ngModuleDef = getNgModuleDef(type);

// a standalone component, directive or pipe
if (ngModuleDef === null) {
return [type];
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
const ngModuleDef = getNgModuleDef(type);
// a standalone component, directive or pipe
if (ngModuleDef === null) {
return [type];
}
if (isStandalone(type)) {
return [type];
}
const ngModuleDef = getNgModuleDef(type, true);

nit: Personally I would think this would be easier to read and doesn't need a comment. But I can imagine it's slightly less optimal because there are a couple more lookups involved by calling isStandalone

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep - exactly.

@pullapprove pullapprove bot requested review from atscott April 20, 2022 20:30
* TODO(pk): documentation
* A feature that acts as a setup code for the {@see StandaloneService}.
*
* The most important responsaibility of this feature is to expose the "getStandaloneInjector"
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: s/responsaibility/responsibility

Copy link
Contributor

@AndrewKushnir AndrewKushnir left a comment

Choose a reason for hiding this comment

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

LGTM, just left a few comments. None of them are blockers and we can look into them in a followup PR.

Copy link
Contributor

Choose a reason for hiding this comment

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

nit: can we add a TODO to add a comment here in a followup PR?

Copy link
Contributor

Choose a reason for hiding this comment

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

nit: it'd be great to extract componentDefinition.standalone === true into a separate const and reuse in 2 places above (for code size optimization):

  const standalone = componentDefinition.standalone === true;

(let's leave a TODO and I can cleanup in a followup PR)

Comment on lines +208 to +209
// skip verifications of standalone components, direcrtives and pipes
if (isStandalone(moduleType)) return;
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we have a verification somewhere else or it should be implemented as a followup?

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not sure if "skip verification" here is a TODO for later - I think this means "skip NgModule verification"

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, I was wondering if we do similar verification for imported standalone types somewhere else (thus we don't need it).

const ngModuleDef = getNgModuleDef(type, true);
const ngModuleDef = getNgModuleDef(type);

// a standalone component, directive or pipe
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: I think adding an assert here (in a followup PR) to check that a type is actually standalone would be great.

@pullapprove pullapprove bot requested a review from atscott April 20, 2022 20:59
Copy link
Contributor

@atscott atscott left a comment

Choose a reason for hiding this comment

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

reviewed-for: size-tracking, public-api

@alxhub alxhub added action: merge The PR is ready for merge by the caretaker merge: caretaker note Alert the caretaker performing the merge to check the PR for an out of normal action needed or note labels Apr 20, 2022
@alxhub
Copy link
Member Author

alxhub commented Apr 20, 2022

Caretaker: the functions here have already been reviewed for public-api (in a previous commit, they just didn't make it into the golden, for reasons). Consider it approved!

Copy link
Contributor

@AndrewKushnir AndrewKushnir left a comment

Choose a reason for hiding this comment

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

Reviewed-for: size-tracking, public-api

@dylhunn dylhunn removed their request for review April 20, 2022 22:08
@pullapprove pullapprove bot requested a review from dylhunn April 20, 2022 22:08
alxhub and others added 6 commits April 20, 2022 15:21
This commit extracts the `importProvidersFrom` function and associated
machinery into a separate file, as opposed to being colocated with
`R3Injector`. Separating these functions will mitigate potential future
circular dependencies as `importProvidersFrom` starts being used in
different parts of the codebase.
This commit exposes the `standalone` flag on `@Directive`, `@Component`, and
`@Pipe`, effectively making standalone components a part of Angular's public
API. As part of this operation, it also implements JIT compilation for
standalone types.

Standalone types are Angular-decorated types which act as their own
"declarations", where they would otherwise be declared in an NgModule.
Marking an Angular type as standalone means that it can be used directly in
other standalone components and in NgModules, without needing an associated
NgModule to depend on it. In the case of a standalone component, template
dependencies which would otherwise be specified by an NgModule are instead
specified directly on the component itself, via the `imports` field. Other
standalone types can be imported, as well as NgModules.
This commit refactors `importProvidersFrom` to support pulling providers
from the dependencies of a standalone component, in addition to NgModules.
Tests will be added in a future commit when standalone components can be
created without calling private APIs.
This commit implements the `StandaloneFeature` which provides for the
creation of standalone injectors, for those components which need them. The
feature-based implementation ensures the machinery for standalone injectors
is properly tree-shakable.
This commit reorganizes the tests around the EnvironmentInjector and its use
for standalone injectors, and adds a number of new test cases.
This commit adds some internal documentation.
@atscott
Copy link
Contributor

atscott commented Apr 20, 2022

This PR was merged into the repository by commit 9e4c4bc.

@atscott atscott closed this in bb6e11c Apr 20, 2022
atscott pushed a commit that referenced this pull request Apr 20, 2022
…45687)

This commit exposes the `standalone` flag on `@Directive`, `@Component`, and
`@Pipe`, effectively making standalone components a part of Angular's public
API. As part of this operation, it also implements JIT compilation for
standalone types.

Standalone types are Angular-decorated types which act as their own
"declarations", where they would otherwise be declared in an NgModule.
Marking an Angular type as standalone means that it can be used directly in
other standalone components and in NgModules, without needing an associated
NgModule to depend on it. In the case of a standalone component, template
dependencies which would otherwise be specified by an NgModule are instead
specified directly on the component itself, via the `imports` field. Other
standalone types can be imported, as well as NgModules.

PR Close #45687
atscott pushed a commit that referenced this pull request Apr 20, 2022
…45687)

This commit refactors `importProvidersFrom` to support pulling providers
from the dependencies of a standalone component, in addition to NgModules.
Tests will be added in a future commit when standalone components can be
created without calling private APIs.

PR Close #45687
atscott pushed a commit that referenced this pull request Apr 20, 2022
This commit implements the `StandaloneFeature` which provides for the
creation of standalone injectors, for those components which need them. The
feature-based implementation ensures the machinery for standalone injectors
is properly tree-shakable.

PR Close #45687
atscott pushed a commit that referenced this pull request Apr 20, 2022
This commit reorganizes the tests around the EnvironmentInjector and its use
for standalone injectors, and adds a number of new test cases.

PR Close #45687
atscott pushed a commit that referenced this pull request Apr 20, 2022
This commit adds some internal documentation.

PR Close #45687
AndrewKushnir added a commit to AndrewKushnir/angular that referenced this pull request May 11, 2022
This commit updates the standalone-related logic to address the feedback from previous code reviews (specifically: angular#45687 (comment)).
jessicajaniuk pushed a commit that referenced this pull request May 16, 2022
…45949)

This commit updates the standalone-related logic to address the feedback from previous code reviews (specifically: #45687 (comment)).

PR Close #45949
jessicajaniuk pushed a commit that referenced this pull request May 16, 2022
…45949)

This commit updates the standalone-related logic to address the feedback from previous code reviews (specifically: #45687 (comment)).

PR Close #45949
@alxhub alxhub deleted the standalone branch May 19, 2022 22:47
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Jun 19, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

action: merge The PR is ready for merge by the caretaker area: core Issues related to the framework runtime merge: caretaker note Alert the caretaker performing the merge to check the PR for an out of normal action needed or note target: minor This PR is targeted for the next minor release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants