Search code examples
javascriptbabeljsreact-spring

Can I control function inlining? Babel is causing "Cannot access [variable] before initialization"


Babel is causing me to have a "Cannot access [variable] before initialization" error that is being caused by how babel is transpiling the following two functions:

function dangerousStyleValue(name: string, value: Value) {
  if (value == null || typeof value === 'boolean' || value === '') return ''
  if (
    typeof value === 'number' &&
    value !== 0 &&
    !isCustomPropRE.test(name) &&
    !(isUnitlessNumber.hasOwnProperty(name) && isUnitlessNumber[name])
  )
    return value + 'px'
  // Presumes implicit 'px' suffix for unitless numbers
  return ('' + value).trim()
}

export function applyAnimatedValues(instance: Instance, props: Lookup) {
  if (!instance.nodeType || !instance.setAttribute) {
    return false
  }

  const isFilterElement =
    instance.nodeName === 'filter' ||
    (instance.parentNode && instance.parentNode.nodeName === 'filter')

  const { style, children, scrollTop, scrollLeft, ...attributes } = props!

  const values = Object.values(attributes)
  const names = Object.keys(attributes).map(name =>
    isFilterElement || instance.hasAttribute(name)
      ? name
      : attributeCache[name] ||
        (attributeCache[name] = name.replace(
          /([A-Z])/g,
          // Attributes are written in dash case
          n => '-' + n.toLowerCase()
        ))
  )

  if (children !== void 0) {
    instance.textContent = children
  }

  // Apply CSS styles
  for (let name in style) {
    if (style.hasOwnProperty(name)) {
      const value = dangerousStyleValue(name, style[name])
      if (name === 'float') name = 'cssFloat'
      else if (isCustomPropRE.test(name)) {
        instance.style.setProperty(name, value)
      } else {
        instance.style[name] = value
      }
    }
  }

  // Apply DOM attributes
  names.forEach((name, i) => {
    instance.setAttribute(name, values[i])
  })

  if (scrollTop !== void 0) {
    instance.scrollTop = scrollTop
  }
  if (scrollLeft !== void 0) {
    instance.scrollLeft = scrollLeft
  }
}

The transpiled output is:

applyAnimatedValues: function(e, t) {
        if (!e.nodeType || !e.setAttribute) return !1;
        const n = "filter" === e.nodeName || e.parentNode && "filter" === e.parentNode.nodeName,
            r = t,
            {
                style: o,
                children: i,
                scrollTop: a,
                scrollLeft: d
            } = r,
            p = u(r, s),
            h = Object.values(p),
            v = Object.keys(p).map(t => n || e.hasAttribute(t) ? t : c[t] || (c[t] = t.replace(/([A-Z])/g, e => "-" + e.toLowerCase())));
        void 0 !== i && (e.textContent = i);
        for (let u in o)
            if (o.hasOwnProperty(u)) {
                const t = null == (t = o[u = u]) || "boolean" === typeof t || "" === t ? "" : "number" !== typeof t || 0 === t || l.test(u) || f.hasOwnProperty(u) && f[u] ? ("" + t).trim() : t + "px";
                "float" === u ? u = "cssFloat" : l.test(u) ? e.style.setProperty(u, t) : e.style[u] = t
            }
        var m, g;
        v.forEach((t, n) => {
            e.setAttribute(t, h[n])
        }), void 0 !== a && (e.scrollTop = a), void 0 !== d && (e.scrollLeft = d)

I'm getting this error:

javascript error cant access variable before initialization

As far as I can tell, it is coming from the inlined version of the dangerousStyleValue function:

const t = null == (t = o[u = u]) || "boolean" === typeof t || "" === t ? "" : "number" !== typeof t || 0 === t || l.test(u) || f.hasOwnProperty(u) && f[u] ? ("" + t).trim() : t + "px";
                "float" === u ? u = "cssFloat" : l.test(u) ? e.style.setProperty(u, t) : e.style[u] = t

I believe this is being caused by my babel configuration, which is:

{
    const babelLoader = environment.loaders.get('babel');
    const babelLoaderUsed = babelLoader.use.find(
      (el) => el.loader === 'babel-loader'
    );

    babelLoader.test = /\.(js|jsx|ts|tsx)?(\.erb)?$/;

    babelLoader.exclude = /node_modules\/(?!(recoil)\/).*/;
    babelLoaderUsed.options = merge({}, babelLoaderUsed.options, {
      presets: [
        [
          '@babel/preset-env',
          {
            modules: false,
            targets: {
              browsers: ['> 1%', 'IE 11']
            },
            forceAllTransforms: true,
            useBuiltIns: 'entry',
            corejs: {
              version: 2,
              proposals: true
            }
          }
        ],
        '@babel/preset-react',
        '@babel/preset-typescript'
      ],
      plugins: [
        '@babel/plugin-transform-typescript',
        '@babel/plugin-syntax-dynamic-import',
        '@babel/plugin-proposal-object-rest-spread',
        '@babel/plugin-transform-modules-commonjs',
        [
          '@babel/plugin-proposal-class-properties',
          {
            spec: true
          }
        ],
        [
          'module-resolver',
          {
            root: ['./app'],
            alias: {
              assets: './assets'
            }
          }
        ],
        '@babel/plugin-syntax-import-meta',
        '@babel/plugin-proposal-json-strings',
        [
          '@babel/plugin-proposal-decorators',
          {
            legacy: true
          }
        ],
        '@babel/plugin-proposal-function-sent',
        '@babel/plugin-proposal-export-namespace-from',
        '@babel/plugin-proposal-numeric-separator',
        '@babel/plugin-proposal-throw-expressions'
      ]
    });
  }

I don't know what setting I need to change in order to fix how the function is being inlined (or to disable inlining if that is necessary). I do need to support IE11 still, that is very important.


Solution

  • I finally figured out that it was coming from uglifyjs. I turned off inlining and the problem was resolved.