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

Mark shared packages as side effects free #18365

Merged
merged 5 commits into from
May 3, 2023
Merged

Conversation

nickrum
Copy link
Member

@nickrum nickrum commented Apr 28, 2023

API extensions using Typescript import one of the define*() from @directus/extensions-sdk. Rollup's tree-shaking heuristics aren't prefect. So in order for this import to be properly tree-shaken away by rollup, the package from which the function is imported (@directus/utils) must be marked as side effects free. Due to reasons not clear to me, @directus/constants also needs to be marked as side effects free.

This was also present in the old @directus/shared package, so this PR essentially only reverts to the previous behavior.

@nickrum nickrum requested review from a team, br41nslug, Nitwel and azrikahar and removed request for a team April 28, 2023 16:59
@changeset-bot
Copy link

changeset-bot bot commented Apr 28, 2023

🦋 Changeset detected

Latest commit: bb38e4c

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

This PR includes changesets to release 14 packages
Name Type
@directus/constants Patch
@directus/utils Patch
@directus/composables Patch
@directus/exceptions Patch
@directus/app Patch
@directus/api Patch
create-directus-extension Patch
@directus/extensions-sdk Patch
@directus/storage-driver-azure Patch
@directus/storage-driver-cloudinary Patch
@directus/storage-driver-gcs Patch
@directus/storage-driver-local Patch
@directus/storage-driver-s3 Patch
directus 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

@rijkvanzanten
Copy link
Member

@nickrum arent most packages of ours side effect free?

Copy link
Contributor

@azrikahar azrikahar left a comment

Choose a reason for hiding this comment

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

With additional context from #11329, this PR does seems to resolve the inefficient tree shaking when this sideEffects property was not present. Here are some observed outcome:

Sample file used

import { defineEndpoint } from '@directus/extensions-sdk';

export default defineEndpoint((router) => {
	router.get('/', (_req, res) => res.send('Hello, World!'));
});

