admin管理员组

文章数量:1122832

Problem Statement

Tailwind classes are not being extracted from a particular component even though files is specified under content in tailwind.config.ts

Project Setup

I have 2 projects. Lets call them project A and B. Project A is a common design UI component library, where I am building and exporting components that are then consumed by other projects such as project B.

Dependencies of project A

  • Next.js
  • Tailwind
  • Storybook
  • Radix

Dependencies of project B

  • Next.js
  • Tailwind
  • Project A

Problem Details

I am using tailwindcss dependency to pre-compile the css before exporting project A so that project B can use it out of the box.

However when I run "build:css": "npx tailwindcss -c tailwind.config.ts -i ./src/app/globals.css -o ./dist/styles.css" certain classes from a particular component called nl-header.tsx is not being exported properly.

In particular the responsive classes like lg:col-span-3 and lg:col-span-3 are not being compiled. I know this because I can see the compiled styles.css and lg:col-span-3 and lg:col-span-3 are missing.

I also want to add, all the other classes from all other components are working perfectly, just this component is acting wonky.

I have shared the code for the nl-header.tsx and the resultant styles.css are mentioned below.

I know this is exactly the issue because when I include the project A package within the content of the consuming project which is project B the issues go away

  content: [
    "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
    "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
    "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
    // "./node_modules/@name-of-package/common-design-system/src/components/header/nl-header.tsx",
    // When I un-comment above line the styles and responsive classes work perfectly
    // because tailwind is able to identify the classes, but it also shows
    // that they are exported by project A
  ],

Project Setup Details

Lets dive in the details of Project A Folder structure looks like this

.
├── README.md
├── components.json
├── dist
│   ├── index.d.mts
│   ├── index.d.ts
│   ├── index.js
│   ├── index.js.map
│   ├── index.mjs
│   ├── index.mjs.map
│   └── styles.css
├── next-env.d.ts
├── next.config.mjs
├── package-lock.json
├── package.json
├── postcss.config.mjs
├── scripts
├── src
│   ├── Configure.mdx
│   ├── app
│   │   ├── globals.css
│   │   ├── layout.tsx
│   │   └── page.tsx
│   ├── components
│   │   ├── filter
│   │   │   ├── nl-filter.stories.tsx
│   │   │   └── nl-filter.tsx
│   │   ├── header
│   │   │   ├── nl-header.stories.tsx
│   │   │   └── nl-header.tsx
│   │   ├── loading
│   │   │   ├── nl-loading.stories.tsx
│   │   │   └── nl-loading.tsx
│   │   ├── news
│   │   │   ├── ...
│   │   │   ├── ...
│   │   │   ├── ...
│   │   │   └── ...
│   │   ├── primitives
│   │   │   ├── ...
│   │   │   ├── ...
│   │   │   ├── ...
│   │   │   └── ...
│   │   ├── sidebar
│   │   │   ├── ...
│   │   │   ├── ...
│   │   │   ├── ...
│   │   │   └── ...
│   │   ├── tab
│   │   │   ├── nl-tab-bar.stories.tsx
│   │   │   └── nl-tab-bar.tsx
│   │   └── typography
│   │       ├── nl-block-quote-tag.stories.tsx
│   │       ├── nl-block-quote-tag.tsx
│   │       └── ...
│   ├── index.ts
│   └── lib
│       └── utils.ts
├── storybook-static
│   ├── sb-addons
│   │   ├── chromatic-com-storybook-9
│   │   ├── essentials-actions-3
│   │   ├── essentials-backgrounds-4
│   │   ├── essentials-controls-2
│   │   ├── essentials-measure-7
│   │   ├── essentials-outline-8
│   │   ├── essentials-toolbars-6
│   │   ├── essentials-viewport-5
│   │   ├── interactions-10
│   │   ├── onboarding-1
│   │   └── storybook-core-core-server-presets-0
│   ├── sb-common-assets
│   ├── sb-manager
│   └── sb-preview
├── tailwind.config.ts
├── tsconfig.json
└── tsup.config.ts

tailwind.config.ts looks like this - I have tried adding classes to the safe list, but it does not work completely (some classes are still missing) and I do not see this is as a scalable solution.

