question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Minified global var names in conflict with other libraries using iife output format

See original GitHub issue

Describe the bug

Recently I came across an extreme edge case when vite would build and minify my library in iife format, but keep some global variables outside of the main closure. This resulted to one of these minified global vars to be named after ga which resulted to conflict with the actual google analytics library, causing my library to break during runtime.

This is an example of the output javascript I got:

code

My vite configuration is similar to the following one:

import path from "path";
import minifyHTML from "rollup-plugin-minify-html-literals";
import { defineConfig } from "vite";
import eslintPlugin from "vite-plugin-eslint";

export default defineConfig(() => {
  return {
    build: {
      outDir: "dist",
      emptyOutDir: false,
      sourcemap: "hidden",
      lib: {
        name: "MyLibrary",
        entry: path.resolve(__dirname, "MyLibrary/index.ts"),
        formats: ["iife"],
        fileName: () => "my-library.js",
      },
    },
    plugins: [eslintPlugin(), minifyHTML()],
  };
});

Expected behaviour

I would expect that globally defined variables that are part of my distributable code should be enclosed in the main closure when in iife format, to avoid such issues.

Temporary solution

What I’ve done to “hack” this for now and avoid any potential issues is that after my build finishes I run a custom node script which wraps the output javascript file in a closure likewise:

import fs from "fs";
import glob from "glob";
import path from "path";

const ENCODING = "utf8";
const outDir = path.resolve(__dirname, "../dist");

const searchFor = `${outDir}/my-library.js`;

function closurify(content: string) {
  return `(function(){${content}})();`; // do the hack
}

glob(searchFor, {}, (err, files) => {
  files.forEach((file) => {
    fs.readFile(file, { encoding: ENCODING }, (err, content) => {
      fs.writeFile(
        file,
        closurify(content),
        { encoding: ENCODING, flag: "w" }
      );
    });
  });
});

Reproduction [UPDATED]

https://github.com/thanoskrg/lit-playground

The issue appears when I use spread operator inside index.ts and it can be noticed in the output js on the first line.

System Info

System:
    OS: macOS 11.6
    CPU: (8) x64 Intel(R) Core(TM) i7-4770HQ CPU @ 2.20GHz
    Memory: 35.39 MB / 16.00 GB
    Shell: 5.8 - /bin/zsh
  Binaries:
    Node: 16.13.0 - ~/.nvm/versions/node/v16.13.0/bin/node
    Yarn: 1.22.17 - ~/.nvm/versions/node/v16.13.0/bin/yarn
    npm: 8.1.0 - ~/.nvm/versions/node/v16.13.0/bin/npm
  Browsers:
    Chrome: 98.0.4758.109
    Firefox: 97.0.1
    Safari: 14.1.2
  npmPackages:
    vite: ^2.8.0 => 2.8.0

Used Package Manager

npm

Logs

No response

Validations

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:3
  • Comments:12 (6 by maintainers)

github_iconTop GitHub Comments

2reactions
pd4d10commented, Apr 3, 2022

These seem to be the helper functions introduced by esbuild:

var __defProp = Object.defineProperty;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
  for (var prop in b || (b = {}))
    if (__hasOwnProp.call(b, prop))
      __defNormalProp(a, prop, b[prop]);
  if (__getOwnPropSymbols)
    for (var prop of __getOwnPropSymbols(b)) {
      if (__propIsEnum.call(b, prop))
        __defNormalProp(a, prop, b[prop]);
    }
  return a;
};
1reaction
patak-devcommented, Apr 28, 2022

What do you think about injecting the esbuild helpers by hand inside the iife after esbuild is done when this is the target? Something like this could work:

res = res.replace(
  /(.*)(var [^\s]+=function\(r\){"use strict";)(.*)/,
  (match, p1, p2, p3) => p2 + p1 + p3
);

Maybe it is good enough? I can’t think of another fix that doesn’t involve other options in esbuild here

Read more comments on GitHub >

github_iconTop Results From Across the Web

window.once name conflict with other third party script - Drupal
This iife version exposes a global variable named "once", making window.once the entrypoint of the functionality, this is the version drupal ...
Read more >
API - ESBuild
This sets the output format for the generated JavaScript files. There are currently three possible values that can be configured: iife , cjs...
Read more >
Global and Local variables in JavaScript - GeeksforGeeks
In general, it's better to pass local variables from one function to another as parameters than it is to use global variables.
Read more >
esbuild global is not defined - You.com | The Search Engine You ...
since react-dates has some dependencies that use global , assuming the ... Now I need a plugin to tell esbuild to include the...
Read more >
Understanding (all) JavaScript module formats and tools
Only 1 global variable is introduced, which is the module name (or ... or transpiled to other formats, including CommonJS/Node.js, ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found