Skip to content

Instantly share code, notes, and snippets.

@alesmenzel
Last active August 24, 2019 14:31
Show Gist options
  • Save alesmenzel/fe24e5e05061d860ad3debe2c2793522 to your computer and use it in GitHub Desktop.
Save alesmenzel/fe24e5e05061d860ad3debe2c2793522 to your computer and use it in GitHub Desktop.

Simple removal of debug module

Common usage of the debug module is for development and then disable it in production (usually also have a separate logger for production issues). Thus the code is shipped without a purpose and also it can have some perf. implication. E.g. imagine you log some big object debug('Some big object', JSON.stringify(largeObject). The JSON.stringify runs even if we disable the module, waisting precious resources - the correct usage of the module is to use formatters, e.g debug('Some big object %o', largeObject), but i have rarely seen someone use it. To avoid this common pitfalls, we can remove the debug module from our code completely - saving bundle size and performance.

Example:

https://astexplorer.net/#/gist/1652612fd62624282390aa74883beeb8/9c46a23a73496cea19d550f3a45ee8d335988054

How to use

All 'debug()' will be removed along with the import and initialization

import createDebug from 'debug'
import moment from 'moment'
import lodash from 'lodash'

const debug = createDebug('my:debug:namespace')

debug('Log this message')

function double(value) {
  return value * 2
}

function () {
  debug('in a function')
  return _.map([1,2,3], double)
}

will output:

import moment from 'moment'
import lodash from 'lodash'





function double(value) {
  return value * 2
}

function () {
  
  return _.map([1,2,3], double)
}

AST transformation (babel7)

const state = {}


export default function (babel) {
  const { types: t } = babel;
  
  return {
    name: "ast-transform", // not required
    visitor: {
      ImportDeclaration(path) {
        if (path.node.source.value === "debug") {
          const specifier = path.node.specifiers[0]
          if (specifier.type === "ImportDefaultSpecifier") {
            const importName = specifier.local.name
            state[importName] = true
            path.remove()
          }
        }
      },
      VariableDeclaration(path) {
        const declaration = path.node.declarations[0]
        console.log("in", state, path.node, declaration)
        const refs = path.context.scope.references
        if (declaration.init.type === "CallExpression") {
          if (refs[declaration.init.callee.name]) {
            state[declaration.id.name] = true
            path.remove()
          }
        }
        if (declaration.init.type === "Identifier") {
          if (refs[declaration.init.name]) {
            state[declaration.id.type] = true
            path.remove()
          }
        }
      },
      ExpressionStatement(path) {
        const refs = path.context.scope.references
        const expression = path.node.expression
        if (expression.type === "CallExpression") {
          const callee = path.node.expression && path.node.expression.callee.name
          if (state[callee] && refs[callee]) {
            path.remove()
          }
        }
      }
    }
  };
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment