Skip to content

updating webpack config for differential loading #14015

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

Closed
wants to merge 1 commit into from
Closed

updating webpack config for differential loading #14015

wants to merge 1 commit into from

Conversation

manfredsteyer
Copy link
Contributor

No description provided.

Copy link
Contributor

@alexeagle alexeagle left a comment

Choose a reason for hiding this comment

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

the commit description is not nearly descriptive enough. "tweak" could be anything. Please explain the difference in behavior (and also probably state how this is used or not used yet)

see AlexR's preso to the team about commit messages from a couple months back

* found in the LICENSE file at https://angular.io/license
*/

type WebpackConfig = any; // tslint:disable-line
Copy link
Contributor

Choose a reason for hiding this comment

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

why? either give a local type that matches the shape, or import a correct type, or explain in the //tslint comment why you can't

type WebpackConfig = any; // tslint:disable-line
type WebpackPlugin = any; // tslint:disable-line

export function updateWebpackConfig(config: WebpackConfig): WebpackConfig {
Copy link
Contributor

Choose a reason for hiding this comment

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

"update" is not descriptive. could you find a name that says what is the update?

createSubConfigs or something? (what does webpack call it when configs are nested in this way?)


const tweakPolyfills = (file: string) => {

// TODO: Do we need an own polyfill file for modern browsers? If yes, where is it created?
Copy link
Contributor

Choose a reason for hiding this comment

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

when do we plan to fix the TODO? can we figure it out in this PR?

Copy link
Contributor Author

@manfredsteyer manfredsteyer Mar 29, 2019

Choose a reason for hiding this comment

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

Question for reviewers: Do we need an own polyfill file for modern browsers? If yes, where is it created? (e. g. by a schematic or by this logic on the fly?)

*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
Copy link
Contributor

Choose a reason for hiding this comment

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

needs some file-level commenting explaining what's going on, in case the reader hasn't seen the design doc. linking to the design might also be nice

return modernStatsPlugin;
}

function buildLegacyAcp(acp: WebpackPlugin): object {
Copy link
Contributor

Choose a reason for hiding this comment

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

Acp is that intentional spelling?

const options = acp._options;
const modernOptions = { ...options };

// TODO: Where shall we create this tsconfig with target=es5?
Copy link
Contributor

Choose a reason for hiding this comment

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

will we address the TODO in this PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Question for reviewers: Where shall we create this tsconfig with target=es5? Schematics? On the fly if it does not exist?

@alexeagle alexeagle requested a review from alan-agius4 March 29, 2019 17:16
@filipesilva filipesilva requested a review from clydin March 29, 2019 19:47
…erential loading

This updates a webpack configuration which has been created by a webpack-based builder for differential loading. For this, it duplicates the existing configuration and modifies e. g. the name of the bundles to generate (` [name].modern.js` instead of `[name].js`), the resolve array, and the Angular Compiler Plugin’s reference to the tsconfig.json.

Because of this strategy, just one webpack config needs to be maintained per builder. The other one is retrieved from it by this logic. This is esp. important if the CLI supports several bundles in future, e. g. ES5, ES2015, ES2016, ES2017, etc.
This PR is currently not used but it is the foundation for further ones.

Also see: https://docs.google.com/document/d/13k84oGwrEjwPyAiAjUgaaM7YHJrzYXz7Cbt6CwRp9N4/edit?ts=5c652052#heading=h.gijrsdjw51q5
@manfredsteyer manfredsteyer changed the title tweak webpack config for differential loading updating webpack config for differential loading Mar 30, 2019
Copy link
Collaborator

@alan-agius4 alan-agius4 left a comment

Choose a reason for hiding this comment

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

See above.

const workspaceRoot = path.join(
devkitRoot,
'tests/angular_devkit/build_angular/test-differential-loading/');

Copy link
Collaborator

Choose a reason for hiding this comment

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

Try to avoid using the files from the file system directly, to test ideally always use the abstracted fs, as it would be easier to update a property in a file, write another file etc.. during a specs.

See here for an example: https://github.com/angular/angular-cli/blob/master/packages/angular_devkit/build_webpack/src/webpack-dev-server/index_spec_large.ts

Copy link
Collaborator

Choose a reason for hiding this comment

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


modernOptions.tsConfigPath = tsConfigPath;

const legacyAcp = new AngularCompilerPlugin(modernOptions);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Has this been tested? Afaik this plugin doesn’t support multicompiler or we won’t use multi webpack compiler at all and use two separate webpack instances?

In addition a single build can have multiple AngularCompilerPlugin when using Web Workers, which is not being handled here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. It works if we adopt some methods a bit.

Copy link
Collaborator

@alan-agius4 alan-agius4 Apr 1, 2019

Choose a reason for hiding this comment

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

Just to confirm are you going to go for webpack multicompiler?

Also can you elaborate what you mean by adopt some methods a bit?

Copy link
Collaborator

Choose a reason for hiding this comment

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

At the moment @angular-devkit/build-webpack doesn’t have implementations for multi-compiler.

// TODO: Where shall we create this tsconfig with target=es5?
// Schematics? On the fly if it does not exist?

let tsConfigPath = modernOptions.tsConfigPath;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think creating an extra config, might complicate things a bit especially considering the web workers, which need a separate tsconfig, meaning that each 'build' will have multiple config files. See: #13700

Not sure if it best to change the file script target on the fly.

//cc @filipesilva what do you think?

Also this would increase maintain in tsconfig files for users.

So, if users have workers and a differential severing they end up with 4 tsconfig for their application which users would need to keep in sync if they do a change.

  1. tsconfig for the app es5
  2. tsconfig for the app es2015
  3. tsconfig for the worker es5
  4. tsconfig for the worker es2015

Copy link
Contributor Author

Choose a reason for hiding this comment

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

TBH, I don't like it either. However, I see no alternative for this. Or is it possible to pass an object literal representing the contents of a tsconfig.json to the AngularCompilerPlugin? I guess, in this case the AngularCompilerPlugin also needs to write it to hard disk.

Copy link
Collaborator

@alan-agius4 alan-agius4 Apr 1, 2019

Choose a reason for hiding this comment

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

You can pass the compiler options to the AngularCompilerPlugin.

export interface AngularCompilerPluginOptions {

Why should the angular compiler plugin write the file to disk?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, that means I could read the tsconfig.json into an object, modify it's target in memory and assign it to the compilerOptions property, right? In this case we don't need a seperate tsconfig.json for this target on disk. Do I see this right?


// TODO: Do we need an own polyfill file for modern browsers? If yes, where is it created?

if (file.endsWith('polyfills.ts')) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This doesn’t seem right, polyfills file can be named anything. It can be foo.ts.

https://angular.io/cli/build

Also, I believe polyfills for modern and legacy will be internal which @clydin is working on something for zone.js

const StatsPlugin = require('stats-webpack-plugin');


export function createWebpackMultiConfig(config: webpack.Configuration): webpack.Configuration[] {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I am not quite understanding how this fits in the builder. You need a webpack config here and you transform it afterwards.

Why not use the existing methods to generate two separate config files and avoid post transformations?

Example:

 const webpackConfigs = (wco) => [
    getCommonConfig(wco),
    getBrowserConfig(wco),
    getStylesConfig(wco),
    getStatsConfig(wco),
 ];

const [legacyConfig, modernConfig] = [
   generateBrowserWebpackConfigFromContext(
      legacyBrowserOptions,
      context,
      wco => webpackConfigs(wco),
      host,
   ),
   generateBrowserWebpackConfigFromContext(
      moderBrowserOptions,
      context,
      wco => webpackConfigs(wco),
      host,
   ),
];

Then, based on the type of build type change the file output paths and script target, This is something similar to how the serve builder generates it's webpack config. You can also use the new transformations hooks, if you need to do post transformation. Something like https://github.com/angular/angular-cli/blob/master/packages/angular_devkit/build_angular/src/dev-server/index.ts#L123 //@clydin knows more about this feature.

There are some helper methods for webpack here: https://github.com/angular/angular-cli/blob/master/packages/angular_devkit/build_angular/src/utils/webpack-browser-config.ts

However, I am still not sure how everything will be glued together seeing this logic. As based on the design doc I was under the impression that the browser builder will implement the differential serving logic and the differential-builder responsibility was more to orchestrate to the different browser builders.

If the browser builder will be responsible for both builds, should this code

switchMap(() => from(buildBrowserWebpackConfigFromContext(options, context, host))),
switchMap(({ workspace, config }) => {
if (configFn) {
return configFn(workspace, config).pipe(
map(config => ({ workspace, config })),
);
} else {
return of({ workspace, config });
}
}),
switchMap(({workspace, config}) => {
need to change and run buildBrowserWebpackConfigFromContext run twice?

return modernPlugins;
}

function buildModernStatsPlugin(): webpack.Plugin {
Copy link
Collaborator

@alan-agius4 alan-agius4 Apr 1, 2019

Choose a reason for hiding this comment

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

What about the other profile plugins such as the chrome-profiler and speed-measure and also the license plugin https://github.com/angular/angular-cli/blob/master/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/browser.ts#L64?

@@ -0,0 +1,185 @@
/**
Copy link
Collaborator

@alan-agius4 alan-agius4 Apr 1, 2019

Choose a reason for hiding this comment

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

inline comments near the implementations would definitely help the reviewers and future engineers that go through the code as they wouldn't need to jump from an implementation to another to understand why something is needed.

return modernEntry;
}

function buildLegacyPlugins(config: webpack.Configuration): webpack.Plugin[] | undefined {
Copy link
Collaborator

@alan-agius4 alan-agius4 Apr 1, 2019

Choose a reason for hiding this comment

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

Why not generate a webpack config which is already property configured for an es2015 or es5 build? Rather than having to go through certain plugins and re-create them, with a risk of skipping one and increasing maintenance, if the original webpack configurations are changed.

resolve: buildLegacyResolve(config),
};

const modernConfig: webpack.Configuration = {
Copy link
Collaborator

@alan-agius4 alan-agius4 Apr 1, 2019

Choose a reason for hiding this comment

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

With this approach you are missing some configuration for es2015 https://github.com/angular/angular-cli/blob/master/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts#L236 and https://github.com/angular/angular-cli/blob/master/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts#L216

Hence, I strongly recommend that we avoid doing such transformations and let the webpack config builder return the appropriate configs as this is quite brittle

@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 Sep 13, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants