-
Notifications
You must be signed in to change notification settings - Fork 26.4k
feat(compiler-cli): add resource inlining to ngc #22615
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
dd1a51d
to
4b18d71
Compare
You can preview dd1a51d at https://pr22615-dd1a51d.ngbuilds.io/. |
You can preview 4b18d71 at https://pr22615-4b18d71.ngbuilds.io/. |
@chuckjaz : the
|
@alexeagle will this respect TS path mapping? |
4b18d71
to
191689a
Compare
@alfaproject this uses the existing resource loader in ngc so the behavior should be the same - so no :( |
You can preview 191689a at https://pr22615-191689a.ngbuilds.io/. |
When angularCompilerOptions { enableResourceInlining: true }, we replace all templateUrl and styleUrls properties in @component with template/styles
191689a
to
627be1d
Compare
You can preview 627be1d at https://pr22615-627be1d.ngbuilds.io/. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NITs, otherwise LGTM
|
||
updateDecoratorMetadata(arg: MetadataObject): MetadataObject { | ||
if (arg['templateUrl']) { | ||
const templateUrl = arg['templateUrl']; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT: Consider factoring out the code duplication between templateUrl
and styleUrls
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
|
||
const declaration = symbol.declarations[0] !; | ||
|
||
if (!ts.isImportSpecifier(declaration)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider adding !declarations ||
here instead of the !
on 217.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
|
||
const name = (declaration.propertyName || declaration.name).text; | ||
const moduleId = | ||
(declaration.parent !.parent !.parent !.moduleSpecifier as ts.StringLiteral).text; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider adding a comment that parents are guaranteed to be set in the AST given to a transformer and the depth of the tree is guaranteed by the the traversal by which arrives at this code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
*/ | ||
function updateComponentProperties( | ||
args: ts.NodeArray<ts.Expression>, host: ResourceLoader): ts.NodeArray<ts.Expression> { | ||
if (args.length !== 1) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 for redundant checks as you can emit on error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't follow - are you saying this code is good as written since it's tolerant of incorrect input?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes!
return node; | ||
|
||
default: | ||
break; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return node;
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops, missing a test for that
@alexeagle sorry if it's off-topic, but did you guys ever considered that? o: |
@alfaproject I can understand how you might load resources dynamically, and have a different design-time module layout on disk than you have at runtime when fetching resources, and so you have exactly the same use case that TypeScript path mapping was designed for. And it reduces overall complexity for users if the various ways to express a dependency from one file on another use the same semantics. I think it's reasonable to file a feature request for that. |
You can preview d7a9dd6 at https://pr22615-d7a9dd6.ngbuilds.io/. |
You can preview 0148f5b at https://pr22615-0148f5b.ngbuilds.io/. |
@alexeagle oh, nice. Yep lets try it, currently I inlined the templates manually in the bazel branch |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey Alex, it will be a big win!
import {MetadataTransformer, ValueTransform} from './metadata_cache'; | ||
|
||
export type ResourceLoader = { | ||
loadResource(path: string): Promise<string>| string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Perfect! The Promise<string> | string
allows to integrate external tools like scss, less and other preprocessors preprocessors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nope, if it doesn't return string
this transform fails because the typescript compiler is a synchronous API. Under this toolchain the preprocessors are expected to run before ngc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm 😐 Nevertheless, I'll get rid of the horrible replace source text by string-position-marker thing that you'll solved in a more elegant way in ngc.
// The number of parent references here match the recursion depth at this point. | ||
const moduleId = | ||
(declaration.parent !.parent !.parent !.moduleSpecifier as ts.StringLiteral).text; | ||
return moduleId === '@angular/core' && name === 'Component'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
devkit has an AST util for resolving namespace imports. ng-packagr resolves namespaces too
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks, Angular has a build-time dependency on devkit but not yet a runtime dependency... will have to think about that.
What's the failing test case look like?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be:
import * as ngCore from '@angular/core';
@ngCore.Component({
templateUrl: `..`
})
export class Something {}
https://github.com/dherges/ng-packagr/blob/master/src/lib/ts/ng-ts-ast.spec.ts#L64-L66
return false; | ||
} | ||
|
||
const name = (declaration.propertyName || declaration.name).text; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 I think this accounts for named imports – import { Component } from '@angular/core'
– and aliased imports – import { Component as Foo } from '@angular/core'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I should add tests for those cases though - I borrowed some of this code from you but dropped all the conditional logic I wasn't testing
For users: the transformer's calls to |
Wasn't inlining already possible with the *ngfactory files? What's the difference with this PR? |
@alippai other tools were doing inlining on the resulting JS outputs of the Angular compiler before. Now we make this a first-party feature. (Under Bazel, we never plan to do the workaround of modifying JS outputs) Also it means source-maps should be more correct. |
@alexeagle awesome, thanks! |
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
When angularCompilerOptions { enableResourceInlining: true }, we replace all templateUrl / styleUrls properties in
@Component
with template / styles