-
Notifications
You must be signed in to change notification settings - Fork 25.1k
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
RFC: Exploration of use-cases for Angular JIT compilation mode #43133
Comments
|
I’ve never seen any use case for JIT in any app I worked on over the last 5 years. Always —aot. |
|
TBH, I don't know for sure if that involves JIT mode or not, but I suspect it might. What I'm sure is that it's a common practice, so you've probably thought about it already. But many of my unit tests consist in having test host components that are only ever declared in the testing module: @Component({
template: '<component-under-test ...></component-under-test>'
})
class TestComponent {
...
}
describe('some test', () => {
beforeEach(() => {
configureTestingModule({
declarations: [ComponentUnderTest, TestComponent]
}
});
...
}Some times, the template of the test component is dynamic, i.e. it's overridden in each of the tests to test various combinations of inputs and outputs. That's why I guess it uses the JIT. If such a feature wasn't supported anymore, it would imply a huge amount of re-design and rewrite of the tests. |
|
I would say, get rid of it as soon as the view composition APIs is in a stable state, as that would fulfill all of the use-cases JIT is now used for. When this, and the related RFC's do speed things up enough, the custom builds using JIT will become unneeded anyway |
|
@jnizet great point! Thank you. You are right that the testing components today rely on JIT. Usually not because they are dynamic but because you need the flexibility to declare them inline, usually within functions of a test file as your example shows. With the right compiler and API modifications we should be able to support this with AOT (thanks to Ivy). This change could be rolled out with an automated migration so nobody has to rewrite their tests. But as you bring up, this flexibility of testing components means that you could dynamically create a template or modify the component metadata (e.g. use string concat and interpolation to create a unique template for a bunch of components created within a loop that wraps an This is not the most common pattern but I'd be shocked if some codebases didn't rely on it. I currently don't have a solution for this one. Maybe the composition api could be it, but automated migration from unconstrained TS/JS code that generates a component to a component built using the composition API would be tricky and not 100% reliable. I do appreciate bringing this up though. This is exactly the kind of feedback we are looking for. |
|
We use JIT mainly for unit testing only, especially with Jest. Currently, we follow slightly similar setup how Angular CLI did is that:
If removing Regarding to code emitting, IIRC AOT compiler uses some extra AST transformers besides the above 2 which I think will be the most work for us to replicate the same behavior for Jest. We would love to use AOT compiler for Jest but will need to spend some time first to experiment. Ofc using everything from Angular is the best way. My concern only is how open the AOT compiler APIs will be so that we can reuse them. |
|
Storybook users write story files like this one export default {
title: 'Welcome/ To Angular',
} as Meta;
export const toAngular: Story = () => ({
component: AppComponent,
props: {
showApp: linkTo('Button'),
},
});A story contains metadata to generate the actual NgModule and render the component or template during runtime. This information is not available during compile-time and therefore is not compatible with AoT, right? Actually, the story is. But not the generated NgModule and Component. Here's one example of what Storybook does with the provided metadata information of a story export const createStorybookModule = (ngModule: NgModule): Type<unknown> => {
@NgModule(ngModule)
class StorybookModule {}
return StorybookModule;
};I talked about this with Alan, Minko and Alex during the Storybook Ivy integration and I remember one of them said: "Maybe, it is possible to partly make Storybook AoT compatible as a second step" but we didn't talk about this any further. |
|
We care about Jest tests (for faster dev cycles) and a home-grown app for demoing components using templates that are compiled at runtime. Most developers will probably use Storybook, but we use something similar to this to host angular examples within an angular app: https://github.com/johncrim/angular-dynamic-styleguide Here's the part that compiles templates: The general problem description is: "How do we render angular component code alongside working examples of that code?" I'm sure that if the problem is solved well for aio and storybook we can use the same approach. We'd be happy to migrate to a new way to accomplish the same thing once it's available. |
|
@ahnpnl, @kroeder, and @johncrim this is exactly the kind of feedback we are looking for! Thank you for sharing the links and examples. My first impression is that Jest, Storybook, and example use case would be fully supported using a combination of the proposed view composition APIs (primarily for the demo use cases) and whatever solution we implement to AOT compile testing components within unit tests (for jest and storybook). Do you see any obvious holes in these solutions? (I apologies for the lack of clarity around the solution for unit tests, I'll see if I can write something up in the next few days to make it less ambiguous) |
|
We are still using JiT mode for local development for our large app (~1300 components), as AoT is still noticeably slower for incremental rebuilds. v12 and webpack's in memory caching helped a lot to make this better as previously a single line change in a component would take more than a minute to rebuild, now after a few rebuilds it goes down to about 14s, although it's still double the speed of JiT mode on the same file (apx 7s). The first few changes to the file are always a lot slower as well (1st: ~79s, 2nd: ~28s, 3rd: ~14s). We'd be happy to arrange access to the repo for an angular team member to do some profiling to see if it's possible to get it down to match the speed of JiT mode 😄 |
|
@mattlewis92 I'm always interested in real-life repos to do perf tests with, as they often show new insights in ways to optimize builds. The first rebuild is indeed slower because incremental type checking of TS sources is ineffective in the first rebuild. This is a known limitation because of how template type checking is achieved. I'd be interested to learn where the 7s deficit from JIT mode comes from. |
|
My team use JIT in spite of themselves: to quick fix never understood OOM & build/rebuild speed. use case : +150 lazyroutes +1000 components Thanks to @JoostK &co a lot of work is done in practically each major release to “get closer” to JIT rebuild time. 🙏 |
|
@IgorMinar - thank you for soliciting community feedback! Regarding your statement here:
Thinking about our style-guide app (public starter version here: https://github.com/johncrim/angular-dynamic-styleguide ), my first thought is "oh boy, then we'll have to maintain separate text for the template source code for developers to use, and view composition code that is functionally equivalent to that source code, for each of our examples". Which doesn't seem tenable - if we had to do without runtime compilation from text templates, I'd probably try to come up with a way to compile each of the examples during a custom compilation process, so that we could pull the source code text and the working example into the style-guide app. It seems pretty difficult right now to come up with a compile-time implementation for this. Though I haven't dug into what aio does (it looks like the code and screenshots are generated), or what Storybook does, a couple years ago I concluded that using the runtime compiler was the easiest way to solve this. Another possibility is: Could there be a way to compile string templates into view composition code, as part of a custom compilation process? For this use-case, there's no reason that the compilation has to be done at runtime - all that's needed is a way to compile example templates, and correlate that template text with a loadable component. The number of developers that care about this case is probably far fewer than the testing use cases, though functionally there may be a lot of overlap. Maybe this is a 3rd party library built on top of Angular APIs. Speaking only for myself, I'm up for recreating this functionality within new constraints, in the interest of reducing Angular surface area. Another use case to consider:
|
@johncrim maybe, there might be some advanced features in the template syntax that we might initially keep out of the view composition API to focus on what matters the most and delivering this in a reasonable timeline, but I could see how over time, the API could match the full expressiveness of declarative templates. |
|
@mattlewis92 and @elvisbegovic please check out #43131 which has some ideas about how to make the builds significantly faster. |
|
@mattlewis92 and @elvisbegovic, I've also just posted #43165 that proposes changes to make the compilation significantly faster. |
|
We have a use case where our app uses a dynamic form(dynamic component HTML + Typescript + CSS) created by end-users and loads it in specific sections in our app. If angular remove the JIT compiler then we will be screwed :( |
|
@sheshnathverma can you please help us understand why wouldn't the proposed view composition API work for you to replace the JIT compiler? |
@IgorMinar thanks for replying to my concern. ` @component({ Now if the proposed view composition api can handle this scenario then we will be safe. let me also highlight we offer them our inbuild control as well (ex. app-text, app-number etc.). |
|
@sheshnathverma It's logical that the proposal won't include your current way of processing. Probably #43133 (comment) promises a future way how to do it. But it means storing not the plain HTML code but the view composition code (taking the plain HTML and pre-compile it before storing it into a database). |
|
@sheshnathverma - Given that you actually control the content for these dynamic templates (even though they can be defined by a user), another solution would be to AOT compile the HTML template strings stored in the database on the server into a JS module that you can load dynamically into an Angular app. The compiled output could be cached at the server to avoid undue compilation cost. This would also speed up and reduce resource usage on the users browser. |
|
When I upgraded to Angular 12 and AOT became the default, I found it impossible to develop code the way I was use to. With JIT, I would make a change in my IDE, hit save, and see the change instantly in my browser pointing to localhost:4200. With AOT, it was 10 seconds before the browser refreshed. The most obvious example of this type of programming would be getting CSS exactly right. You make a change then see how it is displayed, then adjust it a little more, save and see it again. If it takes many seconds between save and refreshing the page then I'm not working as fast as I could. I do this type of iterative development with everything, templates, methods, rest endpoints, etc. |
|
We have an internal docs site for our design system which has live editable versions of our components. We compile the TS in the browser and then restart the Angular app that's rendered inside of a containing div, running inside of a Gatsby site. This is similar to how Stackblitz worked in the past (or at least based on my naive assumption.) While we don't specifically use the The proposed view composition api would most likely work for us although would require a bit of retooling and tinkering to make it work, depending on what the exposed api would end up being. Otherwise we'd need to either go with a static implementation and remove the live-editable feature, or pay for an enterprise version of Stackblitz or something. I'm all for cleaning up Angular and trimming down the needed code, but it does present some challenges for us in the future. I mostly wanted to inform you of one of the use cases for JIT mode. |
|
@mdunhem and @vinayk406 while I believe that the proposed composition API would work for your use-cases, wonder if running the AOT compiler within a service worker would be a better fit for you. It's something we discussed on and off. This is not the simplest approach but it wouldn't be too crazy either. |
|
@LayZeeDK thanks for the collection of links and pointing out a great example of an inconsistency between JIT and AOT. For AOT to work the code does need to be statically analyzable, and we go to great lengths to statically evaluate the expressions to provide better DX, but that has limits. These limits are usually not visible to developers though and we don't currently consider them to be something that needs addressing. Are you suggesting otherwise or is the goal of your comment just to illustrate how JIT and AOT differ? |
|
@perjerz thanks for sharing your use-cases. I believe that would be supported by the composition API. To make it more ergonomic, it would be interesting to discuss a possibility of creating a higher level API which would accept data in JSON (or similar format) and produce the view using the composition API. That way, you'd only need to get your CMS to produce the JSON instead of html to be able to use this API. An alternative would be something like along the lines of |
|
My comment doesn't have a point other than pointing out that most kinks have been ironed out by the Angular team over the course of time which is great to see. JIT -> AOT was not an easy transition in early versions of Angular. Based on the remaining caveats listed, I don't have a specific use case in mind although I'm a bit surprised by the synchronous assignment examples. You list the obvious use cases in the original post, for example dynamic generation of declarables at runtime. How about testing? Which limitations would be put on automated tests if JIT was removed entirely? |
|
@LayZeeDK Any code that dynamically builds up templates of testing components would be affected, but that's about it. I've seen a handful of instances of this pattern at Google and all those cases could use the composition API instead. |
Thanks for the response. I might tinker with that, especially considering we're already running the TypeScript compiler in the browser. Switching it to use |
|
Our use case is a back office application built using module federation approach. |
ng-packagr/ng-packagr#2050 might be interesting for your current approach cheers |
@flash-me |
|
#43133 (comment) I agree with this opinion, and just like Storybook, Testing Library's API for writing templates in string format and dynamically generating test host components is important for the developer experience. await render(`<my-button></my-button>`, {
imports: [MyButtonModule],
});The Testing Library is just one example, but in this interest, I hope that directive testing by test hosts will remain the same experience as before. |
|
@johncrim, you mentioned compiling string templates as a part of custom compilation step:
This is exactly what already quoted tshtml does. You basically export a string from TS file, the file is executed at build time and it's output is treated as usual static HTML template. |
|
At our company, we are using (and are reliant on) JIT to generate and utilise generated mock services/components/directives in tests. I think there is a use case for JIT in test code. |
|
Spectactular's pipe testing API allows the user to decide the template of the (internal) host component for integration testing an Angular pipe. How would we solve this using the imperative view composition API or otherwise, without JIT in tests? import {
createPipeHarness,
SpectacularPipeHarness,
} from '@ngworker/spectacular';
import { PowPipe } from './pow.pipe';
describe(PowPipe.name, () => {
beforeEach(() => {
harness = createPipeHarness({
pipe: PowPipe,
// template: '{{ value | pow }}' // 👈 Default host component template
value: 2,
});
});
let harness: SpectacularPipeHarness;
it('raises the base to the specified power', () => {
harness.value = 5;
harness.template = '{{ value | pow:3 }}'; // 👈 Resets the Angular testing module and overrides the host component template
expect(harness.text).toBe('125');
});
}); |
|
I am using the JIT compiler to build up text document fragments. We allow our staff to define templates (HTML) and bind them to a model via JIT and Its really powerful as we can just point them to some angular basics, build some custom pipes for the tricky stuff, and let them at it. |
|
@lacolaco I agree with you that for testing use cases, using strings as inputs is important. I think we can support this by translating/transpiling strings with templates being tested to the view composition API calls. From the DX perspective it works in the same way, but under the hood it won't require JIT compiler, which would be a huge win for all of us. |
|
@matthewjh could you please share some examples that capture various usage patterns? I'd love to know more to determine if these patterns are already captured in the use-cases we discussed above or if they are unique. thanks |
|
I really appreciate all the feedback we've received from all of you. This RFC was supposed to close this week, but I like the conversation and I'd like to finish some of the unresolved questions around testing use-cases, and CMS-like use-cases. From what I've seen in the feedback so far, I think we can have a solid story for all the concerns raised even without JIT compiler, as long as we implement some of the proposed features to fill in the current gaps in AOT capabilities and DX. If you have more details you'd like to share with us, please do so by next Wednesday, September 8. Thank you! 🙇🏻 🖖🏻 |
Yes, this also ties into the Spectacular use case. Having that string template to imperative view composition feature to optionally add would be great. API bundle size doesn't matter as much for testing so it's the perfect companion to keep supporting the rich ecosystem of Angular testing libraries. Maybe it could even be a choice for bundling at runtime for dynamic scripting-like use cases if bundle size is less of a concern, similar to bundling the JIT compiler today for dynamic runtime composition. |
Let's say we are testing a component A that utilises another component or directive B from our codebase (I'll just say "directive" from here onwards). This directive may reside in the app itself or in a library in our monorepo. In the test for A, we will configure the testing module with So in a nutshell, we would need to be able to:
|
|
Sorry @IgorMinar, I'm late on the discussion. As already described to @mgechev we have a quite big application where we compose on runtime routing and loading dynamically modules using systemjs (quite old application), of course, based on JIT Compiler. Just a short question related to Ivy and AOT: will it be possible to compile single modules (angular library) with ivy Using that approach we will be free to remove jit compiler on our project. |
|
@meriturva This is already possible. UPDATE: |
When can we expect the conclusion of the Angular Team? Any timeline? |
|
Hey everyone, thanks for participating in this RFC. I'm finally wrapping up this one now that the RFC for standalone components, directives, and pipes is out. Several of the sub-rfc of this RFC referred to the "standalone" design, so I'm glad that all of the information is out there and up for discussion. The key takeaways from this RFC for me are:
Overall, my take on this RFC is that JIT is not going to disappear any time soon, but if we fill in all the gaps, it could disappear in the future. Thank you all for participating in the discussion. |
|
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. |
Note: 📺 Check out the video recording of a community discussion about this RFC @ angularnation.net
Summary
The Angular team would like to understand the remaining use-cases for Angular's JIT compilation mode, and discover any gaps that prevent adoption of the AOT compilation mode for these use-cases.
We'd like you, the community, to share with us how and why you still use JIT mode, and what prevents you from using AOT.
Background information
When Angular launched as v2.0 back in 2016, the template compiler supported two distinct compilation modes: JIT (just in time) and AOT (ahead of time) compilation.
While initially JIT was readily available and the primary mode for both development and production build workflows, our intention has always been to primarily focus on AOT mode which was harder to implement, but offered more opportunities to improve the development experience (e.g. type checking, autocompletion, automated refactoring, and faster development server and unit testing incremental iteration cycle), as well as user experience (faster and smaller apps, thanks to significantly better runtime and payload size optimizations).
Over the last many releases we overhauled the AOT compiler and kept on improving it. As of Angular v9 the AOT compilation mode is the default for all development and production workflows for all CLI application and library workflows (it's been the default at Google for much longer than that). There are only a few remaining cases where JIT compilation is still used:
The use of the JIT compiler for these use-cases suffers from a lack of type checking, as well as performance and security issues that are a side-effect of compiling code at runtime in the browser (and in the JavaScript context shared with the production application).
The security implications are serious enough that our Information Security Engineering team at Google has early-on disallowed the use of Angular's JIT compiler in production environments at Google.
As of v13, the legacy View Engine compilation pipeline will no longer be part of Angular's stack (more info and also here), which significantly simplifies Angular, especially for library authors, which have had to ensure compatibility of their libraries with both View Engine and Ivy during the transition.
It is our goal to keep making Angular simpler and streamline internal complexity that affects Angular application developers and library authors in direct and indirect ways, and as part of this effort we'd like to evaluate if keeping JIT compilation mode around is still providing Angular developers with value that justifies the increase in complexity, security risks, and maintenance cost for everyone, including Angular application developers, library developers, as well as the Angular team.
There are many benefits to standardizing on AOT compilation mode, the main ones include:
consistency and predictability — JIT and AOT modes behave identically once all the templates & metadata are collected, and all the JavaScript references (module imports, class references, etc) are resolved. However, the collection of templates & metadata, and resolution of JavaScript symbols is significantly different between AOT and JIT, and requires special considerations in the application and library code (inconsistent behavior of what can and cannot be declared with Angular's decorators), in the library packaging format (the npm packages must support both JIT and AOT compilation), and also in the Angular compiler and runtime, which needs to accomodate the needs and quirks of both JIT and AOT.
fewer runtime performance and security pitfalls, and fewer confusing APIs for developers — for example the @angular/platform-browser-dynamic package and the Compiler APIs could be removed.
addition of view composition APIs to support commonly requested use-cases that are currently handled via JIT compilation — for example dynamic view composition (e.g. new core APIs for dynamically assembling and composing views out of directives, and components at runtime to support data-driven form, and other UIs).
focus on further build time improvements for AOT — for example by out-of-band type-checking for TypeScript and Template compilation, and transition to parallelizable localized compilation.
Community feedback
We'd like the community to share with us how and why you still use JIT mode, and what prevents you from using AOT.
We are specifically interested to know if there are use-cases that we are not familiar with (not listed in this RFC)?
Additionally, we'd also like to hear if you face organizational or technical restrictions that require you to use the JIT compilation mode?
The information provided by the community will help us understand what gaps we need to fill, and if it is feasible to deprecate and remove the JIT mode some time in the future once all the significant gaps are filled.
This RFC will close on Sep 8, 2021. Thank you for participating!
The text was updated successfully, but these errors were encountered: