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

fix(react): correctly mark dependencies as external #2479

Merged
merged 4 commits into from
Sep 20, 2024

Conversation

unekinn
Copy link
Contributor

@unekinn unekinn commented Sep 20, 2024

This ensures Accordion works when consumers have enabled tree-shaking.

Because we didn't mark all our dependencies as external,
import "@u-elements/u-details" was tree-shaked when @digdir/designsystemet-react
was used in an application with tree-shaking enabled.

This happened because we bundled several dependencies (including this one)
with our library, and our library has "sideEffects": false, implying that
any side-effect imports that happened within our library folder was safe to remove.

This was fixed by correctly marking all our dependencies as external, in
which case the application's build will correctly identify "@u-elements/u-details"
as having side-effects and thus not not remove the import.

Closes #2477

Copy link

changeset-bot bot commented Sep 20, 2024

🦋 Changeset detected

Latest commit: a5f6ff6

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
@digdir/designsystemet-react Patch
@digdir/designsystemet Patch
@digdir/designsystemet-css Patch
@digdir/designsystemet-theme Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link
Contributor

github-actions bot commented Sep 20, 2024

Preview deployments for this pull request:

Storybook - 20. Sep 2024 - 15:11

Storefront - 20. Sep 2024 - 15:12

Theme - 20. Sep 2024 - 15:12

Copy link
Contributor

github-actions bot commented Sep 20, 2024

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 62.09% 4275 / 6885
🔵 Statements 62.09% 4275 / 6885
🔵 Functions 86.15% 168 / 195
🔵 Branches 75.36% 572 / 759
File CoverageNo changed files found.
Generated in workflow #559

@unekinn unekinn changed the title fix(react): don't tree-shake away u-elements fix(react): don't tree-shake away u-elements Sep 20, 2024
@eirikbacker
Copy link
Contributor

Very nice work <3

@mimarz
Copy link
Collaborator

mimarz commented Sep 20, 2024

Make sure to remove the rollup-plugin-peer-deps-external devDependency from react package.

@mimarz
Copy link
Collaborator

mimarz commented Sep 20, 2024

Unsure about the test app as-is because it introduces a lot of dependencies we need to maintain in the repository, ontop of having its own configs instead extending the existing one.

My experience has always been to have the test-apps seperate to prevent false positives or stuff bleeds over from being a monorepo.

@unekinn unekinn force-pushed the fix/no-tree-shaking-of-u-elements branch 2 times, most recently from 491a9ad to 530cf2a Compare September 20, 2024 11:26
@mimarz
Copy link
Collaborator

mimarz commented Sep 20, 2024

What this really means is that we bundle a copy of the dependencies with our library.

This can cause side effects with duplicate packages for our end-users.

@unekinn
Copy link
Contributor Author

unekinn commented Sep 20, 2024

What this really means is that we bundle a copy of the dependencies with our library.

This can cause side effects with duplicate packages for our end-users.

When we don't mark all our dependencies as external, we get stuff like this in our dist/ output:

import { jsx } from 'react/jsx-runtime';
import { useMergeRefs } from '../../node_modules/@floating-ui/react/dist/floating-ui.react.js';
import { clsx } from '../../node_modules/clsx/dist/lite.js';
import { forwardRef, useState, useRef, useEffect } from 'react';
import '../../node_modules/@u-elements/u-details/dist/u-details.js';

The imports that start with ../../node_modules and the like will refer to our bundled dependencies, while the other imports will refer to the library consumer's installed versions of dependencies.

The side effect of bundling dependencies is that

  1. we take away control of the exact version used by the consuming application,
  2. we increase the likelihood of the consuming application ending up with multiple versions of the same library -- when we don't bundle dependencies, this will only happen when the application's dependency version is incompatible with the semver range of our dependency version, but when we bundle dependencies it will always happen if the consumer also depends on the library (even if the exact same version)
  3. most relevant to the issue at hand: it seems like Vite at least now tree-shakes away side-effectful imports like import '../../node_modules/@u-elements/u-details/dist/u-details.js';, because the bundled dependencies are considered part of our package, and our package.json says "sideEffects": false. Whereas import '@u-elements/u-details/dist/u-details.js'; which is what we get when we correctly mark it as external, will be treated as having side-effects and not tree-shaked away by the vite build in the consuming application.

