{"id":18421159,"url":"https://github.com/ud-ud/webpack-strip-log-loader","last_synced_at":"2025-07-25T05:40:06.381Z","repository":{"id":32098564,"uuid":"131263506","full_name":"UD-UD/webpack-strip-log-loader","owner":"UD-UD","description":":x::page_facing_up: Removes log (or any specific) module imports and usages","archived":false,"fork":false,"pushed_at":"2022-12-30T18:25:17.000Z","size":4029,"stargazers_count":2,"open_issues_count":24,"forks_count":4,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-04-18T13:23:22.534Z","etag":null,"topics":["typescript","typescript-compiler","webpack","webpack-loader","webpack-loader-strip-code"],"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/UD-UD.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}},"created_at":"2018-04-27T07:44:49.000Z","updated_at":"2019-10-08T10:19:27.000Z","dependencies_parsed_at":"2023-01-14T20:45:35.913Z","dependency_job_id":null,"html_url":"https://github.com/UD-UD/webpack-strip-log-loader","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/UD-UD%2Fwebpack-strip-log-loader","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/UD-UD%2Fwebpack-strip-log-loader/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/UD-UD%2Fwebpack-strip-log-loader/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/UD-UD%2Fwebpack-strip-log-loader/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/UD-UD","download_url":"https://codeload.github.com/UD-UD/webpack-strip-log-loader/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223283256,"owners_count":17119412,"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":["typescript","typescript-compiler","webpack","webpack-loader","webpack-loader-strip-code"],"created_at":"2024-11-06T04:24:35.133Z","updated_at":"2024-11-06T04:24:35.734Z","avatar_url":"https://github.com/UD-UD.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://github.com/webpack/webpack\"\u003e\n    \u003cimg width=\"200\" height=\"200\" src=\"https://webpack.js.org/assets/icon-square-big.svg\"\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\n# webpack-strip-log-loader\n\n[![Travis](https://img.shields.io/travis/bendtherules/webpack-strip-log-loader/master.svg?style=for-the-badge)](https://travis-ci.org/bendtherules/webpack-strip-log-loader)\n[![npm](https://img.shields.io/npm/v/webpack-strip-log-loader.svg?style=for-the-badge)](https://www.npmjs.com/package/webpack-strip-log-loader)\n\nA webpack loader to remove import and other statements containing reference to a module (usually, logger module).\n\n## Use case\n\n_Removing all lines which directly or indirectly reference to a third-party (or, inbuilt) logging module during production build._\n\nFor ex, removing all calls to winston logger or removing all console.\\* statements.\n\nExample 1 :\n\nRemoves logger module and its usage\n\nPre:\n\n```javascript\nimport { Logger, defaultLogger } from \"logger\"; // strip-log\n\nconst myLogger = new Logger({ level: 2 });\n\nvar someInt = 123;\nvar someInt2 = someInt * 2;\n\nmyLogger.debug(someInt);\ndefaultLogger.log(someInt2);\n```\n\nPost:\n\n```javascript\nvar someInt = 123;\nvar someInt2 = someInt * 2;\n```\n\nExample 2 :\n\nRemoves console.\\* usage\n\nPre:\n\n```javascript\nconsole; // strip-log\n\nfunction abc() {\n  var someObj = {};\n\n  console.log(someObj);\n  return someObj;\n}\n```\n\nPost:\n\n```javascript\nfunction abc() {\n  var someObj = {};\n\n  return someObj;\n}\n```\n\nPlease look in the usage and examples section to understand more.\n\n## Getting Started\n\nTo begin, you'll need to install `webpack-strip-log-loader`:\n\n```console\n$ npm install webpack-strip-log-loader --save-dev\n```\n\nThen add the loader to your `webpack` config. For example:\n\n```js\n// webpack.config.js\nconst path = require(\"path\");\n\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.js?$/,\n        use: \"webpack-strip-log-loader\",\n        // Options is optional and should include the module names whose usage (via import/require) will be stripped (in any matching file)\n        options: {\n          modules: [\"remove-module-name\"], // supports glob patterns here\n          matchOptions: {} // optional, same as minimatch options\n        }\n      }\n    ]\n  }\n};\n```\n\nAnd run `webpack` via your preferred method.\n\nNote: We have only tested this with Webpack 3 and 4. For webpack 3, use its corresponding configuration format.\n\n## Terminologies\n\nKnowing some terms will help you in the later section.\n\nWe will first try to show them directly within a pseudo code snippet and then proceed to describe them.\n\n```javascript\n// RS = Restricted symbol\n// RE = Restricted expression\n// RM = Restricted module\n\nimport { Logger, defaultLogger } from \"logger\"; // strip-log\n//      (^ RS ) (^ RS       )       (^ RM  )  (^ Trigger comment)\n\nconsole; // strip-log\n//       (^ Trigger comment)\n\nconst myLogger = new Logger({ level: 2 }); // normal comment\n//   (^ RS   )   (^ RE                )\n\nvar someInt = 123;\nvar someInt2 = someInt * 2;\n\nmyLogger.debug(someInt);\n//(^ RS)\n//(^ RE              )\n\ndefaultLogger.log(someInt2);\n//(^ RS)\n//(^ RE                   )\n```\n\n**Trigger comment** - Comment with special content to mark its associated statement for further scrutiny.\n\n**Restricted module** - Modules whose usage you want to remove. Its content is not changed. Typically, log modules can be marked as restricted.\n\n**Symbol** - Symbols are equivalent to what we think of as variables. Wherever you use the same variable (variable hiding in inner scope creates new variable), you can think of them as the same symbol.\n\n**Restricted symbol** - Restricted symbols are those symbols which either have some dependency on restricted modules or are explicitly marked as restricted. Any statement which uses this symbol will be removed. It is also used to find more related restricted symbols or expressions (for eg. when you assign a different variable/symbol to the value of an already restricted symbol, the assignee symbol also gets marked as restricted).\n\n**Restricted expression** - These are those expressions which have some dependency on other restricted symbols or expressions. For eg. `new abc()` becomes a restricted expression if `abc` is a restricted symbol.\n\n## Usage\n\nTo remove the affected lines during build, there are two phases that you need to care about:\n\n1. Marking symbols as restricted\n2. Using restricted symbols in language constructs\n\n### 1. Marking restricted symbols\n\nThe following types of statements are monitored for finding initial restricted symbols.\n\n#### A. ES6 import and require calls (with strip-log comment)\n\nSide-effect import :\n\n```js\nimport \"some-css\"; // strip-log\n```\n\nDefault import :\n\n```js\nimport logger from \"some-logger\"; // strip-log\n```\n\nNamespace import :\n\n```js\nimport * as logger2 from \"some-logger\"; // strip-log\n```\n\nNamed import :\n\n```js\nimport { log as speak, warn } from \"some-logger\"; // strip-log\n```\n\nRequire statement:\n\n```js\nvar logger = require(\"some-logger\"); // strip-log\n```\n\nNote:\nAfter build, this \"marking\" import / require statements will be removed.\n\n#### B. Explicit symbol(s) marking\n\nRestrict a symbol :\n\n```js\nconsole; // strip-log\n```\n\nRestrict multiple symbols at once :\n\n```js\nconsole1, console2; // strip-log\n```\n\nNote:\nAfter build, this \"marking\" statements will be removed.\n\n#### C. Loader config\n\nIn webpack config file, pass options to this loader in the form of `{modules: string[], matchOptions?: minimatch.IOptions }` where:\n\n1. `modules` is an array of globally restricted module names (globs, matched using minimatch).\n2. `matchOptions`: options object as supported by minimatch (documented in \u003chttps://github.com/isaacs/minimatch#options)\u003e\n\nThis is equivalent to marking all import statements to \"some-logger\" in all files with comment strip-log.\n\n```js\n    module: {\n      rules: [\n        {\n          test: /\\.js$/,\n          use: {\n            loader: 'webpack-strip-log-loader',\n            options: {\n                \"modules\": \"some-logger\"\n            },\n          },\n        },\n      ],\n    },\n```\n\nExample of glob:\nSetting `\"modules\": \"logger-*\"` will remove both statements `import 'logger-1'; import log from 'logger-99';`\n\n### 2. Using restricted symbols in language constructs\n\nFollowing type of language constructs are looped through to find more restricted expression or symbol.\n\n#### A. Function call\n\nPre:\n\n```js\nimport defaultLogger from \"some-logger\"; // strip-log\ndefaultLogger(\"Init\");\n\nsomeOtherFunction();\n```\n\nPost:\n\n```js\nsomeOtherFunction();\n```\n\nThe whole function call expression for `defautLogger` becomes a restricted expression if the function itself is restricted.\n\n#### B. Simple assignment\n\nPre:\n\n```js\nimport defaultLogger from \"some-logger\"; // strip-log\n\nvar logger = defaultLogger;\nvar a = 1; // some other assignment\n\nlogger(\"Init\");\n```\n\nPost:\n\n```js\nvar a = 1; // some other assignment\n```\n\nThe variable/symbol `logger` also becomes restricted as it was assigned to the same value as `defaultLogger`, which is a restricted symbol. Hence, function calls to `logger` would also be marked as restricted expression.\n\n#### C. New call\n\nPre:\n\n```js\nimport Logger from \"some-logger\"; // strip-log\n\nvar someLogger = new Logger({ level: 3 });\nsomeLogger(\"Init\");\n\nvar a = new List(); // some other new call\n```\n\nPost:\n\n```js\nvar a = new List(); // some other new call\n```\n\nThe variable/symbol `someLogger` becomes restricted as it was assigned to the new expression, which becomes restricted as the newee `Logger` symbol is restricted.\n\n#### D. Property access (by dot notation)\n\nPre:\n\n```js\nimport defaultLogger from \"some-logger\"; // strip-log\ndefaultLogger.log(\"Init\");\n\nsomeOtherFunction();\n```\n\nPost:\n\n```js\nsomeOtherFunction();\n```\n\nThe expression `defaultLogger.log` becomes restricted as `defaultLogger` symbol is restricted. Eventually any call with that expression as the callee also becomes restricted as mentioned in previous `Function call` section.\n\nNote: Combinations of this various constructs should work in most cases.\n\n## Removing statements, expressions and comments\n\nAny restricted expression has to get removed during build. But replacing any expression with blank space is dangerous.\n\nConsider the following:\n\nPre:\n\n```js\nimport LogError from \"some-logger\";\n\nthrow new LogError(\"Output stream not found\");\n```\n\nIf we just replaced the restricted new expression with blank, it would look like:\n\nPost:\n\n```js\nimport LogError from 'some-logger';\n\nthrow ;\n```\n\nwhich would be an invalid javascript syntax (as blank is not an expression).\n\nWe could have replaced expressions with `undefined` which would be an appropriate replacement expression (although it might not have _looked_ good ).\nBut instead we have decided to (move up the AST tree from any restricted expression to) find out the its parent statement and remove the complete statement with blank.\n\nRight now, this creates a empty new line for removed statements and **doesn't** remove any comment (if any) on that line.\n\nNote: We have future plans for removing those comments which are used to only restrict symbols or import statements. Other comments should be handled with separate webpack plugins.\n\n## More examples -\n\nExamples showing more complex cases due to mixing of multiple language constructs will be added soon.\n\n## Philosophy \u0026 Approach\n\nUsually, we prefer to keep logs enabled in developemnt build, and supress them in production build.\n\nTypical solution to this is to make the log function calls no-op depending on some environment variable. But with this solution, the function call statements and other log setup statements are still present in the built source code - even though they don't cause anything.\n\nInstead, what if we could completely remove those statements during build by static analysis? That should cause slight performance improvement and cleanup the code a little bit. This was our motivation to build such a webpack plugin.\n\nOur approach is to use Typescript compiler API to parse and understand the source file, then find the variables and expressions which depend on the restricted module and finally remove those occurences with string replacement.\n\nThere are a few _finder_ methods which move through the whole AST to find more restricted symbols and expressions from the existing ones (already identified restricted symbols / expressions). We use multiple passes (each pass calls all the finders sequentially) to find this information. Whenever any of the finders add a new restricted symbol / expression, we do one more pass. When a complete pass doesn't find anything new, finding is considered complete.\n\n## Scope\n\nWe support a few language constructs using finders, which we think are mostly needed to use log modules. We will always try to stay true to our original goals and don't aim to grow this as a generic dependency removal plugin.\n\n## Contributing\n\nContribution is highly welcome from anyone.\nPlease look into the scope before raising a new feature request. Having said that, if you have a use case where we should support more things, please let us know.\n\nWe are eager to help the community by building better tools.\n\n## Publishing to npm\n\nOne-step:\n\nDepending on required version bump, run one of these:\n\n`npm run \u003crelease-patch|release-minor|release-major\u003e`\n\nThese commands are just shortcut for:\n\n1. `npm version \u003cpatch|minor|major\u003e`\n2. `npm publish`\n\n\n`npm version` will internally:\n\n1. run test and build\n2. create version commit and tag\n3. git push with tags\n\n## Thanks\n\nLots of thanks to\n\n* FusionCharts for letting me build this during office hours\n* And my colleagues there for the awesome ideas and feedback regarding this project\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fud-ud%2Fwebpack-strip-log-loader","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fud-ud%2Fwebpack-strip-log-loader","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fud-ud%2Fwebpack-strip-log-loader/lists"}