2024-01-11
Last year I wrote a blog about the same top here.
In the previous blog, I need to:
build the app normally;
manually move the built static assets (js/css/images etc.) to a versioned folder;
manually replace the path in index.html and manifest.json to add the versioned prefix;
upload everything to S3;
But yesterday I found that create-react-app has a native support for placing assets to a specific folder, and all the links in index.html will also have that prefix automatically. And since I now generate all my favicon with Favicon37, I don't need to care about manifest.json anymore.
The trick is the PUBLIC_URL env variable:
const timestamp = new Date()
  .toISOString()
  .replace(/[^0-9]/g, '')
  .slice(0, 14);PUBLIC_URL in .env.production to be the timestamp:const envPath = path.join(__dirname, '..', '.env.production'); // Adjust the path to your .env file
let envContents = fs.readFileSync(envPath, 'utf-8');
let lines = envContents.split('\n');
let found = false;
lines = lines.map(line => {
  const [currentKey] = line.split('=');
  if (currentKey === key) {
    found = true;
    return `${key}=${value}`;
  }
  return line;
});
if (!found) {
  lines.push(`${key}=${value}`);
}
// Filter out any empty lines
lines = lines.filter(line => line.trim() !== '');
fs.writeFileSync(envPath, lines.join('\n'));console.log('Building the app...');
execSync(`npm run build`);
console.log('Build app completed.');console.log('Uploading assets to S3...');
execSync(
  `aws s3 sync build/static ${process.env.S3_URL}/${timestamp}/static --cache-control max-age=31536000,public`
);
console.log('Upload assets to S3 completed.');
console.log('Uploading index.html to S3...');
execSync(
  `aws s3 cp build/index.html ${process.env.S3_URL}/index.html --cache-control max-age=0,no-store`
);
console.log('Upload index.html to S3 completed.');That's it.