@mimarz
Copy link
Collaborator

mimarz commented Sep 20, 2024

What this really means is that we bundle a copy of the dependencies with our library.
This can cause side effects with duplicate packages for our end-users.

When we don't mark all our dependencies as external, we get stuff like this in our dist/ output:

import { jsx } from 'react/jsx-runtime';
import { useMergeRefs } from '../../node_modules/@floating-ui/react/dist/floating-ui.react.js';
import { clsx } from '../../node_modules/clsx/dist/lite.js';
import { forwardRef, useState, useRef, useEffect } from 'react';
import '../../node_modules/@u-elements/u-details/dist/u-details.js';

The imports that start with ../../node_modules and the like will refer to our bundled dependencies, while the other imports will refer to the library consumer's installed versions of dependencies.

The side effect of bundling dependencies is that

  1. we take away control of the exact version used by the consuming application,
  2. we increase the likelihood of the consuming application ending up with multiple versions of the same library -- when we don't bundle dependencies, this will only happen when the application's dependency version is incompatible with the semver range of our dependency version, but when we bundle dependencies it will always happen if the consumer also depends on the library (even if the exact same version)
  3. most relevant to the issue at hand: it seems like Vite at least now tree-shakes away side-effectful imports like import '../../node_modules/@u-elements/u-details/dist/u-details.js';, because the bundled dependencies are considered part of our package, and our package.json says "sideEffects": false. Whereas import '@u-elements/u-details/dist/u-details.js'; which is what we get when we correctly mark it as external, will be treated as having side-effects and not tree-shaked away by the vite build in the consuming application.

Jepp, bundling dependencies or having users packagemanager install them via dependencies are both valid approaches. They both have their pros and cons as far as I can remember.

I've experienced problems before with bundling dependencies because downstream a different version was used and they were both patching the same global or some other conflicting stuff I can't remember now. This was 5 years ago, so as long as we keep our bundling to a minimum this should be ok.

My point was just that we don't want to bundle a copy of the dependencies unless absolutely needed 🙈

@unekinn
Copy link
Contributor Author

unekinn commented Sep 20, 2024

as long as we keep our bundling to a minimum this should be ok.

To be clear, what this PR is doing is removing all depenency bundling, not adding more dependencies to the bundle

@unekinn unekinn force-pushed the fix/no-tree-shaking-of-u-elements branch from 2ae461c to 129b846 Compare September 20, 2024 12:25
Copy link
Collaborator

@mimarz mimarz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work!

Good thing you put that guard in so that we avoid this being misconfigured again in the future 😓

Suggest also adding a changeset so we can get a specific entry for this in our prerelease changelog incase we need to backtrack due to some other issue.

@mimarz
Copy link
Collaborator

mimarz commented Sep 20, 2024

Hmm, maybe also update the PR to better reflect the changes done here?

@eirikbacker eirikbacker self-requested a review September 20, 2024 12:47
Copy link
Contributor

@eirikbacker eirikbacker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Superb work 🌟

@unekinn unekinn force-pushed the fix/no-tree-shaking-of-u-elements branch from 129b846 to c19898c Compare September 20, 2024 13:00
@unekinn unekinn changed the title fix(react): don't tree-shake away u-elements fix(react): ensure Accordion works when consumers have enabled tree-shaking Sep 20, 2024
@unekinn unekinn changed the title fix(react): ensure Accordion works when consumers have enabled tree-shaking fix(react): correctly mark dependencies as external Sep 20, 2024
This ensures Accordion works when consumers have enabled tree-shaking.

Because we didn't mark all our dependencies as external,
`import "@u-elements/u-details"` was tree-shaked when `@digdir/designsystemet-react`
was used in an application with tree-shaking enabled.

This happened because we bundled several dependencies (including this one)
with our library, and our library has `"sideEffects": false`, implying that
any side-effect imports that happened within our library folder was safe to remove.

This was fixed by correctly marking all our dependencies as external, in
which case the application's build will correctly identify `"@u-elements/u-details"`
as having side-effects and thus not not remove the import.

Closes #2477
@unekinn unekinn force-pushed the fix/no-tree-shaking-of-u-elements branch from c19898c to a5f6ff6 Compare September 20, 2024 13:09
@unekinn unekinn merged commit 047c9c1 into next Sep 20, 2024
8 checks passed
mimarz pushed a commit that referenced this pull request Sep 20, 2024
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to next, this PR will
be updated.

⚠️⚠️⚠️⚠️⚠️⚠️

`next` is currently in **pre mode** so this branch has prereleases
rather than normal releases. If you want to exit prereleases, run
`changeset pre exit` on `next`.

⚠️⚠️⚠️⚠️⚠️⚠️

# Releases
## @digdir/[email protected]

### Patch Changes

- Textarea: Use `field-sizing: content`
([#2463](#2463))

- ErrorSummary: Rename ErrorSummary.Root to ErrorSummary
([#2437](#2437))

-   Tabs: ([#2448](#2448))

    -   Renames `Tabs.Root` to `Tabs`
    -   Renames `Tabs.Content` to `Tabs.Panel`

- Rename classes from `ds-error-message*` to `ds-validation-message*`
([#2473](#2473))

- Modal: css changes
([#2418](#2418))

- DropdownMenu:
([#2432](#2432))

    -   Rename from `DropdownMenu` to `Dropdown`
    -   Change API and structure
    -   Rename `.Root` to `.Context`
    -   Rename `.Content` to `Dropdown`

- Tabs: css changes
([#2431](#2431))

- ToggleGroup: Rename ToggleGroup.Root to ToggleGroup
([#2424](#2424))

- Badge: Only use single DOM element for rendering
([#2422](#2422))

- Skeleton: Replace Skeleton.Text, Skeleton.Circle and
Skeleton.Rectangle with <Skeleton variant="">
([#2435](#2435))

- Breadcrumbs: Rename `Breadcrumbs.Root` to `Breadcrumbs` and remove
`Breadcrumbs.Nav`
([#2428](#2428))

- HelpText:
([#2438](#2438))

    -   Use Popover API
    -   Remove `portal` prop
    -   Render icon with pseudo element and require aria-label

- Fieldset: Style using css attributes
([#2447](#2447))

## @digdir/[email protected]

### Patch Changes

- Correctly mark dependencies as external. This ensures Accordion works
when consumers have enabled tree-shaking.
([#2479](#2479))

- Button: Remove `type` when `asChild={true}`
([#2472](#2472))

- ErrorSummary: Rename ErrorSummary.Root to ErrorSummary
([#2437](#2437))

-   Tabs: ([#2448](#2448))

    -   Renames `Tabs.Root` to `Tabs`
    -   Renames `Tabs.Content` to `Tabs.Panel`

- Modal: css changes
([#2418](#2418))

- Rename `ErrorMessage` to `ValidationMessage`
([#2473](#2473))

- DropdownMenu:
([#2432](#2432))

    -   Rename from `DropdownMenu` to `Dropdown`
    -   Change API and structure
    -   Rename `.Root` to `.Context`
    -   Rename `.Content` to `Dropdown`

- Tabs: css changes
([#2431](#2431))

- ToggleGroup: Rename ToggleGroup.Root to ToggleGroup
([#2424](#2424))

- Badge: Only use single DOM element for rendering
([#2422](#2422))

- Skeleton: Replace Skeleton.Text, Skeleton.Circle and
Skeleton.Rectangle with <Skeleton variant="">
([#2435](#2435))

- Breadcrumbs: Rename `Breadcrumbs.Root` to `Breadcrumbs` and remove
`Breadcrumbs.Nav`
([#2428](#2428))

- HelpText:
([#2438](#2438))

    -   Use Popover API
    -   Remove `portal` prop
    -   Render icon with pseudo element and require aria-label

- Fieldset: Style using css attributes
([#2447](#2447))

## @digdir/[email protected]



## @digdir/[email protected]

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
@Barsnes Barsnes deleted the fix/no-tree-shaking-of-u-elements branch October 22, 2024 12:54
mimarz pushed a commit that referenced this pull request Feb 21, 2025
This ensures Accordion works when consumers have enabled tree-shaking.

Because we didn't mark all our dependencies as external,
`import "@u-elements/u-details"` was tree-shaked when
`@digdir/designsystemet-react`
was used in an application with tree-shaking enabled.

This happened because we bundled several dependencies (including this one)
with our library, and our library has `"sideEffects": false`, implying that
any side-effect imports that happened within our library folder was safe
to remove.

This was fixed by correctly marking all our dependencies as external, in
which case the application's build will correctly identify `"@u-elements/u-details"`
as having side-effects and thus not not remove the import.

Closes #2477
mimarz pushed a commit that referenced this pull request Feb 21, 2025
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to next, this PR will
be updated.

⚠️⚠️⚠️⚠️⚠️⚠️

`next` is currently in **pre mode** so this branch has prereleases
rather than normal releases. If you want to exit prereleases, run
`changeset pre exit` on `next`.

⚠️⚠️⚠️⚠️⚠️⚠️

# Releases
## @digdir/[email protected]

### Patch Changes

- Textarea: Use `field-sizing: content`
([#2463](#2463))

- ErrorSummary: Rename ErrorSummary.Root to ErrorSummary
([#2437](#2437))

-   Tabs: ([#2448](#2448))

    -   Renames `Tabs.Root` to `Tabs`
    -   Renames `Tabs.Content` to `Tabs.Panel`

- Rename classes from `ds-error-message*` to `ds-validation-message*`
([#2473](#2473))

- Modal: css changes
([#2418](#2418))

- DropdownMenu:
([#2432](#2432))

    -   Rename from `DropdownMenu` to `Dropdown`
    -   Change API and structure
    -   Rename `.Root` to `.Context`
    -   Rename `.Content` to `Dropdown`

- Tabs: css changes
([#2431](#2431))

- ToggleGroup: Rename ToggleGroup.Root to ToggleGroup
([#2424](#2424))

- Badge: Only use single DOM element for rendering
([#2422](#2422))

- Skeleton: Replace Skeleton.Text, Skeleton.Circle and
Skeleton.Rectangle with <Skeleton variant="">
([#2435](#2435))

- Breadcrumbs: Rename `Breadcrumbs.Root` to `Breadcrumbs` and remove
`Breadcrumbs.Nav`
([#2428](#2428))

- HelpText:
([#2438](#2438))

    -   Use Popover API
    -   Remove `portal` prop
    -   Render icon with pseudo element and require aria-label

- Fieldset: Style using css attributes
([#2447](#2447))

## @digdir/[email protected]

### Patch Changes

- Correctly mark dependencies as external. This ensures Accordion works
when consumers have enabled tree-shaking.
([#2479](#2479))

- Button: Remove `type` when `asChild={true}`
([#2472](#2472))

- ErrorSummary: Rename ErrorSummary.Root to ErrorSummary
([#2437](#2437))

-   Tabs: ([#2448](#2448))

    -   Renames `Tabs.Root` to `Tabs`
    -   Renames `Tabs.Content` to `Tabs.Panel`

- Modal: css changes
([#2418](#2418))

- Rename `ErrorMessage` to `ValidationMessage`
([#2473](#2473))

- DropdownMenu:
([#2432](#2432))

    -   Rename from `DropdownMenu` to `Dropdown`
    -   Change API and structure
    -   Rename `.Root` to `.Context`
    -   Rename `.Content` to `Dropdown`

- Tabs: css changes
([#2431](#2431))

- ToggleGroup: Rename ToggleGroup.Root to ToggleGroup
([#2424](#2424))

- Badge: Only use single DOM element for rendering
([#2422](#2422))

- Skeleton: Replace Skeleton.Text, Skeleton.Circle and
Skeleton.Rectangle with <Skeleton variant="">
([#2435](#2435))

- Breadcrumbs: Rename `Breadcrumbs.Root` to `Breadcrumbs` and remove
`Breadcrumbs.Nav`
([#2428](#2428))

- HelpText:
([#2438](#2438))

    -   Use Popover API
    -   Remove `portal` prop
    -   Render icon with pseudo element and require aria-label

- Fieldset: Style using css attributes
([#2447](#2447))

## @digdir/designsystemet@1.0.0-next.34



## @digdir/[email protected]

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Prevent tree-shaking of side-effect imports of @u-elements/*
3 participants