Skip to content

[@ngtools/webpack] Decoration of compiler.inputFileSystem breaks its API #10064

Closed

Description

@DorianGrey

I've recently attempted to update one of my projects to webpack v4, in addition to a couple of other updates. One of them broke my build with a curious error:

TypeError: readFileFn is not a function

After debugging things a bit, I figured out that one of the plugins I'm using attempts to access compiler.inputFileSystem._readFile, which is present in the apply phase, but was no longer existing when it came to emit.
Playing a bit with the configuration, I was able to point out that this modification was made by the AngularCompilerPlugin, which is part of @ngtools/webpack. More precisely, it happens due to the decoration performed by it:

compiler.hooks.environment.tap('angular-compiler', () => {
compiler.inputFileSystem = new VirtualFileSystemDecorator(
compiler.inputFileSystem, this._compilerHost);
compiler.watchFileSystem = new VirtualWatchFileSystemDecorator(compiler.inputFileSystem);
});

After this, compiler.inputFileSystem._readFile is no longer available. Thus, the decoration breaks the API available on compiler.inputFIleSystem and makes plugins relying on it fail.

Versions

  • No ng version, since it's a custom setup
  • Node 8.10.0
  • NPM 5.7.1
  • Yarn 1.5.1
  • @ngtools/webpack 1.10.2
  • Ubuntu 16.04

Repro steps

Observed behavior

The last command will fail with an error like this.

TypeError: readFileFn is not a function

(See the build output here: https://travis-ci.org/DorianGrey/ng-webpack-template/jobs/357274315)

Desired behavior

Decoration or encapsulation of any of these internal parts of webpack should not break their available API, regardless of potentially intended privacy (suppose the leading _ might tend in this direction).

Mention any other details that might be useful (optional)

I've also tried the latest beta version of the @ngtools/webpack plugin and made a cross-check against webpack v3, but neither made any difference.
Not sure if this is of any help or use, but the affected plugin in my case is the workbox-webpack-plugin, which changed it's implementation and behavior in v3.

https://github.com/GoogleChrome/workbox/blob/fa4d8b7dab2b0680c15d6057c12fd9ec9f0932c4/packages/workbox-webpack-plugin/src/inject-manifest.js#L150-L154

Suppose that's why this problem did not raise before.

Activity

  1. filipesilva commented on Mar 26, 2018

    @filipesilva
    Contributor

    I believe the _readFile method in the native Webpack inputFileSystem is a private-ish method. I say private-ish because JS doesn't really have private methods but it is common practice to prefix methods with _ to mark them as private.

    With this in mind, there is no guarantee that it should exist in the inputFileSystem because it might have been decorated (as is the case here).

    Decorating inputFileSystem is the recommended approach to intercept FS calls, according to the Webpack author (webpack/enhanced-resolve#98 (comment)). We've been through this in the past with ngtools/webpack because we weren't decorating it properly (#7169 and #7471).

    I think workbox-webpack-plugin needs to also decorate the file system like we did to ensure compatibility between plugins.

  2. hansl commented on Mar 26, 2018

    @hansl
    Contributor

    Like @filipesilva said, _readFile is private. You should use readFile, which we do provide and is the proper public method to use.

  3. DorianGrey commented on Mar 27, 2018

    @DorianGrey
    Author

    I'm not sure if using another decoration here makes sense or is useful - it would end up with a decoration of an already decorated inputFileSystem, given that compiler.inputFileSystem is simply replaced. Since the decoration does not have an enforced API, other instances attempting to decorate it might end up non-functional due to making assumptions about inputFileSystem that only hold true on the original version, not the decorated one - or vice versa.

    However, I agree that relying on a private method isn't the best idea, and will open a corresponding issue on the workbox repository, and see if there is a better solution - esp. since the plugin only utilizes this method for reading a single file.

  4. clydin commented on Mar 27, 2018

    @clydin
    Member

    It's also important to note that the webpack filesystem abstractions are intended to be extendable and/or re-implementable. Webpack provides NodeJS versions which are used by default. These specifically have the following:

    stat
    statSync
    readdir
    readdirSync
    readFile
    readFileSync
    readlink
    readlinkSync
    

    The plugin in question here appears to be assuming that webpack is using, and providing via inputFileSystem, the CachedInputFileSystem; which is not guaranteed.

  5. DorianGrey commented on May 2, 2018

    @DorianGrey
    Author

    Suppose I can close this - the corresponding issue on the other repo has been closed due to a fix being merged recently.

  6. angular-automatic-lock-bot commented on Sep 8, 2019

    @angular-automatic-lock-bot

    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.

  7. locked and limited conversation to collaborators on Sep 8, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions