Skip to content

Commit d3222a7

Browse files
committed
fix(packaging)!: make the component library consumable outside the monorepo
Restructure @dirac-grid/diracx-web-components packaging so the library works when installed from npm outside this monorepo: - move host-provided packages (react, react-dom, MUI core, emotion, @axa-fr/react-oidc, swr) from dependencies to peerDependencies and mirror them in devDependencies for local dev/test - add a proper exports map with a root "." entry (types-first) plus a new ./services entry; add sideEffects: false and engines.node >= 22 - drop the legacy src/{components,contexts,hooks,types}/package.json stub files (superseded by the exports map) - add scripts/verify-dist.mjs to the build to fail fast when tsup output stops matching package.json#exports - add a framework-agnostic services/fetcher HTTP client module (exported via ./services; root re-export lands with the consumer migration) and guard process.env access in useDiracxUrl so non-Next bundlers don't throw - remove next/image usage from LoginForm and DashboardDrawer (plain <img>) so the library no longer requires Next.js; LoginForm gains a skeleton loading state and an error Alert - pin Node >= 22 at the root (engines + .nvmrc); react-virtuoso stays a direct dependency until the DataTable rewrite lands BREAKING CHANGE: react, react-dom, @mui/material, @mui/icons-material, @emotion/react, @emotion/styled, @axa-fr/react-oidc and swr are now peerDependencies and must be installed by the consuming application. Deep imports that relied on the removed per-directory package.json stubs must use the documented subpath exports instead.
1 parent 6d89033 commit d3222a7

17 files changed

Lines changed: 335 additions & 72 deletions

File tree

.nvmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
24

package-lock.json

