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

Align module exports with webpack #5316

Open
JohnDaly opened this issue Jan 12, 2024 · 16 comments
Open

Align module exports with webpack #5316

JohnDaly opened this issue Jan 12, 2024 · 16 comments
Assignees
Labels
feat New feature or request

Comments

@JohnDaly
Copy link

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 JohnDaly added bug Something isn't working pending triage The issue/PR is currently untouched. labels Jan 12, 2024
@JohnDaly
Copy link
Author

Looks like this is the code that will need to be updated:

Ok(format!("{}: function() {{ return {}; }}", prop, s.1))

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

@hardfist
Copy link
Contributor

try newTreeshaking

@IWANABETHATGUY
Copy link
Contributor

This issue isn't related to tree shaking

@LingyuCoder
Copy link
Collaborator

LingyuCoder commented Jan 13, 2024

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.

@h-a-n-a h-a-n-a removed the pending triage The issue/PR is currently untouched. label Jan 25, 2024
Copy link

stale bot commented Mar 25, 2024

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 stale bot added the stale label Mar 25, 2024
@daveskybet
Copy link

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,
},

Copy link

stale bot commented Jun 2, 2024

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 stale bot added the stale label Jun 2, 2024
@dartess
Copy link

dartess commented Jun 25, 2024

bump

@stale stale bot removed the stale label Jun 25, 2024
@hardfist
Copy link
Contributor

@ahabhgk can you confirm whether it's solved?

@ahabhgk ahabhgk self-assigned this Jun 25, 2024
@isuro
Copy link

isuro commented Jun 27, 2024

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.

@ahabhgk ahabhgk added feat New feature or request and removed bug Something isn't working labels Jul 4, 2024
@ahabhgk
Copy link
Collaborator

ahabhgk commented Jul 4, 2024

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

@isuro
Copy link

isuro commented Jul 12, 2024

I think it may be swc-project/swc#3365

Copy link

stale bot commented Sep 10, 2024

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 stale bot added the stale label Sep 10, 2024
@LingyuCoder
Copy link
Collaborator

bump

@alvinometric
Copy link

Bump from a very eager user of Docusaurus 😁

@victorkirov
Copy link

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 ☹

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feat New feature or request
Projects
None yet
Development

No branches or pull requests