All notes

Long-Lived Asset Caches Require Immutable URLs

Coordinate hashed assets, HTML freshness and retention across deployment generations.

English edition, edited for length. Read the complete Chinese original.

Set /app.js to a one-year cache duration. The next deployment will still use the same URL, and users may continue to run their old scripts. Long caching is not simply optimizing response headers; it requires the resource URL to change along with the content, allowing the browser to naturally distinguish between versions.

This article discusses the creation of generated JavaScript, CSS, fonts, and images. Because HTML and API data often have different semantic updates, it should not be directly applied with the same strategies.

Content Hashing for URL Description Versioning

GET /assets/search.a1b2c3.js

HTTP/1.1 200 OK
Cache-Control: public, max-age=31536000, immutable

If the file content changes, the builder generates a new name, and the HTML references the new address. The old address will remain unchanged. immutable During the caching period, the resources remain unchanged, but the actual maintenance must adhere to this commitment and cannot manually overwrite the same files.

A hash name is not a form of encryption and should not be treated as a private URL. Once a page references a resource, visitors will be able to see it. Draft content, internal configurations, and secrets should not be placed in public asset directories simply because they have a random filename.

Two deployments can generate completely identical CSS, allowing them to share the same content hash address. Deployments with different versions do not necessarily require all assets to be renamed. Instead, if the file content changes while the deployment name remains the same, a new resource identity should be assigned. Content hashes help with deduplication and long-term caching, while deployment identifiers help associate complete page sets. These two mechanisms address different problems. Avoid embedding the creation time of the resource in all resource names, which would lead to redundant downloads of the same bytes every time.

The hash is generated by the builder and cannot be manually modified after the file is created. If the hosting layer compresses or re-encodes the file again, it is necessary to clearly indicate whether the URL refers to the original content or the final representation, and to configure the validator according to the platform’s supported settings. Hash filenames are not a mechanism for access control, and they are not necessarily a mechanism for integrity checking. Browsers will not automatically determine the correct number of bytes to download based solely on the filename. When integrity protection is required, use the appropriate standards and deployment verification.

An asset inventory can record logical names, hash paths, sizes, and reference relationships. The HTML and inventory must come from the same build to avoid new pages referencing paths from previous versions. The inventory also helps identify isolated resources, but removal should consider old pages and historical deployments, rather than simply deleting based on “not currently referenced.” The asset lifecycle is longer than the current repository references.

Considerations for Deploying Code That Uses Legacy HTML

Users may obtain outdated HTML from browser caches, CDNs, or open tabs. If the deployment process immediately removes the old files, it will still attempt to load the old hash resources, resulting in a failed load. Atomic deployment platforms often address this issue through versioned artifacts, but it’s important to verify which versions are retained and how the switch behavior is handled.

Implementing a self-built upload process is prone to errors: either the new HTML is uploaded before the resources are fully available, or the old resources are deleted before the old page is fully unloaded from the cache. The correct order of operations should ensure that the resources referenced in the new HTML are present, and that the resources required by the old version are retained until their reasonable lifespan ends.

The process of building a custom object storage system can initially upload all new assets, followed by verification and HTML updates, while retaining the old assets. This prevents the new HTML from initially referencing missing files, but doesn’t automatically guarantee that multiple HTML pages can be switched simultaneously. If the homepage and article page updates are performed in two steps, a mixed version may exist during this period, requiring compatibility or platform-specific routing capabilities. Do not refer to the secure upload order as a natural atomic operation for all requests.

A versioned deployment platform might switch between page and asset versions, but different platforms have specific guarantees regarding legacy assets and edge caching. It’s important to determine whether legacy resources are still accessible from the new version entry point, rather than simply knowing that the old version is retained in the backend. Client-side old tabs might request old chunks under the current domain, but this doesn’t necessarily help if the legacy deployment is on a different address. Real cross-version testing is necessary to verify this.

The caching rules also need to differentiate between responses for missing resources. If a newly uploaded resource is requested and cached as a 404, and then successfully uploaded, it may not be visible. To avoid accessing resources that are not yet ready, and to set appropriate error caching and cleanup paths. Only switch to a new page after confirming that all new references are available, reducing this window. Simply clearing the homepage will not fix a missing chunk in the cache.

