webpack / webpack

A bundler for javascript and friends. Packs many modules into a few bundled assets. Code Splitting allows for loading parts of the application on demand. Through "loaders", modules can be CommonJs, AMD, ES6 modules, CSS, Images, JSON, Coffeescript, LESS, ... and your custom stuff.
https://webpack.js.org
MIT License
64.65k stars 8.8k forks source link

Crash with `Error: Content and Map of this Source is not available (only size() is supported)` #14840

Closed andreialecu closed 2 years ago

andreialecu commented 2 years ago

Bug report

I'm running into Error: Content and Map of this Source is not available (only size() is supported) with Angular.

This seems to have been reported in various other places recently: https://stackoverflow.com/questions/70066980/angular-12-content-and-map-of-this-source-is-not-available-only-size-is-suppo

What is the current behavior?

.../node_modules/webpack-sources/lib/SizeOnlySource.js:16
                return new Error(
                       ^

Error: Content and Map of this Source is not available (only size() is supported)
    at SizeOnlySource._error (.../node_modules/webpack-sources/lib/SizeOnlySource.js:16:10)
    at SizeOnlySource.buffer (.../node_modules/webpack-sources/lib/SizeOnlySource.js:30:14)
    at _isSourceEqual (.../node_modules/webpack/lib/util/source.js:21:51)
    at isSourceEqual (.../node_modules/webpack/lib/util/source.js:43:17)
    at Compilation.emitAsset (.../node_modules/webpack/lib/Compilation.js:4155:9)
    at .../node_modules/webpack/lib/Compiler.js:546:28
    at .../node_modules/webpack/lib/Compiler.js:1127:17
    at eval (eval at create (.../node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:13:1)
The terminal process "zsh '-c', 'yarn run start'" terminated with exit code: 1.

If the current behavior is a bug, please provide the steps to reproduce.

I don't have a clear reproduction, however I was able to add some logs in emitAsset here, which is part of the stack trace: https://github.com/webpack/webpack/blob/14582fc41504595b04f01561ea19d27391d6b9ac/lib/Compilation.js#L4171-L4176

I added:

    emitAsset(file, source, assetInfo = {}) {
        if (this.assets[file]) {
            try {
                !isSourceEqual(this.assets[file], source);
            } catch (err) {
                console.error(file, this.assets[file], source);
                throw err;
            }

The output before the crash is:

fontawesome-webfont.eot SizeOnlySource { _size: 165742 } RawSource {
  _valueIsBuffer: true,
  _value: <Buffer 6e 87 02 00 ac 86 02 00 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 90 01 00 00 00 00 4c 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... 165692 more bytes>,
  _valueAsBuffer: <Buffer 6e 87 02 00 ac 86 02 00 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 90 01 00 00 00 00 4c 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... 165692 more bytes>,
  _valueAsString: undefined
}

It always seems to crash on the same eot file. Notice that this.assets[file] for this file is a SizeOnlySource.

What is the expected behavior?

No crash.

Other relevant information: webpack version: 5.60.0 Node.js version: 16.13.0 Operating System: MacOS 11.4 Additional tools: Angular 13.0.1

alexander-akait commented 2 years ago

Expected, something try to get content there is not content, replaced after writing by webpack, please wait the answer of angular team, we can't fix it on our side, sorry

andreialecu commented 2 years ago

Thanks, I opened https://github.com/angular/angular-cli/issues/22237 as well.

andreialecu commented 2 years ago

@alexander-akait after some discussion with an Angular team member in the issue mentioned above, it seems that they don't think this problem is on their side.

The stacktrace only mentions webpack from top to bottom, and I noticed that if I delete the webpack cache the problem goes away.

Would you mind taking a look at the discussion there? Thanks!

alexander-akait commented 2 years ago

@andreialecu Can you create reproducible test repo?

andreialecu commented 2 years ago

Unfortunately no, this is a huge project and it seems to be occurring very randomly as also noted in: https://github.com/angular/angular-cli/issues/22237#issuecomment-980102449 where simply re-cloning got rid of the error.

The key part is probably figuring out why SizeOnlySource is being compared to a RawSource and how it ends up in that state. I'm hoping there's an easy way to simply audit the code based on that information.

alexander-akait commented 2 years ago

I am afraid without more information, nobody can help with the problem, do you have enabled cache, can you try to disable, how often it happens? Is it watch/dev server/single build?

andreialecu commented 2 years ago

Currently it's not happening in my project any more.

But it clears up after removing the cache. It also clears up randomly after messing with package.json dependencies.

However it also randomly comes back. I've had this come and go several times over the last few days.

Once it starts happening again I'll archive the project so I have a reproduction.

alexander-akait commented 2 years ago

Thanks

sokra commented 2 years ago

This kind of error usually happens when trying to emit assets after the compiler has already written the assets to the output directory. (After writing webpack replaces the assets with SizeOnlySources, which drops the content for memory reasons)

From the stack trace it looks like a child compiler finishes very later and tries to emits its assets to the parent compiler.

So I think the problem is that somewhere a child compiler is started, but not correctly awaited for completion. That makes it timing dependent when the assets are emitted to the parent compiler, which could randomly cause this error.

andreialecu commented 2 years ago

@sokra from my observations I think your assumptions are correct.

When this was occurring, the process was as follows:

I'm not sure what the reason for the double compilation is. Might be something internal to Angular.

andreialecu commented 2 years ago

The screenshot I referred to is in this comment: https://github.com/angular/angular-cli/issues/22237#issuecomment-980074468

alexander-akait commented 2 years ago

Angular then automatically starts a second compilation which usually takes a second or so

I think this shouldn't be happening, do you have custom plugins?

alexander-akait commented 2 years ago

@andreialecu Anyway I strong recommend do not close https://github.com/angular/angular-cli/issues/22237, I'm almost sure that the problem is on their side, no one except angular users faced with it (this is a pretty clear hint)

sokra commented 2 years ago

From the angular issue it sounds a bit like that might be related to css build. A font file could be referenced by css child compiler and main compiler. Is angular using mini-css?

alan-agius4 commented 2 years ago

@sokra, yeah we are using mini-css.

alexander-akait commented 2 years ago

Will be great to see more items in stack trace...

andreialecu commented 2 years ago

@alexander-akait for some reason that's the entire stack trace (the part after ✔ Compiled successfully. is my own logging) :

✔ Compiled successfully.
fontawesome-webfont.eot SizeOnlySource { _size: 165742 } RawSource {
  _valueIsBuffer: true,
  _value: <Buffer 6e 87 02 00 ac 86 02 00 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 90 01 00 00 00 00 4c 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... 165692 more bytes>,
  _valueAsBuffer: <Buffer 6e 87 02 00 ac 86 02 00 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 90 01 00 00 00 00 4c 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... 165692 more bytes>,
  _valueAsString: undefined
}
.../node_modules/webpack-sources/lib/SizeOnlySource.js:16
                return new Error(
                       ^

Error: Content and Map of this Source is not available (only size() is supported)
    at SizeOnlySource._error (.../node_modules/webpack-sources/lib/SizeOnlySource.js:16:10)
    at SizeOnlySource.buffer (.../node_modules/webpack-sources/lib/SizeOnlySource.js:30:14)
    at _isSourceEqual (.../node_modules/webpack/lib/util/source.js:21:51)
    at isSourceEqual (.../node_modules/webpack/lib/util/source.js:43:17)
    at Compilation.emitAsset (.../node_modules/webpack/lib/Compilation.js:4156:6)
    at .../node_modules/webpack/lib/Compiler.js:546:28
    at .../node_modules/webpack/lib/Compiler.js:1127:17
    at eval (eval at create (.../node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:13:1)
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
The terminal process "zsh '-c', 'yarn run start'" terminated with exit code: 1.
andreialecu commented 2 years ago

I'm not sure if this is in any way helpful, but once it starts occurring it seems to always be the same file. The only place that file is referenced is through the font-awesome npm package:

https://unpkg.com/font-awesome@4.7.0/scss/_path.scss

Notice how it's listed twice, once with a query string. I took a look through webpack sources and I notice that there's some logic related to query strings: https://github.com/webpack/webpack/blob/122db57e7bb0ddb8327b37eeaa0adb9bd5135962/lib/Compiler.js#L592-L604

immutable seem to then be used to consider whether to turn an asset into a SizeOnlySource later below.

Running a full angular build (non watch-mode) works. It works so well actually that it seems to clear up the initial error so now I can no longer reproduce it, again. It does pop up randomly though, so I'm hoping next time I can troubleshoot it further.

alexander-akait commented 2 years ago

Sounds like a cache problem... Do you enable cache?

andreialecu commented 2 years ago

Yes, the cache is enabled, I mentioned it earlier:

The stacktrace only mentions webpack from top to bottom, and I noticed that if I delete the webpack cache the problem goes away.

alexander-akait commented 2 years ago

Can you try to increase stack trace using --stack-trace-limit (https://nodejs.org/api/cli.html)?

alan-agius4 commented 2 years ago

Following a convo on discord with @andreialecu, it turns out that this stylesheet is actually referenced in a component and therefore it doesn’t use mini-css. I therefore suspect that this might be an issue with our plugin.

alan-agius4 commented 2 years ago

While digging into this, I stumbled upon the double incremental re-builds issue when the cache is restored. There appears to be an issue with Webpack, when loaders are not hoisted to the top level node_modules and during watch mode.

More info: https://github.com/webpack/webpack/issues/14911

alexander-akait commented 2 years ago

@alan-agius4 hm, do you reinstall deps in watch mode?

alan-agius4 commented 2 years ago

No, see steps in https://github.com/webpack/webpack/issues/14911#issue-1072012492. Note, this is not related to the only size() is supported issue. Just wanted to mention it here, since some people mentioned the double rebuild problem here.

alan-agius4 commented 2 years ago

Regarding the original issue, what I think is happening is that we are storing the assets from child compilers in a Map.

for (const { info, name, source } of childCompilation.getAssets()) {
   this.assetCache.set(cacheKey, { info, name, source });
}

Later on during an incremental build, we are re-emitting these assets from cache.

for (const [, { name, source, info }] of this.assetCache) {
   this._parentCompilation.emitAsset(name, source, info);
}

I suspect that in some cases, the source is mutated to SizeOnlySources. My 2 cents would be that in the cache we store source as string or buffer instead of the source Instance.

Ie:

this.assetCache.set(cacheKey, { info, name, source: source.source() });

And when we re-emit, we create a new RawSource everytime.

this._parentCompilation.emitAsset(name, new sources.RawSource(source), info);
alexander-akait commented 2 years ago

hm, I think you should not store string or buffer, only sources have cache logic, so better to store them and avoid creating sources.RawSource, because it is also bad for performance

alan-agius4 commented 2 years ago

Actually, I was wrong, at first seeing the logic here, the asset is not mutated since we are creating a new object each time, so back to square one.

alexander-akait commented 2 years ago

Logic for child compilations is the same as for common compilations, and yes source can be SizeOnlySource if child compilation is cacheable, you can mark modules are not cachable to avoid this problem, but better to store source instead string or buffer, also it will be faster, maybe if you provide example of code I can help

alan-agius4 commented 2 years ago

Had a chat with @alexander-akait, which firstly I'd like to thank.

Unfortunately, we didn't find anything suspicions that could cause this issue and hence without a reproduction it would be hard to get to the bottom of this.

@alexander-akait also suggested that you can add a breakpoint/console.log here https://github.com/webpack/webpack-sources/blob/main/lib/SizeOnlySource.js#L15 and https://github.com/webpack/webpack/blob/main/lib/Compiler.js#L546.

andreialecu commented 2 years ago

Can you try to increase stack trace using --stack-trace-limit (nodejs.org/api/cli.html)?

I keep getting this error on and off, and I tried adding Error.stackTraceLimit = Infinity; and longjohn. I'm not sure if either are supposed to work any more, but they didn't change anything.

I'm on Node 16.13.0, and this is an async unhandled promise error, which quits the process. There's a similar stack trace shown here: https://github.com/nodejs/node/issues/11865#issuecomment-850852069

I'm not sure why I can't get a longer stack trace.

In the mean time I've been trying to debug it further and I noticed that the double compilation issue in my case is caused by a missing/leftover file in angular.json's assets field.

It appears that a recompilation is triggered with changedFiles just containing the path to that missing file. This is possibly an Angular issue. Not sure if https://github.com/webpack/webpack/issues/14911#issue-1072012492 is related or not. @alan-agius4 might be able to clarify (I also left additional details on Discord)

Other findings are that if I try to copy the entire project somewhere else, the error will not occur. I even tried to use rsync to preserve file access times, without success. After inspecting the Angular cache files, it appears that full FS paths are hard-coded/baked into the cache. This may trigger an invalidation when the compilation is being ran from elsewhere, and it clears the error.

I've also been trying to add or remove various things to angular's webpack plugin without success. Once the error happens it keeps happening until the cache is invalidated.

andreialecu commented 2 years ago

To add to the above, I thought the error was triggered by the second compilation because it would only ever occur after it - however after removing the leftover file it now compiles just once.

The error still occurs, it just happens a second or so after ✔ Compiled successfully. is printed by Angular.

Here's a recording. (there are some weird console.logs showing as well, from my debugging)

https://user-images.githubusercontent.com/697707/145184221-e210508a-5988-43f3-aca6-f53f841f8854.mov

alan-agius4 commented 2 years ago

@andreialecu, is it a possibility to either share your project (privately) or schedule a call so that we can debug this together?

andreialecu commented 2 years ago

@alan-agius4 yes, sure. Let's schedule a time via Discord.

alan-agius4 commented 2 years ago

FYI @alexander-akait https://github.com/angular/angular-cli/issues/22237#issuecomment-1013195711

DineshCodeFlow commented 2 months ago

Run: rm -rf .angular and then ng serve