{"id":24440525,"url":"https://github.com/ertgl/obfuscator-webpack-plugin","last_synced_at":"2025-10-01T10:30:57.187Z","repository":{"id":272466842,"uuid":"916678256","full_name":"ertgl/obfuscator-webpack-plugin","owner":"ertgl","description":"Webpack plugin that obfuscates JavaScript code using javascript-obfuscator.","archived":false,"fork":false,"pushed_at":"2025-01-14T15:40:46.000Z","size":1039,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-14T17:11:12.881Z","etag":null,"topics":["javascript-obfuscator","webpack","webpack-plugin"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ertgl.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-01-14T15:08:44.000Z","updated_at":"2025-01-14T16:17:19.000Z","dependencies_parsed_at":"2025-01-14T17:15:58.773Z","dependency_job_id":"a1f89381-134a-47eb-8669-c4312987ec40","html_url":"https://github.com/ertgl/obfuscator-webpack-plugin","commit_stats":null,"previous_names":["ertgl/obfuscator-webpack-plugin"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ertgl%2Fobfuscator-webpack-plugin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ertgl%2Fobfuscator-webpack-plugin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ertgl%2Fobfuscator-webpack-plugin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ertgl%2Fobfuscator-webpack-plugin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ertgl","download_url":"https://codeload.github.com/ertgl/obfuscator-webpack-plugin/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234856243,"owners_count":18897403,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["javascript-obfuscator","webpack","webpack-plugin"],"created_at":"2025-01-20T20:55:28.942Z","updated_at":"2025-10-01T10:30:57.178Z","avatar_url":"https://github.com/ertgl.png","language":"TypeScript","readme":"# obfuscator-webpack-plugin\n\nA [webpack](https://webpack.js.org/) plugin for obfuscating JavaScript code\nusing [javascript-obfuscator](https://github.com/javascript-obfuscator/javascript-obfuscator).\n\n## Table of Contents\n\n- [Overview](#overview)\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Options](#options)\n  - [Assumptions](#assumptions)\n    - [Content Security Policy (CSP)](#content-security-policy-csp)\n    - [Hot Module Replacement (HMR)](#hot-module-replacement-hmr)\n    - [Node environment](#node-environment)\n    - [Target environment](#target-environment)\n  - [Cache](#cache)\n  - [Excluding assets](#excluding-assets)\n  - [Setting up hooks](#setting-up-hooks)\n    - [Accessing hooks from other plugins](#accessing-hooks-from-other-plugins)\n  - [Using with other minimizers](#using-with-other-minimizers)\n- [Examples](#examples)\n- [Troubleshooting](#troubleshooting)\n- [License](#license)\n\n## Overview\n\nThis plugin differs from the first-party\n[webpack-obfuscator](https://github.com/javascript-obfuscator/webpack-obfuscator)\nplugin in the following ways:\n\n- Obfuscation can be done in the optimization phase instead of the emit phase,\n  this allows running the obfuscator on the final optimized assets.\n- Obfuscated identifier names cache is consistent across the chunks, to\n  reduce the chance of breaking code.\n- Automatic configuration of the obfuscator for Node.js and browser\n  environments with sensible defaults for each that reduce the chance of\n  breaking code.\n- Initial reserved-keywords preset to reduce the chance of breaking code\n  by default.\n- Custom `pre` and `post` hooks for allowing customization of the obfuscation\n  process per chunk.\n- Custom `done` hook for allowing post-processing of the obfuscated assets and\n  shared identifier names cache.\n- Indicators in the webpack stats output to show which assets were\n  obfuscated, for fast visual inspection.\n\n\u003cdetails\u003e\n  \u003csummary\u003eToggle sample output image\u003c/summary\u003e\n  \u003cimg\n    alt=\"Webpack stats includes 'obfuscated' indicator for obfuscated assets\"\n    src=\"assets/stats-preview.png\"\n    width=\"100%\"\n  /\u003e\n\u003c/details\u003e\n\n## Installation\n\nInstall `javascript-obfuscator` and the plugin using `npm` or another package\nmanager:\n\n```sh\nnpm install -D javascript-obfuscator obfuscator-webpack-plugin\n```\n\n## Usage\n\nAdd the plugin to the **`optimization.minimizer`** array in the webpack\nconfiguration:\n\n```js\nconst { ObfuscatorPlugin } = require(\"obfuscator-webpack-plugin\");\n\nmodule.exports = {\n  optimization: {\n    minimize: true,\n    minimizer: [\n      new ObfuscatorPlugin(),\n    ],\n  },\n};\n```\n\n### Options\n\nThe plugin accepts an options object with the following properties:\n\n- **assumptions**:\n  - **csp** (`boolean`): Indicates whether\n    [Content Security Policy](https://en.wikipedia.org/wiki/Content_Security_Policy)\n    is enabled.\n  - **hmr** (`boolean`): Indicates whether\n    [Hot Module Replacement](https://webpack.js.org/concepts/hot-module-replacement)\n    is enabled.\n  - **nodeEnv** (`string`): Specifies the target environment mode\n    (development/production).\n  - **target** (`string`): Specifies the target environment (browser/node).\n- **cache** (`boolean`): Indicates whether to enable caching of the obfuscated\n  code.\n- **exclude** (`(RegExp | string)[]`): An array of regular expressions to exclude\n  assets from obfuscation.\n- **options** (`object`): The options object to pass to the obfuscator.\n- **setupHooks** (`function`): A function to register hooks for customizing the\n  process.\n- **stage** (`number`): Stage at which the plugin will be run\n  (default: `PROCESS_ASSETS_STAGE_DEV_TOOLING`).\n- **test** (`(RegExp | string)[]`): An array of regular expressions to include\n  assets for obfuscation (default: `/\\.[cm]?js[x]?(?:\\?.*)?$/iu`).\n\nThis example demonstrates how to specify the obfuscator options:\n\n```js\nconst { ObfuscatorPlugin } = require(\"obfuscator-webpack-plugin\");\n\nconst domain = \"example.com\";\nconst domainLockRedirectUrl = `https://${domain}`;\n\nmodule.exports = {\n  optimization: {\n    minimize: true,\n    minimizer: [\n      new ObfuscatorPlugin({\n        options: {\n          domainLock: [domain],\n          domainLockRedirectUrl,\n        },\n      }),\n    ],\n  },\n};\n```\n\nYou can refer to the\n[javascript-obfuscator documentation](https://github.com/javascript-obfuscator/javascript-obfuscator#javascript-obfuscator-options)\nfor more information on how to configure the obfuscator.\n\n### Assumptions\n\nThe plugin attempts to make intelligent decisions about how to obfuscate the\ncode, but it may not always make the best choices. The following sections\ndescribe the assumptions the plugin makes and how to override them.\n\n#### Content Security Policy (CSP)\n\nWhen the `target` option is not defined explicitly and the plugin detects that\nthe target is a browser environment, it also checks that if a `trusted-types`\npolicy is specified in the webpack configuration. If so, the plugin configures\nthe obfuscator to generate code that does not contain `eval` calls.\n\nThis behavior can be overridden by setting one of the `csp` or `target`\nassumptions explicitly.\n\n#### Hot Module Replacement (HMR)\n\nUnless the `cache` option is defined explicitly, the plugin enables the\ncaching of the obfuscated codes to reduce build times if the plugin detects\nthat HMR is enabled.\n\nThis behavior can be overridden by setting the `hmr` assumption explicitly.\n\n#### Node environment\n\nThe plugin tries to determine if the NODE_ENV is development or production\nbased on the webpack configuration.\n\n* If the `mode` is set in the configuration, the plugin uses that value to\n  determine the mode.\n* If the `optimization.nodeEnv` is set, the plugin uses\n  that value as the fallback.\n* If neither is set, the plugin defaults to `process.env.NODE_ENV || \"development\"`.\n\nThis behavior can be overridden by setting the `nodeEnv` assumption explicitly.\n\n#### Target environment\n\nIf the `target` option is not defined explicitly in the obfuscator options,\nthe plugin tries to determine the target environment based on the webpack\nconfiguration, aiming to define sensible defaults for the obfuscator\naccordingly, to reduce the chance of breaking code.\n\nThe plugin assumes that the target is a browser environment if one of the\nfollowing is true:\n\n* `target` key in the webpack configuration is set to either `web` or `webworker`.\n* Either `web` or `webAsync` flag in the `externalsPresets` webpack\n  configuration is set to `true`.\n\nThe plugin assumes that the target is a Node.js environment if one of the\nfollowing is true:\n* `target` key in the webpack configuration is set to `node`.\n* One of the `node`, `electron`, `electronMain`, `electronPreload`,\n  `electronRenderer`, `nwjs` flags in the `externalsPresets` webpack\n  configuration is set to `true`.\n\nIf none of the above conditions are met, before defaulting to `browser` target,\nthe plugin checks if any `browserslist` query is provided in the webpack\nconfiguration. If exists, the plugin evaluates the query to determine the target\nenvironments. If the results contain `node`, the plugin chooses `node` as the\ntarget. Otherwise, the choosen value is `browser`.\n\nThe `target` assumption can be overridden manually if necessary.\n\nHere is an example of how to override the assumptions:\n\n```js\nconst { ObfuscatorPlugin } = require(\"obfuscator-webpack-plugin\");\n\nmodule.exports = {\n  optimization: {\n    minimize: true,\n    minimizer: [\n      new ObfuscatorPlugin({\n        assumptions: {\n          csp: true,\n          hmr: false,\n          nodeEnv: \"production\",\n          target: \"browser-no-eval\",\n        },\n      }),\n    ],\n  },\n};\n```\n\n### Cache\n\nEnabling the cache can reduce build times by reusing the obfuscated code from\nthe previous build. By default, unless the `hmr` assumption is set to `true`,\nthe `cache` option is disabled.\n\n```js\nconst { ObfuscatorPlugin } = require(\"obfuscator-webpack-plugin\");\n\nmodule.exports = {\n  optimization: {\n    minimize: true,\n    minimizer: [\n      new ObfuscatorPlugin({\n        cache: true,\n      }),\n    ],\n  },\n};\n```\n\n### Excluding assets\n\nTo exclude assets from obfuscation, the `exclude` option can be set to an array\nof regular expressions that match the asset names.\n\n```js\nconst { ObfuscatorPlugin } = require(\"obfuscator-webpack-plugin\");\n\nmodule.exports = {\n  optimization: {\n    minimize: true,\n    minimizer: [\n      new ObfuscatorPlugin({\n        exclude: [\n          /\\.no-obfuscation\\.js$/i,\n        ]\n      }),\n    ],\n  },\n};\n```\n\n### Setting up hooks\n\nThe plugin provides custom hooks for customizing the obfuscation process per\nchunk. The `setupHooks` option can be used to register hooks for customizing\nthe process.\n\nThe `setupHooks` function receives two arguments:\n\n- `compilation` (object): The webpack compilation object.\n- `hooks` (object): An object containing the hooks.\n\nThe `hooks` object contains the following properties:\n\n- `preObfuscation`: A tapable hook that is called before obfuscation.\n- `postObfuscation`: A tapable hook that is called after obfuscation.\n- `done`: A tapable hook that is called after all assets are obfuscated.\n\n**Note**: Because of that each compilation will have its own set of hooks,\nthe provided `setupHooks` function will be called for each compilation.\n\nThe following example demonstrates how to use the `setupHooks` option:\n\n```js\nconst { ObfuscatorPlugin } = require(\"obfuscator-webpack-plugin\");\n\nmodule.exports = {\n  optimization: {\n    minimize: true,\n    minimizer: [\n      new ObfuscatorPlugin({\n        setupHooks(\n          compilation,\n          hooks,\n        )\n        {\n          hooks.preObfuscation.tap(\n            // Handler name can be anything,\n            // just keep it unique per hook type to avoid conflicts.\n            \"pre-obfuscation-handler-1\",\n            (\n              assetName,\n              obfuscatorOptions,\n            ) =\u003e\n            {\n              // Pre-process the obfuscator options.\n              // E.g., customize them per asset.\n              obfuscatorOptions.renameGlobals = true;\n            },\n          );\n\n          hooks.postObfuscation.tap(\n            \"post-obfuscation-handler-1\",\n            (\n              assetName,\n              source,\n              sharedIdentifierNamesCache,\n            ) =\u003e\n            {\n              // Post-process the obfuscated source.\n            },\n          );\n\n          hooks.done.tap(\n            \"done-handler-1\",\n            (sharedIdentifierNamesCache) =\u003e\n            {\n              // Post-process all the obfuscated assets or shared identifier names cache.\n              // E.g., dump the shared identifier names cache to a file or memory,\n              // then re-use it in the next build by reading it back and passing it\n              // to the plugin.\n              compilation.emitAsset(\n                \"identifier-names-cache.json\",\n                new compilation.compiler.webpack.sources.RawSource(\n                  JSON.stringify(\n                    sharedIdentifierNamesCache,\n                    null,\n                    2,\n                  ),\n                ),\n              );\n            },\n          );\n        },\n      }),\n    ],\n  },\n};\n```\n\n#### Accessing hooks from other plugins\n\n`ObfuscatorPlugin` class provides a public method named as `setupHooks` that\ncan be used to access the hooks from other plugins.\n\nBy design, to avoid memory leaks and other similar issues, the hooks cannot\nbe accessed directly from the plugin instance. Because the hooks are created\nper compilation, and they are not stored in the scope of the plugin instance,\nintentionally. The same is also true for the current compilation object. So,\nit is necessary to pass the current compilation object to the `setupHooks`\nmethod in order to access the corresponding hooks.\n\nFor example, in your plugin's `apply` method, you can access the hooks like\nthis:\n\n```js\napply(\n  compiler,\n)\n{\n  compiler.hooks.compilation.tap(\n    PLUGIN_NAME,\n    (compilation) =\u003e\n    {\n      const obfuscatorPlugin = compilation.options.plugins.find(\n        (plugin) =\u003e\n        {\n          return plugin instanceof ObfuscatorPlugin;\n        },\n      );\n\n      obfuscatorPlugin.setupHooks(\n        compilation,\n        (hooks) =\u003e\n        {\n          // Use the hooks here.\n        },\n      );\n    },\n  );\n}\n```\n\n### Using with other minimizers\n\nThe plugin can be used in conjunction with other minimizers, such as\n[Terser Plugin](https://github.com/webpack-contrib/terser-webpack-plugin).\n\nExample:\n\n```js\nconst { ObfuscatorPlugin } = require(\"obfuscator-webpack-plugin\");\nconst TerserPlugin = require(\"terser-webpack-plugin\");\n\nmodule.exports = {\n  optimization: {\n    minimize: true,\n    minimizer: [\n      new TerserPlugin(),\n      new ObfuscatorPlugin(),\n    ],\n  },\n};\n```\n\n## Examples\n\nThe [`e2e`](e2e) directory in the repository contain sample packages that uses\nthe plugin. As a more sophisticated example,\n[`e2e/apps/nextjs`](e2e/apps/nextjs) basically demonstrates how to use the\nplugin with a [Next.js](https://nextjs.org) application to obfuscate the\nboth server-side and client-side code.\n\n## Troubleshooting\n\nThe plugin may not work out of the box for all projects. If the obfuscator\ncannot obfuscate the code, the plugin cannot do much about it neither.\n\nIf you encounter issues, it could be likely due to the wild nature of the\nobfuscation in a dynamic language like JavaScript. For a solution, you may\nconsider the following steps:\n\n- Tune the obfuscator options to see if that resolves the issue.\n- Write your code in a way that is more obfuscation-friendly.\n- Disable options that are causing the issue.\n\n**Hints**: It is recommended to keep the `renameGlobals` and `renameProperties`\noptions as `false` unless you are sure that the code can handle the renaming\nof the global variables and properties. You may try setting\n`transformObjectKeys` to `true`, since it is less likely to break the code.\n\n## License\n\nThis project is licensed under the\n[MIT License](https://opensource.org/license/mit).\n\nSee the [LICENSE](LICENSE) file for more information.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fertgl%2Fobfuscator-webpack-plugin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fertgl%2Fobfuscator-webpack-plugin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fertgl%2Fobfuscator-webpack-plugin/lists"}