Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dual package hazard #37

Closed
jcbhmr opened this issue May 26, 2023 · 4 comments · Fixed by #87
Closed

Dual package hazard #37

jcbhmr opened this issue May 26, 2023 · 4 comments · Fixed by #87

Comments

@jcbhmr
Copy link
Collaborator

jcbhmr commented May 26, 2023

I hit the dual package hazard! 🤣 Which means there are duplicate functions in my bundle because I use import {} from "is-what" and then one of my dependencies uses require("is-what") 😱

image

https://nodejs.org/api/packages.html#dual-package-hazard
👇 A possible solution as suggested by Node.js docs ☝

image

Then again, this might not be an issue! 😆

@mesqueeb
Copy link
Owner

mesqueeb commented Jun 3, 2023

I had struggled a lot with the export types of my packages in the past, but I finally found a setup that works recently.
The export types I have just fixed in the latest version:
https://arethetypeswrong.github.io/?p=is-what%404.1.10

I think once all packages use the latest version of is-what, dual package hazard should not occur anymore, unless the project set up or any of the dependencies has an issue where it imports both CJS and ESM for some reason. : S So imo this is not really an issue. Sorry!

@mesqueeb mesqueeb closed this as completed Jun 3, 2023
@jcbhmr jcbhmr mentioned this issue Jun 3, 2023
2 tasks
@jcbhmr
Copy link
Collaborator Author

jcbhmr commented Jun 3, 2023

Actually, my problem isn't the types. Its that this library is bundled as two separate duplicate versions: One of CJS and one for ESM when it should probably be just one with the second format just re-exporting the stuff from the "base" version. For example, CJS everything with index.mjs that just exports the cjs stuff.

This is what I'm talking about:
(function () {
  const e = document.createElement('link').relList;
  if (e && e.supports && e.supports('modulepreload')) return;
  for (const r of document.querySelectorAll('link[rel="modulepreload"]')) u(r);
  new MutationObserver((r) => {
    for (const i of r)
      if (i.type === 'childList')
        for (const f of i.addedNodes)
          f.tagName === 'LINK' && f.rel === 'modulepreload' && u(f);
  }).observe(document, { childList: !0, subtree: !0 });
  function n(r) {
    const i = {};
    return (
      r.integrity && (i.integrity = r.integrity),
      r.referrerPolicy && (i.referrerPolicy = r.referrerPolicy),
      r.crossOrigin === 'use-credentials'
        ? (i.credentials = 'include')
        : r.crossOrigin === 'anonymous'
        ? (i.credentials = 'omit')
        : (i.credentials = 'same-origin'),
      i
    );
  }
  function u(r) {
    if (r.ep) return;
    r.ep = !0;
    const i = n(r);
    fetch(r.href, i);
  }
})();
function D(t) {
  if (t.__esModule) return t;
  var e = t.default;
  if (typeof e == 'function') {
    var n = function u() {
      if (this instanceof u) {
        var r = [null];
        r.push.apply(r, arguments);
        var i = Function.bind.apply(e, r);
        return new i();
      }
      return e.apply(this, arguments);
    };
    n.prototype = e.prototype;
  } else n = {};
  return (
    Object.defineProperty(n, '__esModule', { value: !0 }),
    Object.keys(t).forEach(function (u) {
      var r = Object.getOwnPropertyDescriptor(t, u);
      Object.defineProperty(
        n,
        u,
        r.get
          ? r
          : {
              enumerable: !0,
              get: function () {
                return t[u];
              },
            }
      );
    }),
    n
  );
}
var c = {};
function o(t) {
  return Object.prototype.toString.call(t).slice(8, -1);
}
function m(t) {
  return o(t) === 'Undefined';
}
function O(t) {
  return o(t) === 'Null';
}
function g(t) {
  return o(t) !== 'Object'
    ? !1
    : t.constructor === Object && Object.getPrototypeOf(t) === Object.prototype;
}
function B(t) {
  return g(t);
}
function k(t) {
  return g(t) && Object.keys(t).length === 0;
}
function $(t) {
  return o(t) === 'Object';
}
function R(t) {
  return $(t);
}
function U(t) {
  return o(t) === 'Function';
}
function E(t) {
  return o(t) === 'Array';
}
function L(t) {
  return E(t) && t.length === 0;
}
function y(t) {
  return o(t) === 'String';
}
function x(t) {
  return y(t) && t !== '';
}
function V(t) {
  return t === '';
}
function P(t) {
  return o(t) === 'Number' && !isNaN(t);
}
function d(t) {
  return o(t) === 'Boolean';
}
function q(t) {
  return o(t) === 'RegExp';
}
function z(t) {
  return o(t) === 'Map';
}
function I(t) {
  return o(t) === 'WeakMap';
}
function K(t) {
  return o(t) === 'Set';
}
function G(t) {
  return o(t) === 'WeakSet';
}
function w(t) {
  return o(t) === 'Symbol';
}
function H(t) {
  return o(t) === 'Date' && !isNaN(t);
}
function J(t) {
  return o(t) === 'Blob';
}
function Q(t) {
  return o(t) === 'File';
}
function X(t) {
  return o(t) === 'Promise';
}
function Y(t) {
  return o(t) === 'Error';
}
function Z(t) {
  return o(t) === 'Number' && isNaN(t);
}
function C(t) {
  return d(t) || O(t) || m(t) || P(t) || y(t) || w(t);
}
function tt(t) {
  return O(t) || m(t);
}
function et(t, e) {
  if (!(e instanceof Function)) throw new TypeError('Type must be a function');
  if (!Object.prototype.hasOwnProperty.call(e, 'prototype'))
    throw new TypeError('Type is not a class');
  var n = e.name;
  return o(t) === n || !!(t && t.constructor === e);
}
const nt = Object.freeze(
    Object.defineProperty(
      {
        __proto__: null,
        getType: o,
        isAnyObject: $,
        isArray: E,
        isBlob: J,
        isBoolean: d,
        isDate: H,
        isEmptyArray: L,
        isEmptyObject: k,
        isEmptyString: V,
        isError: Y,
        isFile: Q,
        isFullString: x,
        isFunction: U,
        isMap: z,
        isNaNValue: Z,
        isNull: O,
        isNullOrUndefined: tt,
        isNumber: P,
        isObject: B,
        isObjectLike: R,
        isPlainObject: g,
        isPrimitive: C,
        isPromise: X,
        isRegExp: q,
        isSet: K,
        isString: y,
        isSymbol: w,
        isType: et,
        isUndefined: m,
        isWeakMap: I,
        isWeakSet: G,
      },
      Symbol.toStringTag,
      { value: 'Module' }
    )
  ),
  rt = D(nt);