Before this PR

  • Filesize: 225 kb
  • Code: (omitted since it's a tad large, but I can share it if deemed necessary)

After this PR

  • Filesize: 1 kb
  • Code:
    "use strict";require("axios");var e=e=>{e.get("/",((e,r)=>r.send("Hello, World!")))};module.exports=e;

That being said, @nickrum as seen by the require('axios') in the "After this PR" result, do we want to (or can we?) mark the composables package as sideEffects free as well? As the axios seems to be included due to use-items composable if I'm not mistaken, but it shouldn't be present in this case. A quick test I did by adding sideEffects: false to the composable package seems to make sure the built file turns out to be the following:

"use strict";var e=e=>{e.get("/",((e,l)=>l.send("Hello, World!")))};module.exports=e;

but I'm not sure if that's too naive.

@paescuj
Copy link
Member

paescuj commented May 1, 2023

Rollup's tree-shaking heuristics aren't prefect. So in order for this import to be properly tree-shaken away by rollup, the package from which the function is imported (@directus/utils) must be marked as side effects free. Due to reasons not clear to me, @directus/constants also needs to be marked as side effects free.

I'm pretty sure this is due to the index.ts files where all the "re-exports" happen (see e.g. in constants) since these make it impossible for Rollup to detect if the imported modules are side effect free.

I think the solution here might be to bundle these packages themselves as well, but we could look at that in a later step.

@nickrum arent most packages of ours side effect free?

I'm pretty sure they are and for the moment should be declared as such. For example the composables package as mentioned by @azrikahar

@rijkvanzanten
Copy link
Member

@paescuj thoughts on removing those index files? DX is a tad less nice, but at the same time it makes it super obvious where imports are coming from so maybe it's a win-win?

@paescuj
Copy link
Member

paescuj commented May 1, 2023

@paescuj thoughts on removing those index files? DX is a tad less nice, but at the same time it makes it super obvious where imports are coming from so maybe it's a win-win?

Thought about this as well, but I'm a little put off by the idea of having to update all imports every time we rename or relocate a file (may not happen often, but is definitely a possibility). Also don't know if we really need this, but at the moment we have the control over which modules we actually want to export. If we want to keep this, we would have to explicitly specify all modules to export in the export field of the respective package.json files.

@rijkvanzanten
Copy link
Member

@paescuj thoughts on removing those index files? DX is a tad less nice, but at the same time it makes it super obvious where imports are coming from so maybe it's a win-win?

Thought about this as well, but I'm a little put off by the idea of having to update all imports every time we rename or relocate a file (may not happen often, but is definitely a possibility). Also don't know if we really need this, but at the moment we have the control over which modules we actually want to export. If we want to keep this, we would have to explicitly specify all modules to export in the export field of the respective package.json files.

Yeah now that I'm awake and thinking about this better it's not the right solution. We'd still want people to be able to do things like import { x, y, z } from '@directus/example';, which would require that single entrypoint. That being said, I believe everything is side-effects free

@paescuj
Copy link
Member

paescuj commented May 3, 2023

@paescuj thoughts on removing those index files? DX is a tad less nice, but at the same time it makes it super obvious where imports are coming from so maybe it's a win-win?

Thought about this as well, but I'm a little put off by the idea of having to update all imports every time we rename or relocate a file (may not happen often, but is definitely a possibility). Also don't know if we really need this, but at the moment we have the control over which modules we actually want to export. If we want to keep this, we would have to explicitly specify all modules to export in the export field of the respective package.json files.

Yeah now that I'm awake and thinking about this better it's not the right solution. We'd still want people to be able to do things like import { x, y, z } from '@directus/example';, which would require that single entrypoint. That being said, I believe everything is side-effects free

Yes, I think so too 👍 For now, let's additionally mark @directus/composables as side-effect free and then merge like this.

Edit: And as correctly pointed out by @br41nslug also @directus/execeptions ❤️

@br41nslug br41nslug changed the title Mark the constant and utils packages as side effects free Mark shared packages as side effects free May 3, 2023
@br41nslug br41nslug merged commit 1d7eec9 into main May 3, 2023
6 checks passed
@br41nslug br41nslug deleted the imp/extension-side-effects branch May 3, 2023 12:26
@nickrum
Copy link
Member Author

nickrum commented May 3, 2023

That being said, @nickrum as seen by the require('axios') in the "After this PR" result, do we want to (or can we?) mark the composables package as sideEffects free as well?

That require('axios') was definitely not included when I was testing this. Interesting 🤔
All of the packages which were previously part of shared should be side effects free and can be marked as such (thanks @br41nslug and @paescuj)👍

I'm pretty sure this is due to the index.ts files where all the "re-exports" happen (see e.g. in constants) since these make it impossible for Rollup to detect if the imported modules are side effect free.

Wouldn't that mean that most of the bigger js libraries wouldn't be tree-shakable? AFAIK rollup does treeshaking in multiple passes, one of which specifically includes re-exports, and this little test shows that rollup is perfectly capable of tree-shaking re-exported values.
I suspect this has something to do with zod, which is used in the constants package, as marking every call to zod with /*@__PURE__*/ does seem to make rollup output a clean extension entrypoint.

@paescuj
Copy link
Member

paescuj commented May 3, 2023

Wouldn't that mean that most of the bigger js libraries wouldn't be tree-shakable? AFAIK rollup does treeshaking in multiple passes, one of which specifically includes re-exports, and this little test shows that rollup is perfectly capable of tree-shaking re-exported values.

Yes, I was wondering the same! I just remembered reading that somewhere. Probably the heuristics are much better nowadays. I'm honestly glad if this is not the problem 😄

I suspect this has something to do with zod, which is used in the constants package, as marking every call to zod with /*@__PURE__*/ does seem to make rollup output a clean extension entrypoint.

Yes, this is very likely the case 🕵️ 👍

@rijkvanzanten rijkvanzanten added this to the Next Release milestone May 4, 2023
meditadvisors pushed a commit to ciso360ai/directus-mod that referenced this pull request May 13, 2023
* Mark the constant and utils packages as side effects free

* Add changeset

* mark composables as side effect free

* mark exceptions package as side effects free

* updated changeset

---------

Co-authored-by: Brainslug <tim@brainslug.nl>
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 1, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants