rspack icon indicating copy to clipboard operation
rspack copied to clipboard

Align module exports with webpack

Open JohnDaly opened this issue 1 year ago • 12 comments

System Info

System: OS: macOS 12.4 CPU: (10) arm64 Apple M1 Max Memory: 22.38 GB / 64.00 GB Shell: 5.8.1 - /bin/zsh Binaries: Node: 20.5.0 - ~/Library/Caches/fnm_multishells/61564_1700104358947/bin/node Yarn: 1.22.17 - ~/.yarn/bin/yarn npm: 9.8.0 - ~/Library/Caches/fnm_multishells/61564_1700104358947/bin/npm pnpm: 8.10.5 - ~/Library/Caches/fnm_multishells/61564_1700104358947/bin/pnpm bun: 0.8.1 - ~/.bun/bin/bun Browsers: Chrome: 119.0.6045.105 Safari: 15.5

Details

I've noticed that rspack build artifacts are typically larger than what webpack generates.

One of the contributing factors is how exports are generated.

Example file:

export const variableWithLongNameOne = 'one';
export const variableWithLongNameTwo = 'two';
export const variableWithLongNameThree = 'three';
export const variableWithLongNameFour = 'four';
export const variableWithLongNameFive = 'five';
export const variableWithLongNameSix = 'six';

webpack will generate the following code:

/*!**********************!*\
  !*** ./src/index.js ***!
  \**********************/
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */   variableWithLongNameFive: () => (/* binding */ variableWithLongNameFive),
/* harmony export */   variableWithLongNameFour: () => (/* binding */ variableWithLongNameFour),
/* harmony export */   variableWithLongNameOne: () => (/* binding */ variableWithLongNameOne),
/* harmony export */   variableWithLongNameSix: () => (/* binding */ variableWithLongNameSix),
/* harmony export */   variableWithLongNameThree: () => (/* binding */ variableWithLongNameThree),
/* harmony export */   variableWithLongNameTwo: () => (/* binding */ variableWithLongNameTwo)
/* harmony export */ });
const variableWithLongNameOne = 'one';
const variableWithLongNameTwo = 'two';
const variableWithLongNameThree = 'three';
const variableWithLongNameFour = 'four';
const variableWithLongNameFive = 'five';
const variableWithLongNameSix = 'six';

rspack generates this code:

__webpack_require__.r(__webpack_exports__);
__webpack_require__.d(__webpack_exports__, {
  variableWithLongNameFive: function() { return variableWithLongNameFive; },
  variableWithLongNameFour: function() { return variableWithLongNameFour; },
  variableWithLongNameOne: function() { return variableWithLongNameOne; },
  variableWithLongNameSix: function() { return variableWithLongNameSix; },
  variableWithLongNameThree: function() { return variableWithLongNameThree; },
  variableWithLongNameTwo: function() { return variableWithLongNameTwo; }
});
 const variableWithLongNameOne = 'one';
 const variableWithLongNameTwo = 'two';
 const variableWithLongNameThree = 'three';
 const variableWithLongNameFour = 'four';
 const variableWithLongNameFive = 'five';
 const variableWithLongNameSix = 'six';

When minified, webpack is able to be compressed more, because the export bindings use () => instead of function(){return}

webpack compressed (pretty formatted for readability):

  e.r(o),
    e.d(o, {
      variableWithLongNameFive: () => n,
      variableWithLongNameFour: () => i,
      variableWithLongNameOne: () => r,
      variableWithLongNameSix: () => l,
      variableWithLongNameThree: () => t,
      variableWithLongNameTwo: () => a,
    });
  const r = 'one',
    a = 'two',
    t = 'three',
    i = 'four',
    n = 'five',
    l = 'six';

rspack compressed (pretty formatted for readability):

n.r(r),
          n.d(r, {
            variableWithLongNameFive: function () {
              return a;
            },
            variableWithLongNameFour: function () {
              return u;
            },
            variableWithLongNameOne: function () {
              return t;
            },
            variableWithLongNameSix: function () {
              return f;
            },
            variableWithLongNameThree: function () {
              return i;
            },
            variableWithLongNameTwo: function () {
              return o;
            },
          });
        let t = 'one',
          o = 'two',
          i = 'three',
          u = 'four',
          a = 'five',
          f = 'six';

For modules that contain lots of exports, this causes the size of rspack to grow quite a bit larger than webpack. Aligning with webpack would lead to more optimized bundles