Object.defineProperty(c, '__esModule', { value: !0 });
c.fixEmptyStrings =
  c.transformRawDataMap =
  c.transformRawData =
  c.omitWithoutFunctions =
  c.iterateApi =
  c.cleanObject =
    void 0;
const l = rt;
function F(t) {
  const e = {};
  return (
    Object.keys(t).forEach((n) => {
      const u = t[n];
      !l.isNull(u) && !l.isUndefined(u) && !l.isString(u) && (e[n] = u);
    }),
    e
  );
}
c.cleanObject = F;
async function it(t, e, n, u) {
  let r;
  const i = [],
    f = Math.min(100, e);
  for (; e < 0 || i.length < e; ) {
    const W = F({ ...n, after: r, first: f }),
      p = await t.get(u, { searchParams: W }).json();
    if ((i.push(...p.data), (r = p.pagination.cursor), p.data.length < f))
      break;
  }
  return e > 0 ? i.slice(0, e) : i;
}
c.iterateApi = it;
function ut(t, e) {
  return Object.keys(t)
    .filter((n) => !l.isFunction(t[n]))
    .filter((n) => !e.includes(n))
    .reduce((n, u) => ((n[u] = t[u]), n), {});
}
c.omitWithoutFunctions = ut;
function ot(t, e) {
  return (n) => new t(n, e);
}
c.transformRawData = ot;
function st(t, e) {
  return (n) => n.map((u) => new t(u, e));
}
c.transformRawDataMap = st;
function ct(t) {
  return t === '' || t === void 0 ? null : t;
}
c.fixEmptyStrings = ct;
function s(t) {
  return Object.prototype.toString.call(t).slice(8, -1);
}
function j(t) {
  return s(t) === 'Undefined';
}
function N(t) {
  return s(t) === 'Null';
}
function a(t) {
  if (s(t) !== 'Object') return !1;
  const e = Object.getPrototypeOf(t);
  return !!e && e.constructor === Object && e === Object.prototype;
}
function ft(t) {
  return a(t);
}
function lt(t) {
  return a(t) && Object.keys(t).length === 0;
}
function at(t) {
  return a(t) && Object.keys(t).length > 0;
}
function M(t) {
  return s(t) === 'Object';
}
function bt(t) {
  return M(t);
}
function pt(t) {
  return typeof t == 'function';
}
function S(t) {
  return s(t) === 'Array';
}
function mt(t) {
  return S(t) && t.length > 0;
}
function Ot(t) {
  return S(t) && t.length === 0;
}
function h(t) {
  return s(t) === 'String';
}
function gt(t) {
  return h(t) && t !== '';
}
function yt(t) {
  return t === '';
}
function b(t) {
  return s(t) === 'Number' && !isNaN(t);
}
function jt(t) {
  return b(t) && t > 0;
}
function Nt(t) {
  return b(t) && t < 0;
}
function A(t) {
  return s(t) === 'Boolean';
}
function St(t) {
  return s(t) === 'RegExp';
}
function ht(t) {
  return s(t) === 'Map';
}
function $t(t) {
  return s(t) === 'WeakMap';
}
function Et(t) {
  return s(t) === 'Set';
}
function Pt(t) {
  return s(t) === 'WeakSet';
}
function _(t) {
  return s(t) === 'Symbol';
}
function dt(t) {
  return s(t) === 'Date' && !isNaN(t);
}
function wt(t) {
  return s(t) === 'Blob';
}
function Ft(t) {
  return s(t) === 'File';
}
function Mt(t) {
  return s(t) === 'Promise';
}
function At(t) {
  return s(t) === 'Error';
}
function _t(t) {
  return s(t) === 'Number' && isNaN(t);
}
function Tt(t) {
  return A(t) || N(t) || j(t) || b(t) || h(t) || _(t);
}
const vt = T(N, j);
function T(t, e, n, u, r) {
  return (i) => t(i) || e(i) || (!!n && n(i)) || (!!u && u(i)) || (!!r && r(i));
}
function v(t, e) {
  if (!(e instanceof Function)) throw new TypeError('Type must be a function');
  if (!Object.prototype.hasOwnProperty.call(e, 'prototype'))
    throw new TypeError('Type is not a class');
  const n = e.name;
  return s(t) === n || !!(t && t.constructor === e);
}
function Wt(t, e) {
  if (typeof e == 'function') {
    for (let n = t; n; n = Object.getPrototypeOf(n)) if (v(n, e)) return !0;
    return !1;
  } else {
    for (let n = t; n; n = Object.getPrototypeOf(n)) if (s(n) === e) return !0;
    return !1;
  }
}
const Dt = Object.freeze(
  Object.defineProperty(
    {
      __proto__: null,
      getType: s,
      isAnyObject: M,
      isArray: S,
      isBlob: wt,
      isBoolean: A,
      isDate: dt,
      isEmptyArray: Ot,
      isEmptyObject: lt,
      isEmptyString: yt,
      isError: At,
      isFile: Ft,
      isFullArray: mt,
      isFullObject: at,
      isFullString: gt,
      isFunction: pt,
      isInstanceOf: Wt,
      isMap: ht,
      isNaNValue: _t,
      isNegativeNumber: Nt,
      isNull: N,
      isNullOrUndefined: vt,
      isNumber: b,
      isObject: ft,
      isObjectLike: bt,
      isOneOf: T,
      isPlainObject: a,
      isPositiveNumber: jt,
      isPrimitive: Tt,
      isPromise: Mt,
      isRegExp: St,
      isSet: Et,
      isString: h,
      isSymbol: _,
      isType: v,
      isUndefined: j,
      isWeakMap: $t,
      isWeakSet: Pt,
    },
    Symbol.toStringTag,
    { value: 'Module' }
  )
);
console.log(c);
console.log(Dt);