CSS and Fonts Also Have Version Coupling

The new CSS references the new font paths, but the old CSS should still be able to load the old fonts. It’s important to note that relying solely on the main JavaScript can be problematic. Dynamically imported chunks are more prone to failure after a user has been on the page for a long time, as they may not be requested until a button is clicked.

At this point, clear refresh prompts can be provided, but unlimited automatic refreshing should be avoided to prevent an infinite loop. Error monitoring should record the resource address and page version to easily determine if the version is inconsistent, rather than attributing all failed chunk loading to network issues.

After a user opens the page, the search is only initiated several hours later, and the browser then requests the dynamic chunk. If the old resource has been deleted, the functionality fails while the main content remains functional. The error message can suggest a refresh, but it’s important to preserve the task input and avoid an automatic refresh loop. If the refresh fails, it’s crucial to report the actual error, rather than repeatedly refreshing. Resource failure could be due to network issues, extension blocking, or missing versions. Logs should include version and address information to aid in classification.

Regarding interactions involving writing, refreshing should not discard unsaved content. It’s possible to save non-sensitive drafts or provide copy paths, depending on the specific product requirements. Personal blog searches are relatively easy to recover, but generic loading error components may be reused by other forms, so it should not be assumed that they should always be forcibly reloaded. Version compatibility strategies should be based on user tasks, ensuring that users don’t have to lose input due to resource management decisions.

References to resource paths can also come from CSS, worker scripts, WASM, and fonts, not just scripts within HTML. Build acceptance can parse the manifest and resource dependencies to verify that the files exist. Manual checks may miss deep dependencies. Third-party external libraries use fixed version addresses to avoid one vendor overriding the same path, which would invalidate the commitment to immutability.

HTML Caching Requires a Different Rhythm

HTML can be used with shorter freshness settings or validation, ensuring that newly published content is immediately visible. While CDN and browser caching can be managed separately, it’s important to check the platform’s capabilities to avoid the misconception that a single header can control all layers. When performing emergency fixes, it’s crucial to consider HTML, Service Workers, and CDN objects simultaneously.

If a Service Worker is present, it introduces an additional lifecycle for resources. The pre-caching list, activation timing, and old cache cleanup need to be tested. You cannot assume that offline caching will not affect the release simply because the network layer has been versioned.

Pre-cached lists, installation completion, waiting for activation, and old cache cleanup can be distributed across different stages. Immediately activating a new worker might take over old pages, causing the old pages to request the new policy. Delaying activation means that new features won’t be immediately visible. The choice depends on application compatibility; skipping waiting is not a universally correct answer. For technical blogs that don’t require offline functionality, omitting the service worker can also reduce one layer of the lifecycle.

HTML cached offline will also reference old hash resources. When clearing old caches, ensure that active pages still have available resources, or provide a clear update process. Network strategies, caching strategies, and version lists must be consistent. If a new worker installation fails, retain the old capabilities without deleting all caches, and only discover that the new resources are unavailable afterward. Updates are state transitions, not simply clearing.

Emergency security fixes require evaluating whether existing offline code is still functional, and server-side authorization always operates independently. Do not expect immediate cleanup of the CDN to affect every user device. Public assets may be retained for an extended period, so secrets are not stored within them, and sensitive operations do not rely on client version judgments. This is a security boundary that must be maintained, separate from the immutable resource policy.

Resource Preservation is a Compatibility Policy

The duration for which historical files should be retained should be determined by factors such as the activity of old pages, offline capabilities, and the scope of support. Personal blogs may only need to cover common caching and tab cycle periods, while business applications may require longer version compatibility. A fixed one-year max-age should not be directly interpreted as a requirement to retain files for exactly one year, and deleting files on the second day should not be done without considering dynamically dependent files that have not been requested. The policy should specify which older versions are still supported, and how to restore user tasks when the scope is exceeded.

Before cleanup, create a list of resources and referenced versions to be deleted, and then verify the current and still supported versions. Shared assets may be reused across multiple deployments, and deleting based solely on file creation time would inadvertently affect the current version. The deletion operation uses precise paths and recoverable archiving, followed by acceptance of the old pages. Managing resources is a high-risk infrastructure action that cannot be replaced with a vague wildcard like “clear cache.”

