ionic-team / stencil

A toolchain for building scalable, enterprise-ready component systems on top of TypeScript and Web Component standards. Stencil components can be distributed natively to React, Angular, Vue, and traditional web developers from a single, framework-agnostic codebase.
https://stenciljs.com
Other
12.56k stars 786 forks source link

bug: Building Stencil on prod seems to break the running of 3rd party dependencies like Bootstrap. #6039

Open classicmike opened 1 week ago

classicmike commented 1 week ago

Prerequisites

Stencil Version

4.22.2

Current Behavior

So in our project, we are trying to integrate Bootstrap's JS into our stencil components.

One problem we are experiencing is that when we try to integrate some of Bootstrap's components such as Collapse into stencil, https://getbootstrap.com/docs/5.3/components/collapse/, the animations for showing work fine, but the animations for hiding are non-existent (collapsed element just dissapears).

Funnily enough, my colleague discovered that the problem only happens when stencil builds the library that is using the Bootstrap Collapse in --prod settings. However if the settings are set to --dev, then the animations for showing and hiding collapses work perfectly.

My colleague suspects that there is an issue with perhaps a tree shaking or part of a build process that seems like it removes some of the script calls that are responsible for the animation hiding.

According to him, he thinks that in the collapse class of the Bootstrap JS, there is a method called hide and somewhere down in that hide method, reflow() (See here: https://github.com/twbs/bootstrap/blob/c2a7d686de56f5cdb829c63e1b3849a2c04409d0/js/src/util/index.js#L175) doesn't seem to get called and removed from the final output which is required for the animation.

He says he's not sure if it is rollup or the typescript compiler removing.

Also he's mentioned that rollupConfig.treeshake does not seem like it's working , even when it is set to false.

I've produced a minimum state that will replicate both prod and dev build scenarios.

If it is something in the prod build process that is affecting the output of 3rd party plugins, I fear this could affect others too.

Expected Behaviour

Animations for showing and hiding collapses should work in a similar way as shown on the official Bootstrap documentation's page. https://getbootstrap.com/docs/5.3/components/collapse/

When a collapsible region hides, it should not straight away go to its hidden state (effectively disappearing straight away) and animate.

System Info

System: node 20.11.1
    Platform: darwin (24.1.0)
   CPU Model: Apple M2 Pro (10 cpus)
    Compiler: /Users/michaeltran/Documents/prototype/stencil-bs-collapse-modules-bug/node_modules/@stencil/core/compiler/stencil.js
       Build: 1729874537
     Stencil: 4.22.2 🎺
  TypeScript: 5.5.4
      Rollup: 2.56.3
      Parse5: 7.1.2
      jQuery: 4.0.0-pre
      Terser: 5.31.1

Steps to Reproduce

  1. Clone the following repo: https://github.com/classicmike/stencil-bs-collapse-modules-bug.git
  2. Run npm install to install the required depenencies
  3. Run npm run start:dev to see the expected working behaviour in building in --dev mode. The collapses should animate in both showing and hiding state
  4. Kill and Run npm run start to see the buggy behaviour in building in --prod mode. The collapses now will not animate in hide mode.

Code Reproduction URL

https://github.com/classicmike/stencil-bs-collapse-modules-bug.git

Additional Information

No response

classicmike commented 4 days ago

Further update: My colleague has been looking at the stencil codebase and he seems to think there is an issue with the treeshaking configuration handling, that's possibly affecting the output and ultimately the behaviour of our integrated bootstrap collapse in production settings. It seems like there is no way to disable it completely or customise that particular config.

Key Findings:

Tree-Shake Configuration in Source Code: bundle-output.ts, Line 170:

In Line 170, the treeshake option should theoretically disable tree-shaking when set to false. However, this configuration doesn't seem to work as expected. Even when treeshake is explicitly set to false, it is not properly reflected, causing issues downstream.

Validation Process in validate-rollup-config.ts Source Code: validate-rollup-config.ts, Line 29:

On Line 29, the treeshake property is extracted during configuration validation. This appears normal at first glance but is impacted by the custom pluck method.

Custom pluck Method in helpers.ts Source Code: helpers.ts, Line 185:

The method at Line 185 checks if (obj[key]), which fails when treeshake is false. This results in treeshake not being applied correctly.

He has suggested to either update this check to if (isDefined(obj[key])), ensuring even false values are recognized.

OR

To make tree-shaking more customizable, the relevant snippet in bundle-output.ts (Line 170) Source Code: bundle-output.ts, Line 170 could be updated as follows:

const treeshake =
  isObject(config.rollupConfig.inputOptions.treeshake)
    ? {
        propertyReadSideEffects: false,
        tryCatchDeoptimization: false,
        ...config.rollupConfig.inputOptions.treeshake,
      }
    : config.rollupConfig.inputOptions.treeshake;

Again I don't know how much this will help you but I thought if offering this detail would assist that would be great.

Thanks.