vkashti / scripts / compress-gtm.js
compress-gtm.js
Raw
/**
 * 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();