Skip to content
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

Ivy-only Webpack Compiler Plugin #17717

Closed
wants to merge 5 commits into from

Conversation

clydin
Copy link
Member

@clydin clydin commented May 13, 2020

This change introduces a new Ivy-only Webpack compiler plugin. The plugin is based on and leverages the Ivy ngtsc APIs from within the @angular/compiler-cli package. The plugin also simplifies and reduces the amount of code within the plugin by leveraging newer TypeScript features and capabilities. The need for the virtual filesystem has also been removed. The file replacements capability was the primary driver for the previous need for the virtual filesystem. File replacements are now implemented using a two-pronged approach. The first, for TypeScript, is to hook TypeScript module resolution and adjust the resolved modules based on the configured file replacements. This is similar in behavior to TypeScript path mapping. The second, for Webpack, is the use of the NormalModuleReplacementPlugin to facilitate bundling of the configured file replacements. An advantage to this approach is that the build system (both TypeScript and Webpack) are now aware of the replacements and can operate without augmenting multiple aspects of system as was needed previously.

The plugin also introduces the use of TypeScript’s builder programs. The current primary benefit is more accurate and simplified dependency discovery. Further, they also provide for the introduction of incremental build support and incremental type checking.

NOTE: The deprecated string format for lazy routes is not supported by this plugin. Dynamic imports are recommended for use with Ivy and are required when using the new plugin.

Performance and memory usage have also been improved with these changes. Initial benchmarking indicates an average ~10% reduction in production build time and a similar ~10% reduction in peak memory usage. Watch mode (including the development server) no longer requires the forked type checker which provides a ~30% improvement in memory usage for typical development scenarios. The plugin is also not yet fully optimized. The next phase of development will introduce performance tracing and support further improvements.

@clydin clydin force-pushed the webpack-ngtsc-plugin branch 2 times, most recently from 3e07920 to 29db8d1 Compare May 19, 2020 00:52
@clydin clydin added the target: major This PR is targeted for the next major release label May 19, 2020
@clydin clydin marked this pull request as ready for review May 19, 2020 00:58
@clydin clydin force-pushed the webpack-ngtsc-plugin branch 2 times, most recently from 3178e4f to 054af80 Compare May 21, 2020 00:39
@clydin clydin force-pushed the webpack-ngtsc-plugin branch 4 times, most recently from 09f9243 to a38b1f9 Compare May 29, 2020 00:47
@clydin clydin force-pushed the webpack-ngtsc-plugin branch 3 times, most recently from 91d71d4 to 4c4fc6a Compare June 4, 2020 01:27
@clydin clydin force-pushed the webpack-ngtsc-plugin branch 10 times, most recently from df0024d to 25714a6 Compare June 15, 2020 13:19
@clydin clydin force-pushed the webpack-ngtsc-plugin branch 3 times, most recently from e31511d to e04e781 Compare June 22, 2020 20:23
@clydin clydin force-pushed the webpack-ngtsc-plugin branch 2 times, most recently from c48f99a to 8667fd7 Compare July 9, 2020 21:54
@alan-agius4 alan-agius4 added action: merge The PR is ready for merge by the caretaker and removed action: merge The PR is ready for merge by the caretaker labels Sep 17, 2020
@clydin clydin force-pushed the webpack-ngtsc-plugin branch 2 times, most recently from b1db758 to bc6fde6 Compare September 24, 2020 19:46
@clydin clydin force-pushed the webpack-ngtsc-plugin branch 11 times, most recently from e348a46 to 0c78d5a Compare October 13, 2020 22:28
packages/ngtools/webpack/src/ivy/plugin.ts Outdated Show resolved Hide resolved
packages/ngtools/webpack/src/ivy/plugin.ts Outdated Show resolved Hide resolved

// Save for next rebuild
if (this.watchMode) {
this.ngtscNextProgram = ngtsc.getNextProgram();
Copy link
Member

Choose a reason for hiding this comment

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

Requesting the next program here might be premature, as requesting type check diagnostics (NgtscPlugin.getDiagnostics) will create a new ts.Program which provides a new next program to use for the next incremental build. I verified that calling NgtscPlugin.getNextProgram just before calling this.createFileEmitter in the promise handler does indeed return a different ts.Program.

Copy link
Member Author

Choose a reason for hiding this comment

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

This was originally later in the process. As an experimental with the release of TS 4.0, I moved it to its current location and it didn't appear to cause a change in behavior (no crashes, diagnostics appear to be the same, etc.). TS 4.0 removed an unnecessary assert statement that would previously cause an exception in this case (https://github.com/microsoft/TypeScript/blob/v3.9.2/src/compiler/program.ts#L1239).

Copy link
Member

Choose a reason for hiding this comment

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

Yeah I also didn't observe any difference in behavior. I was expecting it to crash due to that assertion, but if it's been removed then surely it does not. I'm not sure if this causes extra memory to be retained, and what the size of a reused ts.Program would be. Maybe @alxhub has some more insights here.

This change introduces a new Ivy-only Webpack plugin.  The plugin is based on the design introduced by `tsc_wrapped` within Bazel’s `rules_typescript` and leverages the newly added ngtsc plugin from within the `@angular/compiler-cli` package.  By leveraging the same plugin interface that it used by Bazel, a common interface can be used to access the Angular compiler.  This has benefits to both major build systems and dramatically reduces the necessary code infrastructure to integrate the Angular compiler.
The plugin also simplifies and reduces the amount of code within the plugin by leveraging newer TypeScript features and capabilities.  The need for the virtual filesystem has also been removed.  The file replacements capability was the primary driver for the previous need for the virtual filesystem.  File replacements are now implemented using a two-pronged approach.  The first, for TypeScript, is to hook TypeScript module resolution and adjust the resolved modules based on the configured file replacements.  This is similar in behavior to TypeScript path mapping.  The second, for Webpack, is the use of the `NormalModuleReplacementPlugin` to facilitate bundling of the configured file replacements.  An advantage to this approach is that the build system (both TypeScript and Webpack) are now aware of the replacements and can operate without augmenting multiple aspects of system as was needed previously.
The plugin also introduces the use of TypeScript’s builder programs.  The current primary benefit is more accurate and simplified dependency discovery.  Further, they also provide for the potential future introduction of incremental build support and incremental type checking.

NOTE: The deprecated string format for lazy routes is not supported by this plugin.  Dynamic imports are recommended for use with Ivy and are required when using the new plugin.
…at tests

The new Ivy-only Webpack plugin no longer supports the deprecate string format for lazy routes.
…ions

This change allows the compiler options used by the TypeScript paths plugin to be updated if the TypeScript configuration file is changed during a rebuild.
…feature flag

The new Ivy Webpack plugin is considered experimental and can only be used by enabling the `NG_BUILD_IVY_EXPERIMENTAL` environment variable.
Copy link
Member

@alxhub alxhub left a comment

Choose a reason for hiding this comment

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

NgTscPlugin is not yet a finished and stable API, and we're not ready to have Tooling -> FW dependencies on it.

@clydin clydin changed the title Ivy-only Webpack ngtsc Plugin Ivy-only Webpack Compiler Plugin Oct 18, 2020
@clydin clydin closed this Oct 20, 2020
@Rush
Copy link

Rush commented Nov 17, 2020

Is it available as a beta API though? Can I just replace AngularCompilerPlugin with NgTscPlugin?

@alxhub
Copy link
Member

alxhub commented Nov 17, 2020

Is it available as a beta API though? Can I just replace AngularCompilerPlugin with NgTscPlugin?

Plugin means two different things between these two classes.

AngularCompilerPlugin is a webpack plugin. NgTscPlugin is a plugin to tsc_wrapped from the Bazel build infrastructure. It might be wrappable in a webpack context (as ivy.AngularCompilerPlugin in this PR does), but that is left as an exercise for the reader currently.

@clydin clydin deleted the webpack-ngtsc-plugin branch December 7, 2020 18:34
@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 Jan 7, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
target: major This PR is targeted for the next major release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants