#How do ya'll handle 'use client' with Turborepo shared UI libary?

43 messages · Page 1 of 1 (latest)

torpid yew
#

Shared UI library built with tsup.

  • The interactive components have use client.

In my ui/dist/index.js, I get the error:

The "use client" directive must be placed before other expressions. Move it to the top of the file to resolve this issue.

You can see the use client at the top of ui/dist/index.js

"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }"use client"

Since everything bundled together, is it bad that I have use client in my ui library?

Cause at this point no matter which component I use from the shared UI library, I need to wrap it in use client in the consuming app even if there is nothing interactive.

somber lodgeBOT
#

🔎 This post has been indexed in our web forum and will be seen by search engines so other users can find it outside Discord

🕵️ Your user profile is private by default and won't be visible to users outside Discord, if you want to be visible in the web forum you can add the "Public Profile" role in id:customize

✅ You can mark a message as the answer for your post with Right click -> Apps -> Mark Solution
(if you don't see the option, try refreshing Discord with Ctrl + R)

honest badger
#

Tsup is a bundler, it bundles all the components into a file. When you import a button from your ui library, other components like Dialog, Tabs etc. will also be imported and increase your bundle size.

#

I recommend exporting components independently, like ui/button, ui/tabs etc, so that you can only ship required JavaScript to the client

#

Configure the entry options in your tsup config

frail vine
#

this monorepo of mine uses typescript in the utility package and i don't need any build steps for it. transpilePackages then it will just work. forget about tsup and everything

honest badger
#

Maybe he is also publishing the library as a package, then it will be necessary to use a bundler like tsup

torpid yew
#

I really want to consume my ui library like its 3rd party

frail vine
#

yeah if they are publishing a library to be used outside that monorepo, then building is necessary and pretend that my message never existed

#

but, in a monorepo, you don't need to build

#

if you don't intend to use that package elsewhere or publish it to npm

#

you don't need a build step

torpid yew
frail vine
#

and the build step would just be additional manpower and effort for nothing

torpid yew
#

Even if I don't publish, I still like the idea of ui package being treated as standalone.

torpid yew
# honest badger I recommend exporting components independently, like `ui/button`, `ui/tabs` etc,...

My current config in tsup

import { defineConfig, Options } from 'tsup';

export default defineConfig((options: Options) => ({
  banner: {
    js: `"use client"`,
  },
  // treeshake: true,
  splitting: true,
  entry: ['./src/index.ts'],
  format: ['esm', 'cjs'],
  dts: true,
  minify: true,
  clean: true,
  external: ['react'],
  ...options,
}));

So for entry it would be ./src/components/atoms/Button, ./src/components/atoms/Accordion, every other component...

honest badger
#

You can use regex

#

“src/components/*.tsx” is supported

#

Btw remove the banner option if you want to add “use client” manually. Tsup will add the directive if it’s at the top of entry file.

torpid yew
#

what I'm getting now

#

Hm... I'm not getting an index.d.ts at root

#
entry: [
  './src/components/*.tsx',
  './src/hooks/*.{ts,tsx}',
  './src/types/*.ts',
],
honest badger
#

Are you components in “src/components”?

honest badger
torpid yew
torpid yew
#

'./src/components/*/*.tsx'
I don't want to export nested components folder.

honest badger
#

So you will have to create a tsx file under components

torpid yew
#

nice link

#

this is going to take me some time...

honest badger
#

Yeah… tbh refactoring codebase is a boring job xD

torpid yew
#

How do I exlude the nested components folder within a component (in my case Accordion)
I have this './src/components/**/*.tsx',, but it includes everything

#

I just want the top level .tsx

honest badger
#

Just “./src/components/*.tsx”?

#

Or “./src/components/*/*.tsx”

torpid yew
#

Hey, really appreciate your help!

So I ended up getting everything working. Although its unergonomic at this point. I may need to actually manually list my Components in tsup.config.ts to get the import structure I want.

Doesn't seem you can fitler out recursive glob patterns.

How I import something now
import { Button } from 'ui/Button/Button';

#

I really do miss this structure

import {
  Button,
  Accordion,
  Tabs,
} from 'ui';
frail vine
#

Well you can still do that tbf, there’s nothing wrong with client components; the pages router and pre-2023 react are all client components

torpid yew
frail vine
#

Yeah. You have to choose one and discard one, can have them both at the same time

torpid yew
#

this is resolved