/

Grunt Integration

ByteHide Shield provides a dedicated Grunt plugin that allows you to seamlessly protect your JavaScript code during the build process. This guide explains how to install and configure the Shield Grunt plugin.

Installation

Install the ByteHide Shield Grunt plugin from npm:

npm install --save-dev @bytehide/grunt-shield

Or with yarn:

yarn add --dev @bytehide/grunt-shield

Basic Setup

Add the Shield plugin to your Gruntfile.js:

module.exports = function(grunt) {
  grunt.initConfig({
    bytehideShield: {
      options: {
        projectToken: 'your-project-token', // Required: Get this from your ByteHide account
      },
      dist: {}
    }
  });

  grunt.loadNpmTasks('@bytehide/grunt-shield');

  // Register a default task
  grunt.registerTask('default', ['bytehideShield']);
};

With this minimal configuration, Shield will apply default protections to your JavaScript files.

Configuration Options

The Grunt plugin accepts the following options:

OptionTypeDefaultDescription
projectTokenstringRequiredYour ByteHide project token
distDirstring'dist'Directory containing files to protect
replacebooleanfalseWhether to replace original files with obfuscated versions
obfuscatedExtensionstring'.obf'File extension for obfuscated files (when replace is false)
excludestring[][]Files or patterns to exclude from obfuscation
configObject{}ByteHide Shield configuration options

Advanced Configuration

For more advanced use cases, you can provide additional Shield protection options:

module.exports = function(grunt) {
  grunt.initConfig({
    bytehideShield: {
      options: {
        projectToken: 'your-project-token',
        distDir: 'build',
        replace: true,
        obfuscatedExtension: '.obf',
        exclude: ['vendor/**/*.js', 'polyfills.js'],
        config: {
          controlFlowFlattening: true,
          debugProtection: false,
          devtoolsBlocking: false,
          stringArray: true,
          stringArrayEncoding: ['base64'],
          selfDefending: true
        }
      },
      dist: {}
    }
  });

  grunt.loadNpmTasks('@bytehide/grunt-shield');
};

Environment-Specific Configuration

You can apply different protection settings based on the environment:

module.exports = function(grunt) {
  // Determine if we're in production mode
  const isProd = grunt.option('production') || process.env.NODE_ENV === 'production';

  grunt.initConfig({
    bytehideShield: {
      options: {
        projectToken: process.env.BYTEHIDE_PROJECT_TOKEN || 'your-project-token',
        replace: isProd, // Only replace files in production
        config: {
          // More aggressive settings for production
          controlFlowFlattening: isProd,
          debugProtection: isProd,
          devtoolsBlocking: isProd,
          // Basic protection for all environments
          stringArray: true,
          identifierNamesGenerator: 'hexadecimal'
        }
      },
      dist: {}
    }
  });

  grunt.loadNpmTasks('@bytehide/grunt-shield');

  // Define different tasks for development and production
  grunt.registerTask('build:dev', ['otherTasks', 'bytehideShield']);
  grunt.registerTask('build:prod', ['otherTasks', 'set_production', 'bytehideShield']);
  
  // Helper task to set production mode
  grunt.registerTask('set_production', function() {
    grunt.option('production', true);
  });
};

Multi-Target Configuration

You can configure multiple targets for different sets of files:

module.exports = function(grunt) {
  grunt.initConfig({
    bytehideShield: {
      options: {
        projectToken: 'your-project-token',
        replace: false
      },
      app: {
        options: {
          // Target-specific options that override the task options
          config: {
            controlFlowFlattening: true,
            stringArray: true
          }
        },
        files: [{
          expand: true,
          cwd: 'src/app/',
          src: ['**/*.js'],
          dest: 'dist/app/'
        }]
      },
      vendor: {
        options: {
          // Lighter protection for vendor files
          config: {
            controlFlowFlattening: false,
            stringArray: true,
            identifierNamesGenerator: 'hexadecimal'
          }
        },
        files: [{
          expand: true,
          cwd: 'src/vendor/',
          src: ['**/*.js'],
          dest: 'dist/vendor/'
        }]
      }
    }
  });

  grunt.loadNpmTasks('@bytehide/grunt-shield');
};

Integration with Other Grunt Tasks

You can integrate Shield with other Grunt tasks in your build workflow:

module.exports = function(grunt) {
  grunt.initConfig({
    clean: {
      dist: ['dist/']
    },
    babel: {
      options: {
        sourceMap: true,
        presets: ['@babel/preset-env']
      },
      dist: {
        files: [{
          expand: true,
          cwd: 'src/',
          src: ['**/*.js'],
          dest: 'temp/'
        }]
      }
    },
    uglify: {
      dist: {
        files: [{
          expand: true,
          cwd: 'temp/',
          src: ['**/*.js'],
          dest: 'dist/'
        }]
      }
    },
    bytehideShield: {
      options: {
        projectToken: 'your-project-token',
        replace: true,
        config: {
          controlFlowFlattening: true,
          debugProtection: false,
          devtoolsBlocking: false
        }
      },
      dist: {
        files: [{
          expand: true,
          cwd: 'dist/',
          src: ['**/*.js'],
          dest: 'dist/'
        }]
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-babel');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('@bytehide/grunt-shield');

  // Define build task
  grunt.registerTask('build', [
    'clean',
    'babel',
    'uglify',
    'bytehideShield'
  ]);
};

Complete Example

Here's a complete example of a Grunt configuration with Shield:

module.exports = function(grunt) {
  // Determine if we're in production mode
  const isProd = grunt.option('production') || process.env.NODE_ENV === 'production';

  grunt.initConfig({
    // Clean directories
    clean: {
      dist: ['dist/'],
      temp: ['temp/']
    },
    
    // Copy files
    copy: {
      assets: {
        files: [{
          expand: true,
          cwd: 'src/assets/',
          src: ['**/*'],
          dest: 'dist/assets/'
        }]
      }
    },
    
    // Process JavaScript
    babel: {
      options: {
        sourceMap: true,
        presets: ['@babel/preset-env']
      },
      dist: {
        files: [{
          expand: true,
          cwd: 'src/js/',
          src: ['**/*.js'],
          dest: 'temp/'
        }]
      }
    },
    
    // Minify JavaScript
    uglify: {
      options: {
        sourceMap: true
      },
      dist: {
        files: [{
          expand: true,
          cwd: 'temp/',
          src: ['**/*.js'],
          dest: 'dist/js/'
        }]
      }
    },
    
    // Protect JavaScript with Shield
    bytehideShield: {
      options: {
        projectToken: process.env.BYTEHIDE_PROJECT_TOKEN || 'your-project-token',
        replace: true,
        exclude: isProd ? [] : ['**/*.min.js'],
        config: {
          controlFlowFlattening: isProd,
          debugProtection: isProd,
          devtoolsBlocking: isProd,
          stringArray: true,
          stringArrayEncoding: isProd ? ['base64'] : [],
          selfDefending: isProd,
          identifierNamesGenerator: 'hexadecimal',
          reservedNames: [
            '^jQuery$', '^\\$',
            '^addEventListener$', '^removeEventListener$'
          ]
        }
      },
      dist: {
        files: [{
          expand: true,
          cwd: 'dist/js/',
          src: ['**/*.js'],
          dest: 'dist/js/'
        }]
      }
    },
    
    // Watch for changes
    watch: {
      js: {
        files: ['src/js/**/*.js'],
        tasks: ['js']
      },
      assets: {
        files: ['src/assets/**/*'],
        tasks: ['copy:assets']
      }
    }
  });

  // Load tasks
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-babel');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('@bytehide/grunt-shield');
  grunt.loadNpmTasks('grunt-contrib-watch');

  // Define custom tasks
  grunt.registerTask('js', ['babel', 'uglify', 'bytehideShield']);
  grunt.registerTask('build', ['clean', 'copy', 'js']);
  grunt.registerTask('default', ['build', 'watch']);
  grunt.registerTask('build:prod', ['clean', 'copy', 'set_production', 'js']);
  
  // Helper task to set production mode
  grunt.registerTask('set_production', function() {
    grunt.option('production', true);
  });
};

Troubleshooting

Common Issues

Error: Invalid Token

If you see an error about an invalid token:

  • Make sure you're using the correct project token from ByteHide Cloud
  • Verify your token has permissions for JavaScript projects

Files Not Being Processed

If your files aren't being protected:

  • Check your file paths and globs in the Grunt configuration
  • Verify the distDir option is set correctly
  • Make sure the files exist in the specified location

Next Steps

Previous
Gulp