ionic-framework: bug: side effects with reassignment in ionic 6 + webpack, vite

Prerequisites

Ionic Framework Version

  • v4.x
  • v5.x
  • v6.x

Current Behavior

I have an Ionic React v5 app that I upgraded to v6. When I did so and inspected the bundle size:

react-scripts build --stats; webpack-bundle-analyzer build/bundle-stats.json

I noticed that the node-modules bundle is now 3x larger (from ~500 kB to 1.4 MB).

Here’s my Ionic 5 app bundle:

ionic5

And here’s the Ionic 6 bundle:

ionic6-rc3

The only changes between the code for Ionic v5 and v6 are a few lines to update a datetime component, so these builds are basically identical except for the Ionic version.

Expected Behavior

When upgrading to the next major Ionic version, the bundle size should be roughly the same or smaller than the previous version.

I read in the beta announcement that even smaller bundles are coming to Vue first, and then React and Angular, but I didn’t except a massive size increase.

Steps to Reproduce

Update a moderately sized app from v5 to v6.

Code Reproduction URL

No response

Ionic Info

Ionic:

   Ionic CLI       : 6.18.0 (/home/me/.local/lib/node_modules/@ionic/cli)
   Ionic Framework : @ionic/react 6.0.0-rc.3

Capacitor:

   Capacitor CLI      : 3.3.2
   @capacitor/android : 3.3.2
   @capacitor/core    : 3.3.2
   @capacitor/ios     : 3.3.2

Utility:

   cordova-res : 0.15.3
   native-run  : 1.5.0

System:

   NodeJS : v14.16.0 (/usr/local/bin/node)
   npm    : 7.19.1
   OS     : Linux 4.19

Additional Information

No response

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 19 (8 by maintainers)

Commits related to this issue

Most upvoted comments

Relevant change is in Vite 2.7.0-beta.5.

Specifically, these changes in packages/vite/src/node/plugins/resolve.ts:

- // check for deep import, e.g. "my-lib/foo"
- const deepMatch = nestedPath.match(deepImportRE)
-
- const pkgId = deepMatch ? deepMatch[1] || deepMatch[2] : nestedPath
+ const possiblePkgIds: string[] = []
+  for (let prevSlashIndex = -1; ; ) {
+   let slashIndex = nestedPath.indexOf('/', prevSlashIndex + 1)
+   if (slashIndex < 0) {
+     slashIndex = nestedPath.length
+   }
+
+   const part = nestedPath.slice(
+     prevSlashIndex + 1,
+     (prevSlashIndex = slashIndex)
+   )
+   if (!part) {
+      break
+    }
+
+   // Assume path parts with an extension are not package roots, except for the
+   // first path part (since periods are sadly allowed in package names).
+   // At the same time, skip the first path part if it begins with "@"
+   // (since "@foo/bar" should be treated as the top-level path).
+  if (possiblePkgIds.length ? path.extname(part) : part[0] === '@') {
+     continue
+  }
+
+   const possiblePkgId = nestedPath.slice(0, slashIndex)
+   possiblePkgIds.push(possiblePkgId)
+ }
- const pkg = resolvePackageData(pkgId, basedir, options.preserveSymlinks)
+ const pkgId = possiblePkgIds.reverse().find((pkgId) => {
+   pkg = resolvePackageData(pkgId, basedir, options.preserveSymlinks)
+   return pkg
+ })

Removing that reverse() (see second diff) fixes it… Causes these changes:

normal -> reversed

@ionic/core ->   @ionic/core/components
@stencil/core -> @stencil/core/internal/app-data
@stencil/core -> @stencil/core/internal/client
ionicons ->      ionicons/components
ionicons ->      ionicons/icons

Following up on this: This issue is happening due to a bug in Webpack. I have reported the issue here: https://github.com/webpack/webpack/issues/14963

We are investigating potential workarounds and will follow up here when we have more to share.

edit Jan 27 2022: This also impacts Vite. See https://github.com/ionic-team/ionic-framework/issues/24655. We have an experimental fix that seems to resolve this issue. I will update this thread when I have more to share.

Thanks! We identified two issues that are causing treeshaking to not behave as expected.

  1. The framework wrappers we use from Stencil had a sideeffect that caused all components to get pulled in. This was addressed in https://github.com/ionic-team/stencil-ds-output-targets/pull/208 and a fix will be in an upcoming release of Ionic 6.
  2. There is a potential side effect caused by the proxyCustomElement function in Stencil that only affects Webpack 4 (Webpack 5 seems to work fine). This one requires a bit more investigation, but we are working closely with the Stencil team to fix this.

Treeshaking should be fixed for Webpack 5, Vite, Rollup, ES Build, etc users in the next release of Ionic 6. It should be slightly better for Webpack 4 users, but that proxyCustomElement issue will need to be resolved before treeshaking can work as intended. I will keep this open until that second issue is resolved. Thanks!

@liamdebeasi Thank you for explaining