“This is the fifth day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”
Hashing and timestamping most node_modules to survive builds and regular dependencies can be expensive and slow down webpack considerably. To avoid this, WebPack introduces performance optimizations that skip node_modules by default and use version and name in package.json as data sources.
This optimization will be used to configure all paths in the item cache.managedPaths. It installs the node_modules directory for Webpack by default.
After this optimization is enabled, do not manually edit node_modules. You can disable it using cache.managedPaths: [].
Another optimization is enabled when Yarn PnP is used. Because the cache contents are immutable, all files in the YARN cache skip hash and timestamp operations entirely (version and name are not even tracked).
This operation is controlled by the configuration item cache.immutablePaths. If Yarn PnP is enabled, the Yarn cache of WebPack is installed by default.
Do not manually edit the YARN cache, as this is simply not feasible.
Use persistent caching
This is a typical configuration to enable persistent caching:
cache: {
type: "filesystem".buildDependencies: {
config: [ __filename ] // You can ignore it when your CLI automatically adds it}}Copy the code
Watching
Persistent caching is available for both individual and continuous builds (Watch).
When cache.type: “filesystem” is set, webpack internally enables filesystem caching and memory caching in a hierarchical manner. When reading from the cache, the memory cache is first looked at, and if it is not found, it is demoted to the file system cache. The write cache writes to both the memory cache and the file system cache.
The file system cache does not serialize requests to disk directly. It will not execute until the compilation process is complete and the compiler is idle. The reason for this is that serialization and disk writes take up resources, and we don’t want to delay the compilation process any further.
For a single build, the workflow is:
- Loading cache
- Building
- Emitting
- Display results (stats)
- Persisting cache (if changed)
- Process exits
For continuous build (Watch), the workflow is:
- Loading cache
- Building
- Emitting
- Display results (stats)
- Attach filesystem watchers
- Wait
cache.idleTimeoutForInitialStore
- Persisting cache (if changed)
- On change:
- Building
- Emitting
- Display results (stats)
- Wait
cache.idleTimeout
- Persisting cache (if changed)
You will find two new cache configuration items. The idleTimeout and cache idleTimeoutForInitialStore, they control the persistent cache before the compiler must spare time. Cache. IdleTimeout defaults to 60 s, cache idleTimeoutForInitialStore defaults to 0 s. Because serialization prevents the event loop, no cache detection is done when serializing the cache. This delay attempts to avoid the delay caused by a quick edit of the file that causes recompilation in Watch mode, while trying to keep the persistent cache up to date for the next cold start. This is a compromise solution that allows you to set values that are appropriate for your workflow. Smaller values shorten cold start times, but increase the risk of delayed rebuild.
Error handling
The way to recover persistent cache in the event of an error can be by deleting the entire cache and starting a new build, or by removing the cache entry in question and leaving the item uncached.
In this case, the Webpack logger issues a warning. For more information, see infrastructureLogging’s configuration items.
CLI guide
By default, the CLI using WebPack may add build dependencies, but WebPack itself does not.
- By default, the CLI will
cache.buildDependencies.defaultConfig
Set to the configuration file used - The CLI appends command-line arguments to
cache.version
- When using command line parameters, the CLI may be in
cache.name
To add a comment.
Debugging information
Additional debugging information is output using the following configuration:
infrastructureLogging: {
debug: /webpack\.cache/
}
Copy the code
Internal workflow
- Webpack reads the cache file.
- No cached file -> No build cache
- In the cache file
version
δΈcache.version
Mismatch -> No build cache
- Webpack will parse the snapshot (
resolve snapshot
) to the file system- Match to -> Continue with the subsequent process
- No match was found:
- Parse all parses again (
resolve results
)- No match to -> no build cache
- Match to -> Continue with the subsequent process
- Parse all parses again (
- Webpack will build dependency snapshots (
build dependencies snapshot
) to the file system- No match to -> no build cache
- Match to -> Continue with the subsequent process
- Deserialization of cache entries (delayed deserialization of large cache entries during build)
- Build run (with or without caching)
- Trace build dependencies
- tracking
cache.buildDependencies
- Trace the loader in use
- tracking
- Trace build dependencies
- The new build dependencies have been resolved
- Resolution dependencies are traced
- Parsing results have been traced
- Create snapshots from all newly resolved dependencies
- Create snapshots from all new build dependencies
- Serialize persistent cache files to disk
serialization
All classes that support serialization need to register a serializer:
webpack.util.serialization.register(Constructor, request, name, serializer);
Copy the code
Constructor should be a class or Constructor function. Object. constructor for any object that needs to be serialized will be used to find the serializer.
Request will be used to load the call Register module. It should point to the current module. It will be used this way: require(request).
Name is used to distinguish between multiple register calls with the same request.
Serializer is an object that has at least two methods serialize and Deserialize.
To serialize an object, call serializer. Serialize (Object, context). Context is an object that has at least one write(anything) method that writes to the output stream. The passed value is also serialized.
To deserialize an object, call serializer. Deserialize (context). Context is an object that has at least one read(): anything method. This method deserializes something in the input stream. Deserialize must return the deserialized object.
Serialize and deserialize should read and write the same objects in the same order.
// some-module/lib/MyClass.js
class MyClass {
constructor(a, b) {
this.a = a;
this.b = b;
this.c = undefined;
}
}
register(MyClass, "some-module/lib/MyClass".null, {
seralize(obj, { write }) {
write(obj.a);
write(obj.b);
write(obj.c);
}
deserialize({ read }) {
const obj = new MyClass(read(), read());
obj.c = read();
returnobj; }});Copy the code
Both the base datatype and the serializers that reference the datatype are registered, namely string, Number, Array, Set, Map, RegExp, plain Objects, Error.