Browse Source

feat: added tsdown via an internal, easy-to-use wrapper CLI

benduran 1 month ago
parent
commit
ab11a67e6e

+ 1 - 0
packages/build-ts-package/eslint.config.js

@@ -0,0 +1 @@
+export { base as default } from "@cprussin/eslint-config";

+ 27 - 0
packages/build-ts-package/package.json

@@ -0,0 +1,27 @@
+{
+  "private": true,
+  "name": "build-ts-package",
+  "description": "builds a typescript package properly, supporting CommonJS and ESM outputs, as well as TypeScript typing generation",
+  "version": "0.0.0",
+  "bin": "./src/build-ts-package.js",
+  "files": [
+    "src/*"
+  ],
+  "type": "module",
+  "scripts": {
+    "fix:format": "prettier . --write",
+    "start": "tsx ./src/build-ts-package.ts"
+  },
+  "devDependencies": {
+    "@cprussin/eslint-config": "catalog:",
+    "@cprussin/tsconfig": "catalog:",
+    "@types/node": "catalog:",
+    "@types/yargs": "catalog:"
+  },
+  "dependencies": {
+    "tsdown": "^0.15.9",
+    "tsx": "catalog:",
+    "typescript": "catalog:",
+    "yargs": "catalog:"
+  }
+}

+ 135 - 0
packages/build-ts-package/src/build-ts-package.js

@@ -0,0 +1,135 @@
+#!/usr/bin/env node
+
+import fs from "fs/promises";
+import path from "node:path";
+import { build } from "tsdown";
+import createCLI from "yargs";
+import { hideBin } from "yargs/helpers";
+
+/**
+ * returns the path of the found tsconfig file
+ * or uses the provided override, instead,
+ * if it's available
+ *
+ * @param {string} cwd
+ * @param {string | undefined | null} tsconfigOverride
+ */
+async function findTsconfigFile(cwd, tsconfigOverride) {
+  if (tsconfigOverride) {
+    const overridePath = path.isAbsolute(tsconfigOverride)
+      ? tsconfigOverride
+      : path.join(cwd, tsconfigOverride);
+    return overridePath;
+  }
+
+  const locations = [
+    path.join(cwd, "tsconfig.build.json"),
+    path.join(cwd, "tsconfig.json"),
+  ];
+
+  for (const fp of locations) {
+    try {
+      const stat = await fs.stat(fp);
+      if (stat.isFile()) return fp;
+    } catch {}
+  }
+  return null;
+}
+
+/**
+ * builds a typescript package, using tsdown and its Node-friendly API
+ * @returns {Promise<void>}
+ */
+export async function buildTsPackage(argv = process.argv) {
+  const yargs = createCLI(hideBin(argv));
+  const {
+    all,
+    cwd,
+    noCjs,
+    noDts,
+    noEsm,
+    outDir,
+    tsconfig: tsconfigOverride,
+    watch,
+  } = await yargs
+    .scriptName("build-ts-package")
+    .option("all", {
+      default: false,
+      description:
+        "if true, will compile ALL files in your source folder and link them to your package.json. this is only required if you do not have an index.ts or index.tsx entrypoint that exports all of the things you want users to use.",
+      type: "boolean",
+    })
+    .option("cwd", {
+      default: process.cwd(),
+      description: "the CWD to use when building",
+      type: "string",
+    })
+    .option("noCjs", {
+      default: false,
+      description:
+        "if true, will not build the CommonJS variant of this package",
+      type: "boolean",
+    })
+    .option("noDts", {
+      default: false,
+      description: "if set, will not write typescript typings",
+      type: "boolean",
+    })
+    .option("noEsm", {
+      default: false,
+      description: "if true, will not build the ESM variant of this package",
+      type: "boolean",
+    })
+    .option("outDir", {
+      default: "dist",
+      description: "the folder where the built files will be written",
+      type: "string",
+    })
+    .option("tsconfig", {
+      description:
+        "if provided, will explicitly use this tsconfig.json location instead of searching for a tsconfig.build.json or a plain tsconfig.json",
+      type: "string",
+    })
+    .option("watch", {
+      default: false,
+      description:
+        "if set, will automatically watch for any changes to this library and rebuild, making it easier for you to consume changes in the monorepo while doing local development",
+      type: "boolean",
+    })
+    .help().argv;
+
+  const outDirPath = path.isAbsolute(outDir) ? outDir : path.join(cwd, outDir);
+
+  /** @type {import('tsdown').Format} */
+  const format = [noCjs ? undefined : "cjs", noEsm ? undefined : "esm"].filter(
+    (format) => Boolean(format),
+  );
+
+  const tsconfig = await findTsconfigFile(cwd, tsconfigOverride);
+
+  if (!tsconfig) {
+    throw new Error(`unable to build ${cwd} because no tsconfig was found`);
+  }
+
+  await build({
+    dts: !noDts,
+    entry: [
+      "./src/**/*.ts",
+      "./src/**/*.tsx",
+      "!./src/**/*.stories.ts",
+      "!./src/**/*.stories.tsx",
+      "!./src/**/*.stories.mdx", // if you use MDX stories
+    ],
+    exports: all ? { all: true } : true,
+    external: [/\.s?css$/, /\.svg$/],
+    format,
+    outDir: outDirPath,
+    platform: "neutral",
+    plugins: [],
+    tsconfig,
+    unbundle: true,
+    watch,
+  });
+}
+
+await buildTsPackage();

+ 77 - 18
packages/component-library/package.json

@@ -8,22 +8,83 @@
     "pnpm": ">=10.19.0"
   },
   "exports": {
-    "./*": {
-      "types": "./dist/esm/*/index.d.ts",
-      "default": "./dist/esm/*/index.jsx"
-    },
-    "./useData": {
-      "types": "./dist/esm/useData/index.d.ts",
-      "default": "./dist/esm/useData/index.js"
-    },
-    "./useQueryParamsPagination": {
-      "types": "./dist/esm/useQueryParamsPagination/index.d.ts",
-      "default": "./dist/esm/useQueryParamsPagination/index.js"
-    },
-    "./theme": "./dist/esm/theme.scss"
+    "./AppShell": "./dist/AppShell/index.js",
+    "./AppShell/amplitude": "./dist/AppShell/amplitude.js",
+    "./AppShell/body-providers": "./dist/AppShell/body-providers.js",
+    "./AppShell/fonts": "./dist/AppShell/fonts.js",
+    "./AppShell/html-with-lang": "./dist/AppShell/html-with-lang.js",
+    "./AppShell/i18n-provider": "./dist/AppShell/i18n-provider.js",
+    "./AppShell/report-accessibility": "./dist/AppShell/report-accessibility.js",
+    "./AppShell/router-provider": "./dist/AppShell/router-provider.js",
+    "./AppShell/tabs": "./dist/AppShell/tabs.js",
+    "./Badge": "./dist/Badge/index.js",
+    "./Breadcrumbs": "./dist/Breadcrumbs/index.js",
+    "./Button": "./dist/Button/index.js",
+    "./Card": "./dist/Card/index.js",
+    "./compose-providers": "./dist/compose-providers.js",
+    "./CopyButton": "./dist/CopyButton/index.js",
+    "./CrossfadeTabPanels": "./dist/CrossfadeTabPanels/index.js",
+    "./DropdownCaretDown": "./dist/DropdownCaretDown/index.js",
+    "./EntityList": "./dist/EntityList/index.js",
+    "./ErrorPage": "./dist/ErrorPage/index.js",
+    "./Footer": "./dist/Footer/index.js",
+    "./Header": "./dist/Header/index.js",
+    "./Header/theme-switch": "./dist/Header/theme-switch.js",
+    "./InfoBox": "./dist/InfoBox/index.js",
+    "./Link": "./dist/Link/index.js",
+    "./MainNavTabs": "./dist/MainNavTabs/index.js",
+    "./Meter": "./dist/Meter/index.js",
+    "./MobileNavTabs": "./dist/MobileNavTabs/index.js",
+    "./ModalDialog": "./dist/ModalDialog/index.js",
+    "./NoResults": "./dist/NoResults/index.js",
+    "./NotFoundPage": "./dist/NotFoundPage/index.js",
+    "./omit-keys": "./dist/omit-keys.js",
+    "./overlay-visible-context": "./dist/overlay-visible-context.js",
+    "./Paginator": "./dist/Paginator/index.js",
+    "./SearchButton": "./dist/SearchButton/index.js",
+    "./SearchInput": "./dist/SearchInput/index.js",
+    "./Select": "./dist/Select/index.js",
+    "./SingleToggleGroup": "./dist/SingleToggleGroup/index.js",
+    "./Skeleton": "./dist/Skeleton/index.js",
+    "./social-links": "./dist/social-links.js",
+    "./Spinner": "./dist/Spinner/index.js",
+    "./StatCard": "./dist/StatCard/index.js",
+    "./Status": "./dist/Status/index.js",
+    "./Switch": "./dist/Switch/index.js",
+    "./SymbolPairTag": "./dist/SymbolPairTag/index.js",
+    "./Table": "./dist/Table/index.js",
+    "./TableGrid": "./dist/TableGrid/index.js",
+    "./TableGrid/dummy-row-data": "./dist/TableGrid/dummy-row-data.js",
+    "./TableGrid/table-grid-props": "./dist/TableGrid/table-grid-props.js",
+    "./TabList": "./dist/TabList/index.js",
+    "./Term": "./dist/Term/index.js",
+    "./unstyled/Breadcrumbs": "./dist/unstyled/Breadcrumbs/index.js",
+    "./unstyled/Button": "./dist/unstyled/Button/index.js",
+    "./unstyled/Dialog": "./dist/unstyled/Dialog/index.js",
+    "./unstyled/GridList": "./dist/unstyled/GridList/index.js",
+    "./unstyled/Label": "./dist/unstyled/Label/index.js",
+    "./unstyled/Link": "./dist/unstyled/Link/index.js",
+    "./unstyled/ListBox": "./dist/unstyled/ListBox/index.js",
+    "./unstyled/Meter": "./dist/unstyled/Meter/index.js",
+    "./unstyled/Popover": "./dist/unstyled/Popover/index.js",
+    "./unstyled/SearchField": "./dist/unstyled/SearchField/index.js",
+    "./unstyled/Select": "./dist/unstyled/Select/index.js",
+    "./unstyled/Switch": "./dist/unstyled/Switch/index.js",
+    "./unstyled/Table": "./dist/unstyled/Table/index.js",
+    "./unstyled/Tabs": "./dist/unstyled/Tabs/index.js",
+    "./unstyled/TextField": "./dist/unstyled/TextField/index.js",
+    "./unstyled/Toolbar": "./dist/unstyled/Toolbar/index.js",
+    "./use-prefetch": "./dist/use-prefetch.js",
+    "./useAlert": "./dist/useAlert/index.js",
+    "./useData": "./dist/useData/index.js",
+    "./useDrawer": "./dist/useDrawer/index.js",
+    "./useLogger": "./dist/useLogger/index.js",
+    "./useQueryParamsPagination": "./dist/useQueryParamsPagination/index.js",
+    "./Virtualizer": "./dist/Virtualizer/index.js",
+    "./package.json": "./package.json"
   },
   "scripts": {
-    "build": "tshy",
+    "build": "build-ts-package --noCjs",
     "build:declarations": "tsc --project tsconfig.build.json --outDir ./dist/esm",
     "build:scss": "copyfiles -u 1 \"src/**/*.scss\" dist/esm",
     "build:storybook": "storybook build",
@@ -81,6 +142,7 @@
     "@types/react-dom": "catalog:",
     "autoprefixer": "catalog:",
     "babel-plugin-react-compiler": "catalog:",
+    "build-ts-package": "workspace:",
     "copyfiles": "catalog:",
     "css-loader": "catalog:",
     "eslint": "catalog:",
@@ -98,8 +160,5 @@
     "stylelint-config-standard-scss": "catalog:",
     "typescript": "catalog:"
   },
-  "packageManager": "pnpm@10.19.0",
-  "tshy": {
-    "project": "tsconfig.build.json"
-  }
+  "packageManager": "pnpm@10.19.0"
 }

+ 4 - 1
packages/component-library/tsconfig.json

@@ -7,5 +7,8 @@
     ".storybook/**/*.ts",
     ".storybook/**/*.tsx"
   ],
-  "exclude": ["node_modules", "dist"]
+  "exclude": ["node_modules", "dist"],
+  "compilerOptions": {
+    "jsx": "react-jsx"
+  }
 }

File diff suppressed because it is too large
+ 330 - 73
pnpm-lock.yaml


+ 1 - 0
pnpm-workspace.yaml

@@ -126,6 +126,7 @@ catalog:
   lightweight-charts: ^5.0.5
   lucide-react: ^0.487.0
   match-sorter: ^8.1.0
+  minimist: ^1.2.8
   modern-normalize: ^3.0.1
   motion: ^12.9.2
   next: ^15.5.0

+ 2 - 32
turbo.json

@@ -56,9 +56,7 @@
         "//#install:modules",
         "pull:env",
         "^build",
-        "clean",
-        "build:cjs",
-        "build:esm"
+        "clean"
       ],
       "inputs": [
         "$TURBO_DEFAULT$",
@@ -71,39 +69,11 @@
       ],
       "outputs": ["lib/**", "dist/**", ".next/**", "!.next/cache/**"]
     },
-    "build:cjs": {
-      "dependsOn": ["//#install:modules", "^build"],
-      "inputs": [
-        "$TURBO_DEFAULT$",
-        "!README.md",
-        "!**/*.test.*",
-        "!jest.config.js",
-        "!eslint.config.js",
-        "!prettier.config.js",
-        "!vercel.json"
-      ],
-      "outputs": ["dist/cjs/**"]
-    },
-    "build:esm": {
-      "dependsOn": ["//#install:modules", "^build"],
-      "inputs": [
-        "$TURBO_DEFAULT$",
-        "!README.md",
-        "!**/*.test.*",
-        "!jest.config.js",
-        "!eslint.config.js",
-        "!prettier.config.js",
-        "!vercel.json"
-      ],
-      "outputs": ["dist/esm/**"]
-    },
     "build:vercel": {
       "dependsOn": [
         "//#install:modules",
         "pull:env",
-        "^build",
-        "build:cjs",
-        "build:esm"
+        "^build"
       ],
       "inputs": [
         "$TURBO_DEFAULT$",

Some files were not shown because too many files changed in this diff