Lines changed: 43 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
"name": "diracx-web-root",
33
"version": "0.1.0-a11",
44
"private": true,
5+
"engines": {
6+
"node": ">=22"
7+
},
58
"workspaces": [
69
"packages/diracx-web-components",
710
"packages/diracx-web",

packages/diracx-web-components/package.json

Lines changed: 50 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@
77
"access": "public"
88
},
99
"scripts": {
10-
"build": "tsup --minify",
10+
"build": "tsup --minify && node scripts/verify-dist.mjs",
1111
"dev": "tsup --watch",
1212
"test": "jest --ci",
13+
"test:coverage": "jest --ci --coverage",
1314
"lint": "eslint ./src",
1415
"lint-staged": "lint-staged",
1516
"ts-lint": "tsc -noEmit -incremental",
@@ -19,38 +20,49 @@
1920
},
2021
"license": "GPL-3.0",
2122
"type": "module",
23+
"engines": {
24+
"node": ">=22"
25+
},
26+
"sideEffects": [
27+
"**/*.css",
28+
"**/SearchBar/DatePicker.*"
29+
],
2230
"dependencies": {
2331
"@atlaskit/pragmatic-drag-and-drop": "^1.3.0",
2432
"@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.0.3",
2533
"@atlaskit/pragmatic-drag-and-drop-react-drop-indicator": "^3.0.0",
26-
"@axa-fr/react-oidc": ">=7.24.0 <7.27.0",
27-
"@emotion/react": "^11.11.4",
28-
"@emotion/styled": "^11.11.5",
29-
"@mui/icons-material": "^7.0.0",
30-
"@mui/material": "^7.0.0",
3134
"@mui/utils": "^7.0.0",
3235
"@mui/x-charts": "^8.0.0",
3336
"@mui/x-date-pickers": "^8.0.0",
3437
"@tanstack/react-table": "^8.20.5",
35-
"@types/node": "^24.0.0",
36-
"@types/react": "^19.0.0",
37-
"@types/react-dom": "^19.0.0",
3838
"dayjs": "^1.11.13",
39+
"react-virtuoso": "^4.12.3"
40+
},
41+
"peerDependencies": {
42+
"@axa-fr/react-oidc": ">=7.24.0 <7.27.0",
43+
"@emotion/react": "^11.11.4",
44+
"@emotion/styled": "^11.11.5",
45+
"@mui/icons-material": "^7.0.0",
46+
"@mui/material": "^7.0.0",
3947
"react": "^19.0.0",
4048
"react-dom": "^19.0.0",
41-
"react-virtuoso": "^4.12.3",
4249
"swr": "^2.2.5"
4350
},
4451
"devDependencies": {
52+
"@axa-fr/react-oidc": ">=7.24.0 <7.27.0",
4553
"@babel/core": "^7.28.0",
4654
"@babel/preset-env": "^7.28.0",
4755
"@babel/preset-react": "^7.24.7",
4856
"@babel/preset-typescript": "^7.24.7",
4957
"@chromatic-com/storybook": "^5.0.0",
58+
"@emotion/react": "^11.11.4",
59+
"@emotion/styled": "^11.11.5",
5060
"@eslint/compat": "^2.0.0",
5161
"@eslint/eslintrc": "^3.1.0",
5262
"@eslint/js": "^9.14.0",
5363
"@microsoft/api-extractor": "^7.43.7",
64+
"@mui/icons-material": "^7.0.0",
65+
"@mui/material": "^7.0.0",
5466
"@storybook/addon-docs": "^10.2.10",
5567
"@storybook/addon-links": "^10.2.10",
5668
"@storybook/nextjs": "^10.2.10",
@@ -59,13 +71,19 @@
5971
"@testing-library/react": "^16.3.0",
6072
"@testing-library/user-event": "^14.5.1",
6173
"@types/jest": "^30.0.0",
74+
"@types/node": "^24.0.0",
75+
"@types/react": "^19.0.0",
76+
"@types/react-dom": "^19.0.0",
77+
"@types/ungap__structured-clone": "^1.2.0",
6278
"@typescript-eslint/eslint-plugin": "^8.39.1",
6379
"@typescript-eslint/parser": "^8.39.1",
80+
"@ungap/structured-clone": "^1.3.3",
6481
"babel-jest": "^30.0.0",
6582
"babel-plugin-module-resolver": "^5.0.2",
6683
"eslint": "^9.14.0",
6784
"eslint-config-prettier": "^10.0.1",
6885
"eslint-plugin-import": "^2.29.1",
86+
"eslint-plugin-jsx-a11y": "^6.10.2",
6987
"eslint-plugin-react": "^7.37.1",
7088
"eslint-plugin-react-hooks": "^7.0.0",
7189
"eslint-plugin-storybook": "^10.2.10",
@@ -74,31 +92,42 @@
7492
"jest-environment-jsdom": "^30.0.0",
7593
"lint-staged": "^16.0.0",
7694
"prettier": "^3.2.5",
95+
"react": "^19.0.0",
96+
"react-dom": "^19.0.0",
7797
"storybook": "^10.2.10",
98+
"swr": "^2.2.5",
7899
"ts-jest": "^29.1.2",
79100
"tsup": "^8.0.2",
80101
"typescript": "^5.6.3"
81102
},
82-
"main": "dist/index.js",
83-
"module": "dist/index.js",
84-
"types": "dist/index.d.ts",
103+
"main": "./dist/index.js",
104+
"module": "./dist/index.js",
105+
"types": "./dist/index.d.ts",
85106
"exports": {
107+
".": {
108+
"types": "./dist/index.d.ts",
109+
"import": "./dist/index.js"
110+
},
86111
"./package.json": "./package.json",
87112
"./components": {
88-
"import": "./dist/components/index.js",
89-
"types": "./dist/components/index.d.ts"
113+
"types": "./dist/components/index.d.ts",
114+
"import": "./dist/components/index.js"
90115
},
91116
"./contexts": {
92-
"import": "./dist/contexts/index.js",
93-
"types": "./dist/contexts/index.d.ts"
117+
"types": "./dist/contexts/index.d.ts",
118+
"import": "./dist/contexts/index.js"
94119
},
95120
"./hooks": {
96-
"import": "./dist/hooks/index.js",
97-
"types": "./dist/hooks/index.d.ts"
121+
"types": "./dist/hooks/index.d.ts",
122+
"import": "./dist/hooks/index.js"
98123
},
99124
"./types": {
100-
"import": "./dist/types/index.js",
101-
"types": "./dist/types/index.d.ts"
125+
"types": "./dist/types/index.d.ts",
126+
"import": "./dist/types/index.js"
127+
},
128+
"./services": {
129+
"types": "./dist/services/index.d.ts",
130+
"import": "./dist/services/index.js"
102131
}
103132
},
104133
"files": [
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#!/usr/bin/env node
2+
// Verify that `npm run build` produced every entrypoint declared in
3+
// package.json#exports. Guards against tsup `bundle: false` + glob-entry
4+
// misconfiguration silently shipping a broken package.
5+
6+
import { existsSync, readFileSync } from "node:fs";
7+
import { fileURLToPath } from "node:url";
8+
import { dirname, join, resolve } from "node:path";
9+
10+
const __dirname = dirname(fileURLToPath(import.meta.url));
11+
const pkgRoot = resolve(__dirname, "..");
12+
const pkg = JSON.parse(readFileSync(join(pkgRoot, "package.json"), "utf8"));
13+
14+
const required = new Set();
15+
for (const [key, entry] of Object.entries(pkg.exports ?? {})) {
16+
if (key === "./package.json") continue;
17+
if (typeof entry === "string") {
18+
required.add(entry);
19+
} else if (entry && typeof entry === "object") {
20+
for (const value of Object.values(entry)) {
21+
if (typeof value === "string") required.add(value);
22+
}
23+
}
24+
}
25+
26+
// Also validate top-level main/module/types.
27+
for (const field of ["main", "module", "types"]) {
28+
if (typeof pkg[field] === "string") required.add(pkg[field]);
29+
}
30+
31+
const missing = [];
32+
for (const rel of required) {
33+
const abs = join(pkgRoot, rel);
34+
if (!existsSync(abs)) missing.push(rel);
35+
}
36+
37+
if (missing.length > 0) {
38+
console.error("verify-dist: missing expected build outputs:");
39+
for (const m of missing) console.error(` - ${m}`);
40+
console.error(
41+
"\nIf tsup's entry glob or `bundle: false` option was changed, confirm the generated layout still matches package.json#exports.",
42+
);
43+
process.exit(1);
44+
}
45+
46+
console.log(`verify-dist: OK (${required.size} paths checked).`);

packages/diracx-web-components/src/components/DashboardLayout/DashboardDrawer.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import {
1818
} from "@mui/material";
1919
import { MenuBook, Add } from "@mui/icons-material";
2020
import React, { use, useEffect, useState } from "react";
21-
import Image from "next/image";
2221
import { monitorForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
2322
import { extractClosestEdge } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge";
2423
import { ApplicationsContext } from "../../contexts/ApplicationsProvider";
@@ -413,11 +412,17 @@ export default function DashboardDrawer({
413412
backgroundColor: theme.palette.background.default,
414413
}}
415414
>
416-
<Image
415+
<img
417416
src={logoURL}
418417
alt="DIRAC logo"
419-
fill
420-
style={{ objectFit: "contain" }}
418+
style={{
419+
position: "absolute",
420+
top: 0,
421+
left: 0,
422+
width: "100%",
423+
height: "100%",
424+
objectFit: "contain",
425+
}}
421426
/>
422427
</Toolbar>
423428
{/* Map over user app instances and render them as list items in the drawer. */}

packages/diracx-web-components/src/components/Login/LoginForm.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ import {
1616
SelectChangeEvent,
1717
} from "@mui/material";
1818

19-
import Image from "next/image";
20-
2119
import { useOidc } from "@axa-fr/react-oidc";
2220
import { useMetadata, Metadata } from "../../hooks/metadata";
2321
import { useOIDCContext } from "../../hooks/oidcConfiguration";
@@ -153,7 +151,7 @@ export function LoginForm({
153151
paddingBottom: "10%",
154152
}}
155153
>
156-
<Image src={logoURL} alt="DIRAC logo" width={150} height={150} />
154+
<img src={logoURL} alt="DIRAC logo" width={150} height={150} />
157155
</Box>
158156
{singleVO ? (
159157
<Typography

packages/diracx-web-components/src/components/package.json

Lines changed: 0 additions & 6 deletions
This file was deleted.

0 commit comments

Comments
 (0)