puppeteer / replay

Library that provides an API to replay and stringify recordings created using Chrome DevTools Recorder
Apache License 2.0
1.03k stars 310 forks source link

Large bundle size with webpack #257

Open nickserv opened 2 years ago

nickserv commented 2 years ago

Actual Behavior

I'm making a Chrome recorder extension, and I've noticed the production library bundle was 437KB in my project, which I would consider to be relatively large for a bundle that doesn't need to ship GUI assets. I'm guessing this is due to a combination of Node.js dependencies and Puppeteer not being originally designed for browser usage (since the DOM and Selenium APIs already support browser automation). This issue may also apply to Puppeteer's build, but I wanted to open it here because it's related to the recorder use case.

Steps to Reproduce the Problem

  1. Clone https://gist.github.com/ad7d2641f9b7b8c6012d031edab790c4
  2. npm install
  3. Note the sizes outputted by webpack or on disk

Specifications

OrKoN commented 2 years ago

Hey @nickmccurdy I suspect that you don't require Puppeteer for the extension as we currently only support export extensions? In that case, you can safely exclude Puppeteer (which is an optional peer dependency needed for the replay part) from the bundle. Please see this rollup config https://github.com/cypress-io/cypress-chrome-recorder-extension/blob/main/rollup.config.js#L10 as an example in rollup. I believe a similar configuration should be possible for Webpack. Would that work for your extension?

nickserv commented 2 years ago

Thanks for the helpful tip, I didn't think about that because I was trying to use tree shaking. Do you think it would make sense to publish with "sideEffects": false (which assumes all exported code is pure)?

For anyone else having this issue with webpack, here's the workaround I'm using now:

plugins: [
  new webpack.IgnorePlugin({
    resourceRegExp: /^puppeteer$/,
  })
]
OrKoN commented 2 years ago

@nickmccurdy unfortunately, I am not familiar with "sideEffects": false. Is it webpack-specific? Does it mean that webpack will be able to strip Puppeteer automatically if the runner extensions are not used by our code?

nickserv commented 2 years ago

unfortunately, I am not familiar with "sideEffects": false. Is it webpack-specific?

Yes. It tells webpack that an entire package's code is pure, so that modules can be tree shaked without losing side effects. However, Rollup can tree shake ES modules.

Does it mean that webpack will be able to strip Puppeteer automatically if the runner extensions are not used by our code?

In theory, yes, though that should only be used if the entire package is side effect free. If that's not the case, you can use /*#__PURE__*/ comments on pure code to inform webpack and Rollup that tree shaking that code is safe.

Source: webpack Tree Shaking

OrKoN commented 2 years ago

I gave it a try but it looks it does not work: if I import anything from the replay lib, Webpack decides to import Puppeteer too although Puppeteer is only a dynamic import in the generated ESM code?

nickserv commented 2 years ago

Do you have an example webpack config?

OrKoN commented 2 years ago

@nickmccurdy I used the one you posted in the gist: https://gist.github.com/nickmccurdy/ad7d2641f9b7b8c6012d031edab790c4

nickserv commented 2 years ago

Sorry, got distracted working on other things for the extension.

Adding "sideEffects": false to node_modules/@puppeteer/replay/package.json seems to work, as it results in the main.js bundle being empty. This is closer to what we want, because we told webpack it has no side effects and we aren't using any imports from it. However, this unfortunately still requires installing puppeteer and getting webpack to build it with the fairly large resolve.fallback config.

Does anyone have ideas on how to tree shake away Puppeteer without having to install or configure it?