Publishing a rollback might also span across dependency security updates. If scripts referenced by the old page have known vulnerabilities, it should not be done solely for the purpose of reproducing an indefinite rollback of the old code. Instead, a secure fix version should be built based on the known content, and it should be clearly stated that this is not a rollback of the same code. Content restoration and software security should be evaluated separately, and asset retention does not mean that the old version can be deployed indefinitely. Policies for accessing historical files should also minimize the public scope.

For publicly available images and fonts, using the old address for long-term availability can be convenient for external referencing. However, license revocation or privacy risks may necessitate removal. In this situation, cleaning the server and CDN represents a manageable step, but existing downloads cannot be recovered. The promise of immutable caching should require a review of information classification before asset publication, and resources that are difficult to remove later should not be used to store sensitive or confidential information.

Finally, observe the resource hit rate and page version to determine if the cleanup was performed too early. The metrics should be based on a limited version and resource type, and the specific address should retain the sampling logs to avoid creating an infinite sequence of metrics for each hash. After resource recovery, confirm that all incorrect cached copies have disappeared before considering the process complete. The long-term caching optimization should also include lifecycle, diagnostic, and compatibility policies, and should not only report an increase in hit rates.

Visualizing the Dependency Chain for a Dynamic Import Failure

The old HTML reference entry script, which imports the “reference” search chunk after the user clicks “search,” then loads the index and styles. If “reference” is published and only the main script is retained, the old entry can still execute, but the interaction will fail. The resource list should cover the entire reference graph, not just HTML direct links. The version relationships for CSS fonts, wasm, worker scripts, and runtime indexes also need to be registered.

Each address in the diagram has its own specific update semantics. The hash script is immutable, and the fixed index may be updated with each article publication. The API returns real-time permissions. When an old script reads a new index, it must either maintain format compatibility or explicitly specify the version address. It cannot assume that all resources can be independently updated to the latest version. Separating the format version from the content version allows new articles to be added without forcing old clients to re-download the program, and also enables a true migration when the format changes.

Accept and save the original version of the page, and the delay function will only be triggered after deploying the second version. Verify that all referenced scripts are available and have the correct media type. If the platform reverts missing scripts to the default homepage, and the network status is successful, it will result in parsing errors. To distinguish between missing scripts, incorrect routing, and genuine script errors, verify that the content type matches the expected content and identity. The logs also retain the page version and resource address, but limit the entry of high-value numerical fields into the metrics.

Deleting a decision based on cited references rather than the current directory

First, obtain a list of the current version and any still-supported historical versions. Then, identify the set of resources that are still being referenced. Finally, list the candidates for deletion. It’s important to note that assets with the same hash can be shared across multiple versions. Deleting based on file creation time can inadvertently affect the current page. Dynamic resources that haven’t been downloaded yet must also be retained, and cannot be solely determined by the number of bytes available in the cache. The scope of the cleanup is determined by the longest reasonable client lifespan and the product support policy.

Provide preview deletion and recoverable archiving, using precise paths for actual operation. After cleanup, run tests on saved old pages to confirm that compatibility remains valid. If a version is decided to be discontinued, the client should have a clear and understandable update path, and should be able to retain unsaved tasks without forcing everyone to refresh through intentional chunk deletion. Resource management is the implementation of the support policy, not simply transferring disk space issues directly to the user.

Security fixes may require the discontinuation of older scripts, but scripts already downloaded cannot be removed from the server. Sensitive operations depend on compatibility between the current server-side authorization and the protocol, and do not trust client-reported versions. Removing old assets can reduce further distribution, but it cannot be the sole measure to prevent the execution of dangerous code. Content hash addresses are publicly available and can be long-term stored, so secrets must be eliminated before publication.

Two-Stage Verification for HTML Switching and Resource Upload

First, upload the “immutable” version of the resource, then verify it item by item. Finally, switch to HTML. This can reduce the occurrence of errors caused by referencing unavailable windows. Check the actual domain-specific addresses, not just the backend object storage. This is because URL rewriting and CDNs can affect accessibility. If a file was previously cached as missing, it still needs to be cleared or wait for a clear error timeout after a successful upload. It’s more reliable to resolve these known failures before switching to the main version, rather than letting readers encounter loading errors after going live.

