在Nextjs Build之后,我想重命名块文件并使用新数据而不是缓存数据,但manifest.json引用了现有的块文件。 我该如何解决这个问题?
我更改了 next.config.js 选项中的generateBuildId,但它无法正常工作,即使我关闭了缓存,它也会加载现有的块文件。
不是最干净的解决方案,但这对我有用。
/* the trick is to build unique build ID on every build and add it to static files on build time.
* This way the name and URL of static files will change on every build.
*/
/* eslint-disable @typescript-eslint/no-var-requires */
const path = require('path');
// Used to set folders as alias to directly use in nextjs
const nextConfiguration = ({
webpack: (config, { dev }) => {
const newConfig = config;
if (!dev && newConfig.output.filename.startsWith('static')) {
newConfig.output.filename = newConfig.output.filename.replace('[name]', `[name]-${ Math.floor(Date.now() / 1000)}`);
newConfig.output.chunkFilename = newConfig.output.chunkFilename.replace('[name]', `[name]-${ Math.floor(Date.now() / 1000)}`);
}
return newConfig;
},
});
module.exports = nextConfiguration;
每次编译项目时,代码都会向创建的文件的名称添加时间戳。这样,当更改部署到实时站点时,浏览器会收到“新”文件并丢弃缓存的文件。
来源:https://gist.github.com/amit08255/a4eb51d5302e71ba3ecb267bc2a6a5e5
将其添加到您的 next.config.js 文件中。 “generateBuildId”函数已配置为通过创建带有日期的唯一构建 ID 来确保缓存清除。此外,webpack 配置挂钩用于在生产构建期间更改输出文件的名称,向块文件名添加日期。使用时间戳有助于避免缓存问题,确保您获得文件的最新版本。
const path = require('path');
module.exports = {
// Function for cache-busting
generateBuildId: async () => {
// Create a unique build ID with a combination of timestamp and a random string
const timestamp = new Date().getTime(); // Get the current timestamp
const randomString = Math.random().toString(36).substring(2, 8); // Generate a random string
const buildId = `${timestamp}-${randomString}`; // Combine timestamp and random string
return buildId;
},
// Webpack configuration
webpack: (config, { dev }) => {
// Add a timestamp to filenames during production build for cache-busting
if (!dev && config.output.filename.startsWith('static')) {
const timestamp = new Date().getTime(); // Get the current timestamp
// Modify output filenames to include the timestamp
config.output.filename = config.output.filename.replace('[name]', `[name]-${timestamp}`);
config.output.chunkFilename = config.output.chunkFilename.replace('[name]', `[name]-${timestamp}`);
}
// Add other webpack configurations here
return config;
},
// Other configurations...
};
创建一个自定义 Webpack 插件,不仅可以重命名块文件,还可以使用新文件名更新 manifest.json。
import path from 'path';
import fs from 'fs';
class RenameChunksAndUpdateManifestPlugin {
apply(compiler) {
compiler.hooks.afterEmit.tap('RenameChunksAndUpdateManifestPlugin', (compilation) => {
const outputPath = compilation.outputOptions.path;
const chunkFiles = fs.readdirSync(path.join(outputPath, 'static', 'chunks'));
const manifestPath = path.join(outputPath, 'static', 'chunks', 'manifest.json');
let manifest = {};
// Read and parse the existing manifest.json
if (fs.existsSync(manifestPath)) {
manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
}
// Generate a unique hash based on the current timestamp
const hash = Date.now();
// Rename files and update manifest.json
chunkFiles.forEach((file) => {
const ext = path.extname(file); // Get file extension
const oldFilePath = path.join(outputPath, 'static', 'chunks', file);
const newFilename = `${path.basename(file, ext)}-${hash}${ext}`;
const newFilePath = path.join(outputPath, 'static', 'chunks', newFilename);
// Rename the chunk file
fs.renameSync(oldFilePath, newFilePath);
// Update manifest references
for (let key in manifest) {
if (manifest[key] === `static/chunks/${file}`) {
manifest[key] = `static/chunks/${newFilename}`;
}
}
});
// Write the updated manifest.json back to the filesystem
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
console.log('Chunks renamed and manifest.json updated.');
});
}
}
/** @type {import('next').NextConfig} */
const nextConfig = {
webpack: (config, { isServer }) => {
if (!isServer) {
config.plugins.push(new RenameChunksAndUpdateManifestPlugin());
}
return config;
}
};
export default nextConfig;