Reproduce link

https://github.com/JohnDaly/rspack-export-alignment-with-webpack/

Reproduce Steps

Compare the output between rspack and webpack and notice that webpack has smaller output

JohnDaly avatar Jan 12 '24 22:01 JohnDaly

Looks like this is the code that will need to be updated: https://github.com/web-infra-dev/rspack/blob/96ae293534f166d08a84810827cf6c554135df33/crates/rspack_core/src/init_fragment.rs#L290

I think this is the equivalent code from Webpack: https://github.com/webpack/webpack/blob/7d3a8880036d8e5410a144f4c4c495b8f0e21d88/lib/dependencies/HarmonyExportInitFragment.js#L153-L156

The format of the bindings (either function() { return .. } or () => (..)) is determined based on if the environment supports arrow functions or not https://github.com/webpack/webpack/blob/7d3a8880036d8e5410a144f4c4c495b8f0e21d88/lib/RuntimeTemplate.js#L133-L137

JohnDaly avatar Jan 12 '24 23:01 JohnDaly

try newTreeshaking

hardfist avatar Jan 13 '24 01:01 hardfist

This issue isn't related to tree shaking

IWANABETHATGUY avatar Jan 13 '24 09:01 IWANABETHATGUY

Need full support of runtime template and output.environment, related to #5013.

It is recommended to use gzip for further compression, so that these duplicate function() {} will not significantly affect the size, because they will be retained as the same substring only once.

LingyuCoder avatar Jan 13 '24 13:01 LingyuCoder

This issue has been automatically marked as stale because it has not had recent activity. If this issue is still affecting you, please leave any comment (for example, "bump"). We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!

stale[bot] avatar Mar 25 '24 04:03 stale[bot]

I'm also coming up against this issue, where arrow functions are being converted to function syntax. I'm using newTreeshaking and target setup using browserslist where all browsers in the list support arrow functions.

If it helps, adding this to the minimiser config forces the keeping of arrow functions, however shouldn't be needed:

compress: {
    ecma: 2015,
    unsafe_arrows: true,
},

daveskybet avatar Apr 03 '24 16:04 daveskybet

This issue has been automatically marked as stale because it has not had recent activity. If this issue is still affecting you, please leave any comment (for example, "bump"). We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!

stale[bot] avatar Jun 02 '24 16:06 stale[bot]

bump

dartess avatar Jun 25 '24 06:06 dartess

@ahabhgk can you confirm whether it's solved?

hardfist avatar Jun 25 '24 06:06 hardfist

I've also seen issues where browserslist config wasn't being respected. To get around it, I have to pass targets to env in the swc loader config directly.

isuro avatar Jun 27 '24 18:06 isuro

I've also seen issues where browserslist config wasn't being respected. To get around it, I have to pass targets to env in the swc loader config directly.

@isuro Do you mean builtin:swc-loader didn't respect the .browserslistrc file? or the runtime code generated by Rspack didn't respect the .browserslistrc file. Would you open an issue and provide a reproduce, it would be very helpful for us to find the potential bug

ahabhgk avatar Jul 04 '24 06:07 ahabhgk

I think it may be https://github.com/swc-project/swc/issues/3365

isuro avatar Jul 12 '24 16:07 isuro

This issue has been automatically marked as stale because it has not had recent activity. If this issue is still affecting you, please leave any comment (for example, "bump"). We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!

stale[bot] avatar Sep 10 '24 17:09 stale[bot]

bump

LingyuCoder avatar Sep 11 '24 03:09 LingyuCoder

Bump from a very eager user of Docusaurus 😁

alvinometric avatar Oct 18 '24 09:10 alvinometric

Bump

Our build increased by quite a bit from webpack without the arrow functions. So much so that the switch is potentially going to be held back due to the artifact size ☹

victorkirov avatar Nov 29 '24 09:11 victorkirov

This issue has been automatically marked as stale because it has not had recent activity. If this issue is still affecting you, please leave any comment (for example, "bump"). We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!

stale[bot] avatar Feb 16 '25 04:02 stale[bot]

@slorber Does docusaurus still need this ?

alvinometric avatar Feb 18 '25 14:02 alvinometric

I think we'd still benefit from this change yes

slorber avatar Feb 18 '25 15:02 slorber

It's fix by https://github.com/web-infra-dev/rspack/pull/9052

GiveMe-A-Name avatar Mar 17 '25 08:03 GiveMe-A-Name