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

feat(nuxt): allow configuring treeshakeable composables #19383

Merged
merged 21 commits into from Mar 7, 2023

Conversation

harlan-zw
Copy link
Contributor

@harlan-zw harlan-zw commented Mar 2, 2023

πŸ”— Linked issue

Not an issue but to unblock me on #19302

❓ Type of change

  • πŸ“– Documentation (updates to the documentation or readme)
  • 🐞 Bug fix (a non-breaking change that fixes an issue)
  • πŸ‘Œ Enhancement (improving an existing functionality like performance)
  • ✨ New feature (a non-breaking change that adds functionality)
  • ⚠️ Breaking change (fix or feature that would cause existing functionality to change)

πŸ“š Description

Background

Isolating composables to a specific environment is a useful way to optimise bundles. There are many instances of code that only need to run on a single environment that are introduced through modules.

However, there isn't an easy way for modules to opt-in to this treeshaking config.

For example:

  • Unhead - useServerHead, useServerSeoMeta, useServerHeadSafe
  • nuxt-schema-org - useSchemaOrg
  • nuxt-og-image - defineOgImageStatic, defineOgImageDynamic, defineOgImageScreenshot
  • nuxt-simple-robots - defineRobotMeta
  • ...etc

There is currently a way to handle this by wrapping code in env if blocks. This works okay, but it means the function arguments won't be tree-shaken (afaik).

You can wrap the composable call itself but this gets pretty verbose quickly and is not something module authors have control over.

export function useServerLog(input: any) {
  if (process.server) {
    console.log(input)
  }
}
<template lang="ts" setup>
// this is kept in the client build?
useServerLog({
  foo: 'bar'
  bar: 'foo',
  baz: 'bing',
  bong: 'bar',
})
// verbose!
if (process.server) {
  useServerLog({ /* */ })
} 
</template>

Solution

Make the treeShake config extendable by moving it to nuxt config.

πŸ“ Checklist

  • I have linked an issue or discussion.
  • I have updated the documentation accordingly.

@codesandbox
Copy link

codesandbox bot commented Mar 2, 2023

CodeSandbox logoCodeSandbox logoΒ  Open in CodeSandbox Web Editor | VS Code | VS Code Insiders

@antfu
Copy link
Member

antfu commented Mar 3, 2023

Interesting idea! However, I have a few questions:

  • Should we allow both .server and .client functions to explore the same name to have different functions in different env? If so, it might need some changes on the unimport side. (could also lead to problem of function signatures not matched)
  • Note: This will only work with composables when you aren't using their return value. - This pitfall feels a bit too much and may lead to confusion. And honestly might not be that useful as in many cases the return value is important. It was working for Vue because we are tree-shaking mostly the hooks.
  • The side-effects could also lead to confusion, as from a higher view, users would see the imports in .server being executed on the client side. It can be counterintuitive.

In that sense, I think I would push back for the current implementation as I see the trade-off is not worth it. People better use onMounted or if (process.server) or dynamic import to explicitly control the boundary at this moment.

@harlan-zw harlan-zw changed the title feat(nuxt): server/client only composables feat(nuxt): extendable treeShake config Mar 4, 2023
@harlan-zw
Copy link
Contributor Author

harlan-zw commented Mar 4, 2023

Interesting idea! However, I have a few questions:

  • Should we allow both .server and .client functions to explore the same name to have different functions in different env? If so, it might need some changes on the unimport side. (could also lead to problem of function signatures not matched)
  • Note: This will only work with composables when you aren't using their return value. - This pitfall feels a bit too much and may lead to confusion. And honestly might not be that useful as in many cases the return value is important. It was working for Vue because we are tree-shaking mostly the hooks.
  • The side-effects could also lead to confusion, as from a higher view, users would see the imports in .server being executed on the client side. It can be counterintuitive.

In that sense, I think I would push back for the current implementation as I see the trade-off is not worth it. People better use onMounted or if (process.server) or dynamic import to explicitly control the boundary at this moment.

Thanks for the detailed review! Good points

I agree that it could be a useful feature but the limitations open the scope for too many issues. I'd like to see it in Nuxt one day but sounds like some work needs to go into Unimport first.

I've minimised the scope of this PR to only make the treeShake config extendable which I think is more reasonable.

Copy link
Member

@danielroe danielroe left a comment

Choose a reason for hiding this comment

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

Looks great! ❀️

@danielroe
Copy link
Member

Merging so @harlan-zw can go ahead with linked PR. But would particularly appreciate feedback @antfu on the schema change in this PR. If we do end up supporting something like this in unimport down the line, does it give you enough info? (it's in the preset format, so Record<packageName: string, imports: string[]>).

(Happy to change the schema before we release v3.3 if you have any suggestions for improvement.)

@danielroe danielroe changed the title feat(nuxt): extendable treeShake config feat(nuxt): allow configuring treeshakeable composables Mar 7, 2023
@danielroe danielroe merged commit bb61496 into main Mar 7, 2023
@danielroe danielroe deleted the feat/server-client-only-composables branch March 7, 2023 09:30
@danielroe danielroe mentioned this pull request Mar 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants