rslib icon indicating copy to clipboard operation
rslib copied to clipboard

[Feature]: Remove `_webpack_require__.*` + `__webpack_exports__.*` definitions for CJS format in bundleless mode

Open antitoxic opened this issue 1 year ago • 2 comments

What problem does this feature solve?

I am in a similar situation to https://github.com/web-infra-dev/rslib/issues/219. I think it's not the same, so I'm posting a new issue.

From what I know, rsbuild and therefore rslib are reimplementing the webpack algo. And that's cool. What I didn't expect is to use the bundle: false, a.k.a. "bundleless" mode and get a ton of repeated __webpack_require__.* definitions in each file for cjs format.

For example if I get an input file called math.ts with:

export const round = (val: number | null, precision: number = 0) => {
  if (val === null) {
    return Number.NaN;
  }
  const factor = Math.pow(10, precision);

  return Math.round(val * factor) / factor;
};

The bundleless mode of rslib produces ESM output of:

const round = (val, precision = 0)=>{
    if (null === val) return Number.NaN;
    const factor = Math.pow(10, precision);
    return Math.round(val * factor) / factor;
};
export { round };

//# sourceMappingURL=math.mjs.map

Which is fantastic, but the cjs (common js) version of of the same is:

"use strict";
var __webpack_require__ = {};
(()=>{
    __webpack_require__.d = function(exports1, definition) {
        for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
            enumerable: true,
            get: definition[key]
        });
    };
})();
(()=>{
    __webpack_require__.o = function(obj, prop) {
        return Object.prototype.hasOwnProperty.call(obj, prop);
    };
})();
(()=>{
    __webpack_require__.r = function(exports1) {
        if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
            value: 'Module'
        });
        Object.defineProperty(exports1, '__esModule', {
            value: true
        });
    };
})();
var __webpack_exports__ = {};
__webpack_require__.r(__webpack_exports__);
__webpack_require__.d(__webpack_exports__, {
    round: function() {
        return round;
    }
});
const round = (val, precision = 0)=>{
    if (null === val) return Number.NaN;
    const factor = Math.pow(10, precision);
    return Math.round(val * factor) / factor;
};
var __webpack_export_target__ = exports;
for(var __webpack_i__ in __webpack_exports__)__webpack_export_target__[__webpack_i__] = __webpack_exports__[__webpack_i__];
if (__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, '__esModule', {
    value: true
});

//# sourceMappingURL=math.js.map

And that is for every file.

What does the proposed API look like?

No changes of API, changes of output to be more similar to other tools like tsc, rollup, etc.

If this is a fundamental thing for rsbuild and rslib then at least those __webpack_* definitions can be reused and not redefined in every file?

When targetingcjs format, rollup produces:

'use strict';

const round = (val, precision = 0) => {
    if (val === null) {
        return Number.NaN;
    }
    const factor = Math.pow(10, precision);
    return Math.round(val * factor) / factor;
};

exports.round = round;
//# sourceMappingURL=math.cjs.map

When targeting cjs format & configured specifically for node 22 (via tsconfig base), tsc produces:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.round = void 0;
const round = (val, precision = 0) => {
    if (val === null) {
        return Number.NaN;
    }
    const factor = Math.pow(10, precision);
    return Math.round(val * factor) / factor;
};
exports.round = round;

antitoxic avatar Dec 23 '24 13:12 antitoxic

Thank you for the feedback. We are aware that the runtime of webpack is currently quite verbose and has not yet been optimized. The main reasons are:

  • In scenarios where size (using tree shaking) is a concern, CJS is not supported, and we prioritize the quality of ESM outputs.
  • The verbosity of webpack's runtime is due to its better support for more complex scenarios, even though it might seem excessive for smaller, simpler CJS projects.

We can keep this issue open to see if there are opportunities in the future to optimize CJS outputs or the runtime. However, in the near term, this is not on our roadmap.

fi3ework avatar Dec 26 '24 06:12 fi3ework

The verbosity of webpack's runtime is due to its better support for more complex scenarios, even though it might seem excessive for smaller, simpler CJS projects

Even if it doesn't support the complete set of those compatibility guarantees, would it be possible to produce something more akin to the tsc output with a flag? It's unfortunate that the current output makes it so significantly more complex, compared to the module mode, meaning cjs consumers can't even properly apply optimizations with their build tools. Even the minified version of the code still retains long __webpack* strings in it.

johnpyp avatar Feb 19 '25 07:02 johnpyp