Tôi đã gặp sự cố tương tự với index.html được trình duyệt lưu vào bộ nhớ cache hoặc phức tạp hơn bởi cdn / proxy trung gian (F5 sẽ không giúp bạn).
Tôi đã tìm kiếm một giải pháp xác minh 100% rằng máy khách có phiên bản index.html mới nhất, may mắn là tôi đã tìm thấy giải pháp này bởi Henrik Peinar:
https://blog.nodeswat.com/automagic-reload-for-clients- After-deploy-with-angular-4-8440c9fdd96c
Giải pháp cũng giải quyết được trường hợp khách hàng vẫn mở trình duyệt trong nhiều ngày, khách hàng kiểm tra các bản cập nhật theo khoảng thời gian và tải lại nếu phiên bản mới hơn sẽ được triển khai.
Giải pháp là một chút phức tạp nhưng hoạt động như một sự quyến rũ:
- sử dụng thực tế rằng
ng cli -- prod
tạo ra các tệp được băm với một trong số chúng được gọi là main. [hash] .js
- tạo một tệp version.json có chứa hàm băm đó
- tạo một dịch vụ góc cạnh VersionCheckService để kiểm tra version.json và tải lại nếu cần.
- Lưu ý rằng tập lệnh js chạy sau khi triển khai sẽ tạo cho bạn cả phiên bản.json và thay thế hàm băm trong dịch vụ góc, vì vậy không cần thao tác thủ công mà chạy post-build.js
Vì giải pháp Henrik Peinar dành cho góc 4 nên đã có những thay đổi nhỏ, tôi cũng đặt các tập lệnh cố định ở đây:
VersionCheckService:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable()
export class VersionCheckService {
// this will be replaced by actual hash post-build.js
private currentHash = '{{POST_BUILD_ENTERS_HASH_HERE}}';
constructor(private http: HttpClient) {}
/**
* Checks in every set frequency the version of frontend application
* @param url
* @param {number} frequency - in milliseconds, defaults to 30 minutes
*/
public initVersionCheck(url, frequency = 1000 * 60 * 30) {
//check for first time
this.checkVersion(url);
setInterval(() => {
this.checkVersion(url);
}, frequency);
}
/**
* Will do the call and check if the hash has changed or not
* @param url
*/
private checkVersion(url) {
// timestamp these requests to invalidate caches
this.http.get(url + '?t=' + new Date().getTime())
.subscribe(
(response: any) => {
const hash = response.hash;
const hashChanged = this.hasHashChanged(this.currentHash, hash);
// If new version, do something
if (hashChanged) {
// ENTER YOUR CODE TO DO SOMETHING UPON VERSION CHANGE
// for an example: location.reload();
// or to ensure cdn miss: window.location.replace(window.location.href + '?rand=' + Math.random());
}
// store the new hash so we wouldn't trigger versionChange again
// only necessary in case you did not force refresh
this.currentHash = hash;
},
(err) => {
console.error(err, 'Could not get version');
}
);
}
/**
* Checks if hash has changed.
* This file has the JS hash, if it is a different one than in the version.json
* we are dealing with version change
* @param currentHash
* @param newHash
* @returns {boolean}
*/
private hasHashChanged(currentHash, newHash) {
if (!currentHash || currentHash === '{{POST_BUILD_ENTERS_HASH_HERE}}') {
return false;
}
return currentHash !== newHash;
}
}
thay đổi thành AppComponent chính:
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
constructor(private versionCheckService: VersionCheckService) {
}
ngOnInit() {
console.log('AppComponent.ngOnInit() environment.versionCheckUrl=' + environment.versionCheckUrl);
if (environment.versionCheckUrl) {
this.versionCheckService.initVersionCheck(environment.versionCheckUrl);
}
}
}
Tập lệnh hậu xây dựng tạo nên điều kỳ diệu, post-build.js:
const path = require('path');
const fs = require('fs');
const util = require('util');
// get application version from package.json
const appVersion = require('../package.json').version;
// promisify core API's
const readDir = util.promisify(fs.readdir);
const writeFile = util.promisify(fs.writeFile);
const readFile = util.promisify(fs.readFile);
console.log('\nRunning post-build tasks');
// our version.json will be in the dist folder
const versionFilePath = path.join(__dirname + '/../dist/version.json');
let mainHash = '';
let mainBundleFile = '';
// RegExp to find main.bundle.js, even if it doesn't include a hash in it's name (dev build)
let mainBundleRegexp = /^main.?([a-z0-9]*)?.js$/;
// read the dist folder files and find the one we're looking for
readDir(path.join(__dirname, '../dist/'))
.then(files => {
mainBundleFile = files.find(f => mainBundleRegexp.test(f));
if (mainBundleFile) {
let matchHash = mainBundleFile.match(mainBundleRegexp);
// if it has a hash in it's name, mark it down
if (matchHash.length > 1 && !!matchHash[1]) {
mainHash = matchHash[1];
}
}
console.log(`Writing version and hash to ${versionFilePath}`);
// write current version and hash into the version.json file
const src = `{"version": "${appVersion}", "hash": "${mainHash}"}`;
return writeFile(versionFilePath, src);
}).then(() => {
// main bundle file not found, dev build?
if (!mainBundleFile) {
return;
}
console.log(`Replacing hash in the ${mainBundleFile}`);
// replace hash placeholder in our main.js file so the code knows it's current hash
const mainFilepath = path.join(__dirname, '../dist/', mainBundleFile);
return readFile(mainFilepath, 'utf8')
.then(mainFileData => {
const replacedFile = mainFileData.replace('{{POST_BUILD_ENTERS_HASH_HERE}}', mainHash);
return writeFile(mainFilepath, replacedFile);
});
}).catch(err => {
console.log('Error with post build:', err);
});
chỉ cần đặt tập lệnh vào thư mục xây dựng (mới), chạy tập lệnh bằng cách sử dụng node ./build/post-build.js
sau khi xây dựng thư mục dist bằngng build --prod