Skip to content

Commit e19e66c

Browse files
chore: fix circular dependency with vite bundling updates (#61)
* chore: fix circular dependency with vite bundling updates * chore: enhance passkey autofill for login-id screens
1 parent 6cb4dcc commit e19e66c

File tree

14 files changed

+97
-77
lines changed

14 files changed

+97
-77
lines changed

react-js/.github/actions/configure-auth0-screens/scripts/process-screen.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ for css_file in "${SHARED_CSS_FILES[@]}" "${SCREEN_CSS_FILES[@]}"; do
4343
fi
4444
done
4545

46-
# Add JS files in correct dependency order: main → react-vendor (React + React-DOM + Base UI) → vendor → common → screen-specific
46+
# Add JS files in correct dependency order: react-vendor → vendor → common → screen-specific → main
4747
# First collect files by type
4848
MAIN_JS_FILE=""
4949
REACT_VENDOR_JS_FILE=""
@@ -71,8 +71,8 @@ for js_file in "${SHARED_JS_FILES[@]}"; do
7171
fi
7272
done
7373

74-
# Add scripts in dependency order: main → react-vendor (React + Base UI) → vendor → common → screen entry
75-
for js_file in "$MAIN_JS_FILE" "$REACT_VENDOR_JS_FILE" "$VENDOR_JS_FILE" "$COMMON_JS_FILE" "$SCREEN_ENTRY_FILE"; do
74+
# Add scripts in dependency order: react-vendor → vendor → common → screen entry → main
75+
for js_file in "$REACT_VENDOR_JS_FILE" "$VENDOR_JS_FILE" "$COMMON_JS_FILE" "$SCREEN_ENTRY_FILE" "$MAIN_JS_FILE"; do
7676
if [ -z "$js_file" ]; then continue; fi
7777
js_basename=$(basename "$js_file")
7878
if [[ ! "$js_basename" =~ ^[^a-zA-Z0-9] ]]; then

react-js/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,15 +146,15 @@ dist/
146146
├── main.[hash].js # Main application bundle
147147
├── shared/
148148
│ ├── style.[hash].css # Global styles (Tailwind + Auth0 theme)
149-
│ ├── react-vendor.[hash].js # React + ReactDOM (~324 kB)
150-
│ ├── vendor.[hash].js # Third-party dependencies (~196 kB)
151-
│ └── common.[hash].js # Shared app code (~87 kB)
149+
│ ├── react-vendor.[hash].js # React core (~194 kB)
150+
│ ├── vendor.[hash].js # Third-party dependencies (~249 kB)
151+
│ └── common.[hash].js # Shared app code (~49 kB)
152152
└── [screen-name]/
153153
└── index.[hash].js # Screen-specific code (0.9-6 kB)
154154
```
155155

156156
**Bundle Strategy:**
157-
- **react-vendor**: React and ReactDOM for optimal caching
157+
- **react-vendor**: React + ReactDOM for optimal caching
158158
- **vendor**: Third-party packages (captcha providers, utilities)
159159
- **common**: Shared components and utilities from src/
160160
- **Screen bundles**: Minimal screen-specific logic for fast loading

react-js/scripts/build-local.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,15 +116,15 @@ try {
116116
html += `<link rel="stylesheet" href="${baseUrl}/${cssFile}">\n`;
117117
});
118118

119-
// Find and order JS files: main, react-vendor, vendor, common, screen-specific
119+
// Find JS files
120120
const mainFile = jsFiles.find(file => file.includes('main.') && !file.includes('shared/'));
121121
const reactVendorFile = jsFiles.find(file => file.includes('shared/react-vendor.'));
122122
const vendorFile = jsFiles.find(file => file.includes('shared/vendor.'));
123123
const commonFile = jsFiles.find(file => file.includes('shared/common.'));
124124
const screenFile = jsFiles.find(file => file.includes(`${screenName}/index.`));
125125

126-
// Add scripts in the correct dependency order
127-
[mainFile, reactVendorFile, vendorFile, commonFile, screenFile].forEach(file => {
126+
// Add all script tags
127+
[reactVendorFile, vendorFile, commonFile, screenFile, mainFile].forEach(file => {
128128
if (file) {
129129
html += `<script src="${baseUrl}/${file}" type="module"></script>\n`;
130130
}

react-js/src/components/form/ULThemeFloatingLabelField.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ function ULThemeFloatingLabelField({
8888
size = "default",
8989
wrapperClassName,
9090
error,
91+
id,
9192
...props
9293
}: ULThemeFloatingLabelFieldProps) {
9394
// Get the form field context for proper ID association
@@ -104,7 +105,7 @@ function ULThemeFloatingLabelField({
104105
return (
105106
<div className={cn("w-full", wrapperClassName)}>
106107
<BaseFloatingLabelField
107-
id={formItemId}
108+
id={id || formItemId}
108109
className={cn(className, themeOverrides)}
109110
variant={effectiveVariant}
110111
size={size}

react-js/src/screens/login-id/components/AlternativeLogins.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,23 @@ const AlternativeLogins = () => {
1414
locales,
1515
} = useLoginIdManager();
1616
const { texts } = screen;
17-
const { isPasskeyEnabled, alternateConnections } = transaction;
17+
const { isPasskeyEnabled, showPasskeyAutofill, alternateConnections } =
18+
transaction;
1819

1920
const connections = alternateConnections as SocialConnection[] | undefined;
2021

2122
// Handle text fallbacks using locales
2223
const passkeyButtonText =
2324
texts?.passkeyButtonText || locales.form.passkeyButton;
2425

26+
// Only show passkey button if passkeys are enabled AND autofill is NOT active
27+
// When showPasskeyAutofill is true, passkey selection happens via input autocomplete
28+
const showPasskeyButton = isPasskeyEnabled && !showPasskeyAutofill;
29+
2530
return (
2631
<>
2732
<div className="space-y-3 mt-2">
28-
{isPasskeyEnabled && (
33+
{showPasskeyButton && (
2934
<ULThemeSocialProviderButton
3035
key="passkey"
3136
displayName="Passkey"

react-js/src/screens/login-id/components/LoginIdForm.tsx

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { useEffect, useRef } from "react";
12
import { useForm } from "react-hook-form";
23

34
import type { Error, LoginOptions } from "@auth0/auth0-acul-js/types";
@@ -83,10 +84,24 @@ function LoginIdForm() {
8384
const shouldShowCountryPicker = isPhoneNumberSupported(loginIdentifiers);
8485
const selectedCountry = transformAuth0CountryCode(countryCode, countryPrefix);
8586

86-
// Enable passkey autofill for identifier field if supported
87-
if (transaction?.isPasskeyEnabled) {
88-
loginIdInstance.registerPasskeyAutofill("username");
89-
}
87+
// Track if passkey autofill has been registered to prevent duplicate calls
88+
const passkeyRegistered = useRef(false);
89+
90+
// Enable passkey autofill for identifier field if supported (run once on mount)
91+
useEffect(() => {
92+
if (
93+
transaction?.isPasskeyEnabled &&
94+
transaction?.showPasskeyAutofill &&
95+
!passkeyRegistered.current
96+
) {
97+
passkeyRegistered.current = true;
98+
loginIdInstance.registerPasskeyAutofill("username");
99+
}
100+
}, [
101+
transaction?.isPasskeyEnabled,
102+
transaction?.showPasskeyAutofill,
103+
loginIdInstance,
104+
]);
90105

91106
// Proper submit handler with form data
92107
const onSubmit = async (data: LoginOptions): Promise<void> => {
@@ -130,6 +145,7 @@ function LoginIdForm() {
130145
<FormItem>
131146
<ULThemeFloatingLabelField
132147
{...field}
148+
id="username"
133149
value={String(field.value || "")}
134150
label={identifierLabel}
135151
type={identifierType}

react-js/vite.config.ts

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -88,36 +88,31 @@ export default defineConfig({
8888
return "assets/shared/[name].[hash][extname]";
8989
},
9090

91-
// Simplified manual chunks strategy with forced common chunk
9291
manualChunks: (id) => {
93-
// React, React-DOM, and Base UI in a separate chunk (Base UI depends on React)
94-
if (
95-
id.includes("node_modules") &&
96-
(id.includes("react") ||
97-
id.includes("react-dom") ||
98-
id.includes("@base-ui-components"))
99-
) {
100-
return "react-vendor";
101-
}
92+
if (!id.includes("node_modules")) {
93+
const absoluteId = resolve(id);
94+
const absoluteSrcScreensDir = resolve(__dirname, "src/screens");
10295

103-
// All other node_modules dependencies go into vendor chunk
104-
if (id.includes("node_modules")) {
105-
return "vendor";
96+
if (
97+
absoluteId.includes(resolve(__dirname, "src/")) &&
98+
!absoluteId.startsWith(absoluteSrcScreensDir + "/")
99+
) {
100+
return "common";
101+
}
102+
return undefined;
106103
}
107104

108-
// Everything in src/ but NOT in src/screens/ goes to common
109-
const absoluteId = resolve(id);
110-
const absoluteSrcScreensDir = resolve(__dirname, "src/screens");
111-
105+
// React core packages (no external dependencies) go to react-vendor
112106
if (
113-
absoluteId.includes(resolve(__dirname, "src/")) &&
114-
!absoluteId.startsWith(absoluteSrcScreensDir + "/")
107+
id.includes("/node_modules/react/") ||
108+
id.includes("/node_modules/react-dom/") ||
109+
id.includes("/node_modules/scheduler/") // Keep React's internals together
115110
) {
116-
return "common";
111+
return "react-vendor";
117112
}
118113

119-
// For screen-specific code or other cases, let Rollup decide
120-
return undefined;
114+
// All other node_modules go to vendor
115+
return "vendor";
121116
},
122117
},
123118
},

react/.github/actions/configure-auth0-screens/scripts/process-screen.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ for css_file in "${SHARED_CSS_FILES[@]}" "${SCREEN_CSS_FILES[@]}"; do
4343
fi
4444
done
4545

46-
# Add JS files in correct dependency order: main → react-vendor (React + React-DOM + Base UI) → vendor → common → screen-specific
46+
# Add JS files in correct dependency order: react-vendor → vendor → common → screen-specific → main
4747
# First collect files by type
4848
MAIN_JS_FILE=""
4949
REACT_VENDOR_JS_FILE=""
@@ -71,8 +71,8 @@ for js_file in "${SHARED_JS_FILES[@]}"; do
7171
fi
7272
done
7373

74-
# Add scripts in dependency order: main → react-vendor (React + Base UI) → vendor → common → screen entry
75-
for js_file in "$MAIN_JS_FILE" "$REACT_VENDOR_JS_FILE" "$VENDOR_JS_FILE" "$COMMON_JS_FILE" "$SCREEN_ENTRY_FILE"; do
74+
# Add scripts in dependency order: react-vendor → vendor → common → screen entry → main
75+
for js_file in "$REACT_VENDOR_JS_FILE" "$VENDOR_JS_FILE" "$COMMON_JS_FILE" "$SCREEN_ENTRY_FILE" "$MAIN_JS_FILE"; do
7676
if [ -z "$js_file" ]; then continue; fi
7777
js_basename=$(basename "$js_file")
7878
if [[ ! "$js_basename" =~ ^[^a-zA-Z0-9] ]]; then

react/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,16 +83,16 @@ dist/
8383
├── main.[hash].js # Main application bundle
8484
├── shared/
8585
│ ├── style.[hash].css # Global styles (Tailwind + Auth0 theme)
86-
│ ├── react-vendor.[hash].js # React + ReactDOM (~324 kB)
87-
│ ├── vendor.[hash].js # Third-party dependencies (~196 kB)
88-
│ └── common.[hash].js # Shared app code (~87 kB)
86+
│ ├── react-vendor.[hash].js # React core (~194 kB)
87+
│ ├── vendor.[hash].js # Third-party dependencies (~347 kB)
88+
│ └── common.[hash].js # Shared app code (~95 kB)
8989
└── [screen-name]/
9090
└── index.[hash].js # Screen-specific code (0.9-6 kB)
9191
```
9292

9393
**Bundle Strategy:**
9494

95-
- **react-vendor**: React and ReactDOM for optimal caching
95+
- **react-vendor**: React + ReactDOM for optimal caching
9696
- **vendor**: Third-party packages (captcha providers, form libraries, utilities)
9797
- **common**: Shared components, hooks, and utilities from src/
9898
- **Screen bundles**: Minimal screen-specific logic for fast loading

react/scripts/build-local.js

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ try {
116116
html += `<link rel="stylesheet" href="${baseUrl}/${cssFile}">\n`;
117117
});
118118

119-
// Find and order JS files: main, react-vendor, vendor, common, screen-specific
119+
// Find JS files
120120
const mainFile = jsFiles.find(
121121
(file) => file.includes("main.") && !file.includes("shared/")
122122
);
@@ -129,14 +129,12 @@ try {
129129
file.includes(`${screenName}/index.`)
130130
);
131131

132-
// Add scripts in the correct dependency order
133-
[mainFile, reactVendorFile, vendorFile, commonFile, screenFile].forEach(
134-
(file) => {
135-
if (file) {
136-
html += `<script src="${baseUrl}/${file}" type="module"></script>\n`;
137-
}
132+
// Add all script tags
133+
[reactVendorFile, vendorFile, commonFile, screenFile, mainFile].forEach((file) => {
134+
if (file) {
135+
html += `<script src="${baseUrl}/${file}" type="module"></script>\n`;
138136
}
139-
);
137+
});
140138

141139
return html;
142140
};

0 commit comments

Comments
 (0)