import type { Config } from "tailwindcss";
import tailwindcssAnimate from "tailwindcss-animate";

const config: Config = {
  darkMode: ["class"],
  content: [
    "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
    "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
    "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
    "./.storybook/**/*.{js,ts,jsx,tsx,mdx}",
    "./src/**/*.{js,ts,jsx,tsx,mdx}",
  ],
  theme: {
    extend: {
      colors: {
        background: "hsl(var(--background) / <alpha-value>)",
        foreground: "hsl(var(--foreground) / <alpha-value>)",
        ...
        ...
        ...
        ...
        ...
      },
    },
  },
  plugins: [tailwindcssAnimate],
  safelist: [], // I have tried adding classes here to no avail
};
export default config;

postcss.config.mjs looks like this

/** @type {import('postcss-load-config').Config} */
const config = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
};

export default config;

tsup.config.ts looks like this

// tsup.config.ts
import { defineConfig } from "tsup";

export default defineConfig({
  entry: ["src/index.ts"],
  format: ["cjs", "esm"],
  external: ["react", "react-dom"],
  dts: true, // Enable declaration files
  clean: true,
  splitting: false,
  sourcemap: true,
  minify: false,
  target: "esnext",
});

package.json looks like this, pay special attention to the build and build:css command

{
  "name": "...",
  "version": "0.1.84",
  "private": false,
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "peerDependencies": {
    "react": ">=16.8.0 <19.0.0",
    "react-dom": ">=16.8.0 <19.0.0"
  },
  "files": [
    "dist/",
    "src/",
    "README.md",
    "dist/styles.css"
  ],
  "publishConfig": {
    "registry": "..."
  },
  "scripts": {
    "build:css": "npx tailwindcss -c tailwind.config.ts -i ./src/app/globals.css -o ./dist/styles.css",
    "build": "tsup src/index.ts --format cjs,esm --dts && npm run build:css --external react,react-dom",
    "storybook": "storybook dev -p 6006",
    "build-storybook": "storybook build",
    "prepare": "npm run build",
    "dev": "next dev"
  },

nl-header.tsx looks like this

import React, { useState } from "react";
import * as Select from "@radix-ui/react-select";
import { ChevronDown, ChevronUp, X } from "lucide-react";
import { LargeTextTagNL } from "@/components/typography/nl-large-text-tag";
import * as Avatar from "@radix-ui/react-avatar";
import * as Popover from "@radix-ui/react-popover";
import { MutedTextTagNL } from "../typography/nl-muted-text-tag";

import { NLSideBarItem } from "@/components/sidebar/nl-side-bar-item";
import { NLLogo } from "@/components/primitives/nl-logo";
import * as Dialog from "@radix-ui/react-dialog";
import { Menu } from "lucide-react";
import { H4TagNL } from "@/components/typography/nl-h4-tag";
import { PTagNL } from "@/components/typography/nl-p-tag";

export interface Property {
  id: string;
  name: string;
}

export interface HeaderSideBarElementInterface {
  icon: React.ReactNode;
  title: string;
  onClick: () => void;
}

export interface NLHeaderProps {
  properties: Property[];
  avatarImage?: string;
  firstName: string;
  lastName?: string;
  email: string;
  id: string;
  popoverItems: Array<{ element: React.ReactNode; onClick: () => void }>;
  sideBarElements: HeaderSideBarElementInterface[];
  logoLabel: string;
  version: string;
}

export function NLHeader({
  properties,
  avatarImage,
  firstName,
  lastName,
  email,
  popoverItems,
  logoLabel, // sideBarElements --> START HERE
  sideBarElements,
  version,
}: NLHeaderProps) {
  // SideBar State Variables
  const [dialogOpen, setDialogOpen] = useState(false);
  const [active, setActive] = useState(sideBarElements?.[0]?.title);

  // Header State Variables
  const [currentProperty, setCurrentProperty] = useState(properties[0].name);
  const [isOpen, setIsOpen] = useState(false);

  return (
    <Dialog.Root open={dialogOpen} onOpenChange={setDialogOpen}>
      {/* Mobile View - for the side bar*/}
      <div className="md:hidden">
          ... // This part of the code is working fine
      </div>
      {/* Header */}
      {/* Especially the responsive classes are not working */}
      <div className="grid grid-cols-12 h-[10vh] w-full">
        <div className="col-span-2 lg:hidden flex items-center justify-center"> // These classes are not exporting
          <Dialog.Trigger asChild>
            <button>
              <Menu />
            </button>
          </Dialog.Trigger>
        </div>
        <div className="col-span-5 lg:col-span-9">
          <div className="hidden lg:flex items-center justify-start gap-4 p-5"> // These classes are not exporting
                ...
                ...
          </div>
        </div>
        <div className="col-span-5 lg:col-span-3 flex items-center justify-end gap-4 p-5"> // These classes are not exporting
           ...
           ...
        </div>
      </div>
    </Dialog.Root>
  );
}

Here is the resultant styles.css in the dist folder

Lets also look at the consuming project B briefly to rule out any potential issues there. The setup is similar to the project A. There are the addons:

Importing the styles from the package of project A

import "@name-of-the-package/common-design-system/dist/styles.css"; // Import the design system styles
import "./globals.css";

Here is how the header component is being consumed:

"use client";

import React from "react";
import { useAuth0 } from "@auth0/auth0-react";
import { useEffect, useState } from "react";
import { AppDispatch, RootState } from "@/lib/store";
import { useDispatch, useSelector } from "react-redux";
import { fetchClaims } from "@/lib/redux/authSlice";
// import { setLocaleLang } from "@/lib/redux/localeSlice";

import {
  NLSideBar,
  NLHeader,
  NLFilter,
  NLTabBar,
  H1TagNL,
  NLNewsFeed,
  NLLoading,
} from "@name-of-the-package/common-design-system";
import {
  Calendar,
  CreditCard,
  FileSearch,
  House,
  LogOut,
  Moon,
  Network,
  Newspaper,
  Sun,
  Users,
  Wrench,
} from "lucide-react";
import { useTheme } from "next-themes";

// Create typed hooks for better TypeScript support
const useAppDispatch = () => useDispatch<AppDispatch>();
const useAppSelector = useSelector.withTypes<RootState>();

interface Dictionary {
  HomePage: {
    sideBarItemHomePage: string;
    sideBarItemCommunity: string;
    sideBarItemPolicies: string;
    sideBarItemMaintainance: string;
    sideBarItemPayments: string;
  };
}

interface CustomClaim {
  id: string;
  email: string;
  picture: string;
  firstName: string;
  lastName: string;
  internalRoles: string[];
}

export default function HomePage() {
    ...
    ...
    ...
    ...
    ...
    ...

  // Render dashboard if authenticated
  return (
    <div className="h-screen w-screen">
      <div className="grid grid-cols-1 xl:grid-cols-8">
        {/* Sidebar */}
        <div className="hidden xl:block xl:col-span-1 min-w-fit bg-white dark:bg-slate-800">
          <NLSideBar
            className="px-1.5"
            sideBarElements={sideBarData?.sideBarElements}
            logoLabel={sideBarData?.logoLabel}
            version={sideBarData?.version}
          />
        </div>
        {/* Main content */}
        <div className="col-span-7">
          <div className="h-[10vh] border-red-400 border-4">
            <NLHeader
              id={id}
              popoverItems={popoverItems}
              email={email}
              properties={headerData?.properties}
              avatarImage={headerData?.avatarImage}
              firstName={headerData?.firstName}
              lastName={headerData?.lastName}
              sideBarElements={sideBarData?.sideBarElements}
              logoLabel={sideBarData?.logoLabel}
              version={sideBarData?.version}
            />
          </div>
          <div className="grid grid-cols-1 xl:grid-cols-10 w-full h-[90vh]">
            {/* Filter section */}
            <div className="col-span-1 xl:col-span-2 px-8 pt-5 lg:px-3">
              <NLFilter filters={homeFilters} />
            </div>
            {/* Tab bar section */}
            <div className="col-span-1 xl:col-span-7 px-8 lg:pt-0 flex justify-center">
              <NLTabBar tabBarElements={tabData} />
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

I have read all surrounding dicussions, tried safelist approach, tailwind imports in the globals.css file etc to no avail.

本文标签: