Hey I could use some help in resolving this error:
yarn rw prerender --dry-run
::: Dry run, not writing changes :::
You can use `yarn rw prerender --dry-run` to debug
---------- Error rendering path "/login" ----------
Error [ERR_REQUIRE_ESM]: require() of ES Module C:\Users\basti\WebstormProjects\v3Players2Play\node_modules\@simplewebauthn\browser\dist\bundle\index.js from C:\Users\basti\WebstormProjects\v3Players2Play\node_modules\@redwoodjs\auth\dist\webAuthn\index.js not supported.
Instead change the require of C:\Users\basti\WebstormProjects\v3Players2Play\node_modules\@simplewebauthn\browser\dist\bundle\index.js in C:\Users\basti\WebstormProjects\v3Players2Play\node_modules\@redwoodjs\auth\dist\webAuthn\index.js to a dynamic import() which is available in all CommonJS modules.
at Object.newLoader [as .js] (C:\Users\basti\WebstormProjects\v3Players2Play\node_modules\pirates\lib\index.js:141:7)
at Object.<anonymous> (C:\Users\basti\WebstormProjects\v3Players2Play\node_modules\@redwoodjs\auth\dist\webAuthn\index.js:15:16)
at Module._compile (C:\Users\basti\WebstormProjects\v3Players2Play\node_modules\pirates\lib\index.js:136:24)
at Object.newLoader [as .js] (C:\Users\basti\WebstormProjects\v3Players2Play\node_modules\pirates\lib\index.js:141:7)
at Object.<anonymous> (C:\Users\basti\WebstormProjects\v3Players2Play\node_modules\@redwoodjs\auth\webAuthn\index.js:2:18)
at Module._compile (C:\Users\basti\WebstormProjects\v3Players2Play\node_modules\pirates\lib\index.js:136:24)
at Object.newLoader [as .js] (C:\Users\basti\WebstormProjects\v3Players2Play\node_modules\pirates\lib\index.js:141:7)
at Object.<anonymous> (C:\Users\basti\WebstormProjects\v3Players2Play\web\src\App.tsx:14:40)
at Module._compile (C:\Users\basti\WebstormProjects\v3Players2Play\node_modules\pirates\lib\index.js:136:24)
at Object.newLoader [as .tsx] (C:\Users\basti\WebstormProjects\v3Players2Play\node_modules\pirates\lib\index.js:141:7)
at C:\Users\basti\WebstormProjects\v3Players2Play\node_modules\@redwoodjs\prerender\dist\runPrerender.js:179:123
at async runPrerender (C:\Users\basti\WebstormProjects\v3Players2Play\node_modules\@redwoodjs\prerender\dist\runPrerender.js:179:7)
at async Task.task (C:\Users\basti\WebstormProjects\v3Players2Play\node_modules\@redwoodjs\cli\dist\commands\prerenderHandler.js:195:35)
× Prerendering /login -> web/dist/login.html
→ Failed to render "C:\Users\basti\WebstormProjects\v3Players2Play\web\src\pages\LoginPage\LoginPage.tsx"
Prerendering /signup -> web/dist/signup.html
Prerendering /forgot-password -> web/dist/forgot-password.html
Prerendering /reset-password -> web/dist/reset-password.html
Prerendering /games -> web/dist/games.html
Prerendering /game/{name:slug} -> web/dist/game/{name:slug}.html
Prerendering / -> web/dist/index.html
Prerendering /404 -> web/dist/404.html
Running diagnostic checks
✔ Diagnostics checks passed
Here is my /login Page:
import { useRef, useState } from 'react'
import { useEffect } from 'react'
import { useAuth } from '@redwoodjs/auth'
import {
Form,
Label,
TextField,
PasswordField,
Submit,
FieldError,
} from '@redwoodjs/forms'
import { Link, navigate, routes } from '@redwoodjs/router'
import { MetaTags } from '@redwoodjs/web'
import { toast, Toaster } from '@redwoodjs/web/toast'
const WELCOME_MESSAGE = 'Welcome back!'
const REDIRECT = routes.home()
const LoginPage = ({ type }) => {
const {
isAuthenticated,
client: webAuthn,
loading,
logIn,
reauthenticate,
} = useAuth()
const [shouldShowWebAuthn, setShouldShowWebAuthn] = useState(false)
const [showWebAuthn, setShowWebAuthn] = useState(
webAuthn.isEnabled() && type !== 'password'
)
// should redirect right after login or wait to show the webAuthn prompts?
useEffect(() => {
if (isAuthenticated && (!shouldShowWebAuthn || webAuthn.isEnabled())) {
navigate(REDIRECT)
}
}, [isAuthenticated, shouldShowWebAuthn])
// if WebAuthn is enabled, show the prompt as soon as the page loads
useEffect(() => {
if (!loading && !isAuthenticated && showWebAuthn) {
onAuthenticate()
}
}, [loading, isAuthenticated])
// focus on the username field as soon as the page loads
const usernameRef = useRef()
useEffect(() => {
usernameRef.current && usernameRef.current.focus()
}, [])
const onSubmit = async (data) => {
const webAuthnSupported = await webAuthn.isSupported()
if (webAuthnSupported) {
setShouldShowWebAuthn(true)
}
const response = await logIn({ ...data })
if (response.message) {
// auth details good, but user not logged in
toast(response.message)
} else if (response.error) {
// error while authenticating
toast.error(response.error)
} else {
// user logged in
if (webAuthnSupported) {
setShowWebAuthn(true)
} else {
toast.success(WELCOME_MESSAGE)
}
}
}
const onAuthenticate = async () => {
try {
await webAuthn.authenticate()
await reauthenticate()
toast.success(WELCOME_MESSAGE)
navigate(REDIRECT)
} catch (e) {
if (e.name === 'WebAuthnDeviceNotFoundError') {
toast.error(
'Device not found, log in with username/password to continue'
)
setShowWebAuthn(false)
} else {
toast.error(e.message)
}
}
}
const onRegister = async () => {
try {
await webAuthn.register()
toast.success(WELCOME_MESSAGE)
navigate(REDIRECT)
} catch (e) {
toast.error(e.message)
}
}
const onSkip = () => {
toast.success(WELCOME_MESSAGE)
setShouldShowWebAuthn(false)
}
const AuthWebAuthnPrompt = () => {
return (
<div className="rw-webauthn-wrapper">
<h2>WebAuthn Login Enabled</h2>
<p>Log in with your fingerprint, face or PIN</p>
<div className="rw-button-group">
<button className="rw-button rw-button-blue" onClick={onAuthenticate}>
Open Authenticator
</button>
</div>
</div>
)
}
const RegisterWebAuthnPrompt = () => (
<div className="rw-webauthn-wrapper">
<h2>No more passwords!</h2>
<p>
Depending on your device you can log in with your fingerprint, face or
PIN next time.
</p>
<div className="rw-button-group">
<button className="rw-button rw-button-blue" onClick={onRegister}>
Turn On
</button>
<button className="rw-button" onClick={onSkip}>
Skip for now
</button>
</div>
</div>
)
const PasswordForm = () => (
<Form onSubmit={onSubmit} className="rw-form-wrapper">
<Label
name="username"
className="rw-label"
errorClassName="rw-label rw-label-error"
>
Username
</Label>
<TextField
name="username"
className="rw-input"
errorClassName="rw-input rw-input-error"
ref={usernameRef}
autoFocus
validation={{
required: {
value: true,
message: 'Username is required',
},
}}
/>
<FieldError name="username" className="rw-field-error" />
<Label
name="password"
className="rw-label"
errorClassName="rw-label rw-label-error"
>
Password
</Label>
<PasswordField
name="password"
className="rw-input"
errorClassName="rw-input rw-input-error"
autoComplete="current-password"
validation={{
required: {
value: true,
message: 'Password is required',
},
}}
/>
<div className="rw-forgot-link">
<Link to={routes.forgotPassword()} className="rw-forgot-link">
Forgot Password?
</Link>
</div>
<FieldError name="password" className="rw-field-error" />
<div className="rw-button-group">
<Submit className="rw-button rw-button-blue">Login</Submit>
</div>
</Form>
)
const formToRender = () => {
if (showWebAuthn) {
if (webAuthn.isEnabled()) {
return <AuthWebAuthnPrompt />
} else {
return <RegisterWebAuthnPrompt />
}
} else {
return <PasswordForm />
}
}
const linkToRender = () => {
if (showWebAuthn) {
if (webAuthn.isEnabled()) {
return (
<div className="rw-login-link">
<span>or login with </span>{' '}
<a href="?type=password" className="rw-link">
username and password
</a>
</div>
)
}
} else {
return (
<div className="rw-login-link">
<span>Don't have an account?</span>{' '}
<Link to={routes.signup()} className="rw-link">
Sign up!
</Link>
</div>
)
}
}
if (loading) {
return null
}
return (
<>
<MetaTags title="Login" />
<main className="rw-main">
<Toaster toastOptions={{ className: 'rw-toast', duration: 6000 }} />
<div className="rw-scaffold rw-login-container">
<div className="rw-segment">
<header className="rw-segment-header">
<h2 className="rw-heading rw-heading-secondary">Login</h2>
</header>
<div className="rw-segment-main">
<div className="rw-form-wrapper">{formToRender()}</div>
</div>
</div>
{linkToRender()}
</div>
</main>
</>
)
}
export default LoginPage