This is not an automatic, global transaction. Different HTML files may come from different versions during the switch, and the browser also retains the old page. The application design needs to accept the supported version combinations, or utilize a platform with the ability to route to the actual supported version. The report specifically details the platform guarantees, without using the generic term “atomic deployment” to cover caching and client coexistence. Rollback also checks the resource set, rather than simply reverting the homepage pointer.

Allow for Explainable Exceptions to Caching Policies

The one-year immutable policy applies to truly immutable resources. Fixed favicons, site verification files, or specific download URLs may use different update methods. Configuration should be done separately for each use case, rather than applying a single rule to all paths with the same header. While filenames have a hash, the content is manually overwritten, which still violates the promise. Alternatively, if filenames do not have a hash but use reliable version parameters, it is also necessary to ensure that all caching layers treat the parameters as resource identifiers.

Third-party fixed URLs are not under our control, and we cannot guarantee their permanence. You can use vendor-specific versioned addresses and review licenses, or accept the risk of external updates and establish a monitoring system. Before re-hosting, confirm your rights and maintenance responsibilities, and do not simply download all external assets for long-term caching. Resource versioning is a commitment to authentic content, not just adding a few characters to arbitrary filenames.

The list should also cover preloading. While the HTML preloads the primary font, the CSS references the secondary font’s address. The browser might download both resources, and the page will still function correctly. Checking that preload, module entry points, CSS, and runtime imports all originate from the same approved reference chart is crucial. It’s not enough to simply check if the final control is displayed. If resources are being duplicated and unnecessarily transferred, this represents a failure in version coordination, leading to performance issues.

For users who continuously open pages, the resource support period can be determined through limited version statistics and controlled error sample observation, rather than collecting complete browsing history. When support for a version is discontinued, the conditions for updating should be specified, and whether the task status can be retained is defined by the product. Old scripts that are already cached in the browser may continue to run, so the server-side interface compatibility period also needs to be considered. Asset cleanup cannot unilaterally determine when old programs will be retired.

Automatic Recovery: Avoiding Further User Losses

Even after a chunk fails and automatically refreshes once, there’s still a possibility of losing the form or experiencing unintended side effects. First, determine the task type, then retry the search after preserving the query. The editor should retain non-sensitive input and indicate update requirements. Set a limit for repeated refreshes, and stop and provide a stable entry after failure. Different recovery actions may be required for offline network, blocked extensions, and version inconsistencies; not all errors should trigger a page reload.

The monitoring records resource errors, the current page version, and the number of attempts. After recovery, verify that missing cached copies have disappeared. A high hit rate does not necessarily mean correct version coordination, and a low error rate may also be due to infrequent use of delayed functionality. The successful completion of tasks across versions provides more direct evidence. The benefits of long caching must be maintained alongside this compatibility commitment.

Test Across Versions, Not Just the New Page

Save the previous version of the HTML, then deploy the new version. Use it to request the old resources and verify that they are still working. Keep a previous tab open and use the lazy loading feature to observe if any chunks are missing. Request the new page and check if all the resources return content that matches their filenames.

Furthermore, it’s crucial to verify the rollback mechanism: Can the old HTML be successfully re-fetched to obtain the complete original resources? Does the cache header allow for the masking of persistent errors? The benefits of long caching rely on the availability of immutable assets and the preservation of complete versions. Without these, a longer TTL simply prolongs the update failures.

Short hash names also need to handle naming conflicts. If a custom publisher truncates the full summary into a small number of characters, two different assets could potentially obtain the same target path. It is not permissible to allow overwriting simply because the probability of it occurring seems low. When uploading, the system compares the existing bytes with the bytes to be uploaded. If they are the same, they can be reused. If they are different, the system must either block the upload or select a new address according to the approved rules. A mature builder’s naming mechanism takes precedence over temporary implementations.

The test doesn’t actually need to find cryptographic hash collisions. Instead, it provides a controllable naming alias for the synthetic publisher, allowing two different files to generate the same path. This confirms that the second file will not overwrite the first, and that the HTML has not switched. This sample only validates the conflict resolution path, and does not prove the security of the hash algorithm itself. Immutable commitments rely on both naming and writing to be maintained together. A successful upload should not mask the fact that an old URL has been changed.

References: Cache-Control, Vite Static Asset Handling.