/**
* This script downloads Google Tag Manager script, compresses it, and serves it locally
* This helps with the "Enable text compression" and "Minify JavaScript" issues
*/
const fs = require('fs');
const path = require('path');
const https = require('https');
const zlib = require('zlib');
const { execSync } = require('child_process');
// Configuration
const GTM_ID = 'G-XXXXXXXX'; // Replace with your actual GTM ID
const OUTPUT_DIR = path.join(__dirname, '../public/scripts');
const OUTPUT_FILE = path.join(OUTPUT_DIR, 'gtm.js');
const OUTPUT_FILE_MIN = path.join(OUTPUT_DIR, 'gtm.min.js');
const OUTPUT_FILE_GZIP = path.join(OUTPUT_DIR, 'gtm.min.js.gz');
const OUTPUT_FILE_BR = path.join(OUTPUT_DIR, 'gtm.min.js.br');
// Ensure the output directory exists
if (!fs.existsSync(OUTPUT_DIR)) {
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
}
// Function to download the GTM script
function downloadGTMScript() {
return new Promise((resolve, reject) => {
console.log('Downloading Google Tag Manager script...');
const url = `https://www.googletagmanager.com/gtag/js?id=${GTM_ID}`;
https.get(url, (response) => {
if (response.statusCode !== 200) {
reject(new Error(`Failed to download script. Status code: ${response.statusCode}`));
return;
}
let data = '';
response.on('data', (chunk) => {
data += chunk;
});
response.on('end', () => {
fs.writeFileSync(OUTPUT_FILE, data);
console.log(`Downloaded script to ${OUTPUT_FILE}`);
resolve(data);
});
}).on('error', (err) => {
reject(err);
});
});
}
// Function to minify the script using Terser
function minifyScript(script) {
try {
console.log('Minifying script...');
// Check if terser is available
try {
execSync('npx terser --version', { stdio: 'ignore' });
} catch (err) {
console.log('Terser not found. Installing...');
execSync('npm install --no-save terser', { stdio: 'inherit' });
}
// Minify script with terser
const minified = execSync(
`npx terser --compress --mangle --output "${OUTPUT_FILE_MIN}" "${OUTPUT_FILE}"`,
{ encoding: 'utf8' }
);
console.log(`Minified script saved to ${OUTPUT_FILE_MIN}`);
// Read the minified file
const minifiedContent = fs.readFileSync(OUTPUT_FILE_MIN, 'utf8');
return minifiedContent;
} catch (err) {
console.error('Error minifying script:', err);
// Fall back to original script if minification fails
return script;
}
}
// Function to compress the script with gzip
function compressWithGzip(script) {
console.log('Compressing with gzip...');
const compressed = zlib.gzipSync(script, { level: 9 });
fs.writeFileSync(OUTPUT_FILE_GZIP, compressed);
console.log(`Gzip compressed script saved to ${OUTPUT_FILE_GZIP}`);
}
// Function to compress the script with Brotli
function compressWithBrotli(script) {
console.log('Compressing with brotli...');
const compressed = zlib.brotliCompressSync(script, {
params: {
[zlib.constants.BROTLI_PARAM_QUALITY]: 11,
},
});
fs.writeFileSync(OUTPUT_FILE_BR, compressed);
console.log(`Brotli compressed script saved to ${OUTPUT_FILE_BR}`);
}
// Generate a helper script to include in your HTML
function generateHelperScript() {
const helperContent = `
/**
* Helper script to load the Google Tag Manager script with proper compression
* Include this script in your Next.js app to load GTM with compression support
*/
export function loadGTM(id = '${GTM_ID}') {
// Create a script element to load our compressed GTM script
const script = document.createElement('script');
// Try to use the local compressed version first
const supportsCompression = 'HTMLScriptElement' in window;
// If the browser supports modern features, use our compressed local version
if (supportsCompression) {
script.src = '/scripts/gtm.min.js';
} else {
// Fallback to the original Google Tag Manager script
script.src = \`https://www.googletagmanager.com/gtag/js?id=\${id}\`;
}
script.async = true;
document.head.appendChild(script);
// Initialize GTM
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', id);
}
`;
const helperPath = path.join(__dirname, '../utils/gtm.js');
fs.writeFileSync(helperPath, helperContent);
console.log(`Helper script saved to ${helperPath}`);
}
// Main function
async function main() {
try {
const script = await downloadGTMScript();
const minified = minifyScript(script);
compressWithGzip(minified);
compressWithBrotli(minified);
generateHelperScript();
console.log('\nAll done! To use the compressed GTM script:');
console.log('1. Update your Next.js configuration to serve .gz and .br files with correct Content-Encoding headers');
console.log('2. Import the loadGTM function from utils/gtm.js and use it in your layout component');
console.log('3. Run this script periodically to keep your GTM script up to date');
} catch (err) {
console.error('Error:', err);
process.exit(1);
}
}
main();