stencil icon indicating copy to clipboard operation
stencil copied to clipboard

Exclude peer dependencies from bundle size

Open jdnichollsc opened this issue 4 years ago • 8 comments

Stencil version:

@stencil/[email protected]

I'm submitting a:

  • [x] bug report
  • [ ] feature request
  • [ ] support request => Please do not submit support requests here, use one of these channels: https://stencil-worldwide.herokuapp.com/ or https://forum.ionicframework.com/

Current behavior: Peer dependencies are included from bundle size

Expected behavior: Exclude peer dependencies from the bundle of the package. not sure if this is a bug instead, please let me know

Steps to reproduce: Check the issue related here: https://github.com/proyecto26/ion-phaser/issues/18

Related code: Please check the configuration of this stencil component https://github.com/proyecto26/ion-phaser

Other information: There's no guide to fix these types of problems

Thanks in advance for your help!

jdnichollsc avatar Feb 19 '21 02:02 jdnichollsc

Issue related https://github.com/ionic-team/stencil/issues/2512

jdnichollsc avatar Mar 14 '21 23:03 jdnichollsc

I have the same problem, I'm using SortableJS as peer dependency and it goes to the final bundle

luizfilho-hotmart avatar Aug 09 '21 17:08 luizfilho-hotmart

We also have run into this. Seems if anything is imported from another library, even if it is listed as a peerDependency, ends up in the build output as part a dist/node_modules folder.

In our case:

  • We built library "A" with stencil for other developers.
  • Library "B" is also a Stencil project and uses one of library "A"s components as a peer dependency
  • Developers using both libraries end up with library "B"s included library "A" version

I think I would elevate that to bug status. In our case we were able to work around it by removing any library "A" import statements in library "B" and using a CDN reference of library "A" in the index.html test page.

Is there a way to include it for testing and development but exclude it for bundling?

cary-smith avatar Sep 23 '21 21:09 cary-smith

We have a similar problem. Our component library has a peer dependency on the esri-loader library, but it's important that the consuming app be the one to decide which version of esri-loader to include in the build, which is why it is a peer dependency. However, the stencil output includes it, even in the ESM output I see esri-loader-50fa2ebe.js, which is what is loaded by our stencil components, but it can be a different version than is already loaded by the consuming application which can cause problems.

My expectation is that the stencil build output, at least for the ESM build, would not include peerDependencies by default, or at least provide a way to configure the build to exclude them.

tomwayson avatar Dec 31 '21 15:12 tomwayson

In digging a bit further into our Stencil build I discovered that some peerDependencies are included in the build output and others are not. I'm not sure what the criteria is, but I suspect it could be based on size? It seems like some of the larger dependencies are excluded. Whatever it is, it's still not clear to me if this is rollup's default behavior or if it's something that Stencil is configuring.

FWIW - after reading rollup's resolveId() docs I was able able to force specific dependencies to be treated as external by writing a custom rollup plugin inline in the stencil config and adding it to rollupPlugins.before:

// stencil.config.ts

// inline rollup plugin
function externalizeDependenciesPlugin() {
  return {
    name: 'externalize-dependencies',
    resolveId(source) {
      // replace the following regex w/ one that matches the names of dependencies you want to keep external
      if (/^esri-loader/.test(source)) {
        // this tells rollup to treat the module as external
        return false;
      }
      // this tells rollup to perform the default module resolution
      return null;
    }
  };
}

// see: https://stenciljs.com/docs/module-bundling#custom-rollup-plugins
const rollupPlugins = {
  // Plugins injected before rollupNodeResolve()
  before: [
    externalizeDependenciesPlugin()
  ],
}

tomwayson avatar Jan 21 '22 23:01 tomwayson

Hey all, sorry that it took so long for the Stencil team to reply to this issue. It looks like this may be covering similar territory to #3576 and #3226. Given that this has been a pain point for Stencil users, I'm going to label this for inclusion in our backlog and create a task for evaluating what Stencil does now and what it can do in the future.

Thanks for reporting!

alicewriteswrongs avatar Jan 27 '23 14:01 alicewriteswrongs

any progress on this?

yigityuce avatar Feb 10 '25 10:02 yigityuce

hey @yigityuce (anyone else still interested) ... I personally think this is 1/2 a bug and 1/2 intended behaviour :D

The dist output is actually 2 outputs (with variants) in reality:

  1. as a loader to be used directly in a browser < It makes more sense to bundle everything required to make the element work here
  2. as a loader to be used by bundlers < it makes less sense to bundle peer deps here

The dist-custom-element bundle can be used directly in a browser or in a bundler ... so who knows what should happen there.

Stencil aires on the side caution I guess and makes the component work in all situations.

With all that being said - I think the 'official' escape hatch would be to use the rollupConfig in stencil.config.ts:

// stencil.config.ts
...
rollupConfig: {
    inputOptions: {
      external: ['jquery'],
    }
  },
...

I think Stencil should probably always not bundle peer-deps in the dist / bundler output. Whilst it might make sense to be able to tweak rollup's behaviour for dist-custom-elements? e.g.

outputTargets: [
    {
      type: 'dist-custom-elements',
      dir: 'custom-elements',
      rollupConfig: {
        inputOptions: {
          external: ['jquery'],
        }
      },
    },

Anyhoo - please feel free to raise a feature-request with your ideas / thoughts :)

johnjenkins avatar Feb 10 '25 11:02 johnjenkins