You can see the demo here: https://stackblitz.com/edit/vitejs-vite-mpcory?file=vite.config.ts,index.js,dist%2Fassets%2Findex-27addc3e.js&terminal=dev

Note that that demo has TWO DUPLICATE versions of the is-what package. THATs the dual package hazard. 🤣

It's caused by Node.js following the require condition and the import condition BOTH and then seeing two different files when those conditions are resolved. Then Vite just takes those and bundles them as two separate things. Ideally they'd both point to a single canonical source with a wrapper ESM or CJS that re-exports the other

Does that make sense as to what my concern is? 🤔

@jcbhmr jcbhmr reopened this Jun 3, 2023
@mesqueeb
Copy link
Owner

mesqueeb commented Jun 3, 2023

@jcbhmr kinda... 🤔 😅 well i'm open to jump on the ESM only wagon soonish. IF ESM means I don't need to wrack my head in tooling hell anymore, than I'm all for that. I just wanna write beautiful code and not think about how stuff gets bundled tbh. : P

I feel like we can still add a few more functions to the current version, and once everything's stable in a few weeks or so we can do a major ESM only node v16 release.

@jcbhmr
Copy link
Collaborator Author

jcbhmr commented Jun 3, 2023

kinda... 🤔 😅

Let me try again 😆 hopefully this doesn't confuse you more lmao

  1. You compile the code twice: one for MJS and one for CJS.
  2. Packages import either the import condition or the require condition depending on if import {} from "is-what" or const {} = require("is-what").
  3. If you do import in one .mjs file and require() in another .cjs file, you'll import two completely different files with different code.
  4. If one of your dependencies uses require("is-what") they get the require: ... export condition, even if you use import and get the import: ... condition.
  5. When you bundle, your bundler follows the same export rules!
  6. Thus, you get one require() copy and one import copy.

If instead, you do:

// index.mjs
// You can import CJS from MJS, but you CAN'T require() MJS from CJS 😭
export { isArray, isObject } from "./index.cjs"
dist/
  index.mjs
  index.cjs
  isArray.cjs
  isObject.cjs
  ...

Then that fixes it! Now the require and import conditions will map to the same underlying code instead of two duplicate versions of it. Thus, your bundler when it follows the import and require imports will end up with a single canonical source that's just re-exported in the MJS case.

@mesqueeb Does that make it more or less clear? 🤔😂

This was referenced Jun 3, 2023
@mesqueeb mesqueeb mentioned this issue May 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants