DEV: Introduce `DISCOURSE_ASSET_URL_SALT` (#24596)

This value is included when generating static asset URLs. Updating the value will allow site operators to invalidate all asset urls to recover from configuration issues which may have been cached by CDNs/browsers.
This commit is contained in:
David Taylor 2023-11-28 11:28:40 +00:00 committed by GitHub
parent 22ce638ec3
commit 5783f231f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 29 additions and 5 deletions

View File

@ -16,6 +16,7 @@ const { Webpack } = require("@embroider/webpack");
const { StatsWriterPlugin } = require("webpack-stats-plugin");
const withSideWatch = require("./lib/with-side-watch");
const RawHandlebarsCompiler = require("discourse-hbr/raw-handlebars-compiler");
const crypto = require("crypto");
const EMBER_MAJOR_VERSION = parseInt(
require("ember-source/package.json").version.split(".")[0],
@ -153,6 +154,13 @@ module.exports = function (defaults) {
testStylesheetTree,
];
const assetCachebuster = process.env["DISCOURSE_ASSET_URL_SALT"] || "";
const cachebusterHash = crypto
.createHash("md5")
.update(assetCachebuster)
.digest("hex")
.slice(0, 8);
const appTree = compatBuild(app, Webpack, {
staticAppPaths: ["static"],
packagerOptions: {
@ -160,6 +168,8 @@ module.exports = function (defaults) {
devtool: "source-map",
output: {
publicPath: "auto",
filename: `assets/chunk.[chunkhash].${cachebusterHash}.js`,
chunkFilename: `assets/chunk.[chunkhash].${cachebusterHash}.js`,
},
cache: isProduction
? false

View File

@ -29,7 +29,11 @@ module.exports = function generateWorkboxTree() {
// Sprockets' default behaviour for these files is disabled via freedom_patches/sprockets.rb.
const versionHash = crypto
.createHash("md5")
.update(`${versions.join("|")}|${COMPILER_VERSION}`)
.update(
`${versions.join("|")}|${COMPILER_VERSION}|${
process.env["DISCOURSE_ASSET_URL_SALT"] || ""
}`
)
.digest("hex");
return funnel(mergeTrees(nodes), {

View File

@ -22,7 +22,8 @@ class JavascriptCache < ActiveRecord::Base
end
def update_digest
self.digest = Digest::SHA1.hexdigest(content) if content_changed?
self.digest =
Digest::SHA1.hexdigest("#{content}|#{GlobalSetting.asset_url_salt}") if content_changed?
end
def content_cannot_be_nil

View File

@ -386,3 +386,8 @@ allow_impersonation = true
# The maximum number of characters allowed in a single log line.
log_line_max_chars = 160000
# this value is included when generating static asset URLs.
# Updating the value will allow site operators to invalidate all asset urls
# to recover from configuration issues which may have been cached by CDNs/browsers.
asset_url_salt =

View File

@ -6,7 +6,7 @@
Rails.application.config.assets.enabled = true
# Version of your assets, change this if you want to expire all your assets.
Rails.application.config.assets.version = "2"
Rails.application.config.assets.version = "2-#{GlobalSetting.asset_url_salt}"
# Add additional assets to the asset load path.
Rails.application.config.assets.paths << "#{Rails.root}/config/locales"

View File

@ -35,7 +35,8 @@ module HighlightJs
cache_info = {
lang_string: lang_string,
digest: Digest::SHA1.hexdigest(bundle(lang_string.split("|"))),
digest:
Digest::SHA1.hexdigest(bundle(lang_string.split("|")) + "|#{GlobalSetting.asset_url_salt}"),
}
cache[RailsMultisite::ConnectionManagement.current_db] = cache_info

View File

@ -167,12 +167,15 @@ RSpec.describe ThemeJavascriptsController do
component.save!
_, digest = component.baked_js_tests_with_digest
theme_javascript_hash =
component.theme_fields.find_by(upload_id: js_upload.id).javascript_cache.digest
get "/theme-javascripts/tests/#{component.id}-#{digest}.js"
expect(response.body).to include(
"require(\"discourse/lib/theme-settings-store\").registerSettings(" +
"#{component.id}, {\"num_setting\":5,\"theme_uploads\":{\"vendorlib\":" +
"\"/uploads/default/test_#{ENV["TEST_ENV_NUMBER"].presence || "0"}/original/1X/#{js_upload.sha1}.js\"},\"theme_uploads_local\":{\"vendorlib\":" +
"\"/theme-javascripts/#{js_upload.sha1}.js?__ws=test.localhost\"}}, { force: true });",
"\"/theme-javascripts/#{theme_javascript_hash}.js?__ws=test.localhost\"}}, { force: true });",
)
expect(response.body).to include("assert.ok(true);")
ensure