Message:
Hello Velo Community,
I urgently need help with a persistent Velo issue on my website. I’m trying to implement a custom registration process for three different user roles (Mitglied, Investor, Mentor). The registration should use the wix-members-backend
API, and additional custom fields should be saved in the CRM (wix-crm-backend
).
To achieve this, I have three forms on a page (“Register”) and a backend web module (memberRegistration.web.js
). The frontend code calls an exported function (registerAndEnhanceMember
) from this backend module.
Problem:
Although importing the backend function into the frontend code seems to work (no more “Cannot find module” errors after I corrected the path to backend/memberRegistration.web
), I consistently get a TypeError at runtime when calling the function:
TypeError: (...)registerAndEnhanceMember) is not a function
This error occurs after the frontend validation succeeds and the code attempts to execute await registerAndEnhanceMember(memberData);
.
Here is the relevant console log sequence when clicking the submit button (example for “Mitglied” role):
Frontend: Registrierungs-Seite bereit.
DEBUG: Submit Button 1 (Mitglied) wurde geklickt!
Frontend: Mitglied-Submit geklickt.
Frontend: getFormData für Mitglied gestartet.
Frontend: Validierung für Mitglied erfolgreich.
Frontend: Rufe Backend registerAndEnhanceMember für [Email Address] auf.
Frontend: Kritischer Fehler beim Aufruf der Backend-Funktion: TypeError: (0 , backend_memberRegistration_web__WEBPACK_IMPORTED_MODULE_0__.registerAndEnhanceMember) is not a function
(Note: The error trace above might reference registrationService.web
from a previous test, but the issue is identical with memberRegistration.web
)
Troubleshooting Steps Already Taken (Without Success):
- Checked Filename/Location: The backend file is exactly named
memberRegistration.web.js
and located directly in theBackend
folder. - Checked Export: The function in
memberRegistration.web.js
is correctly exported usingexport async function registerAndEnhanceMember(...)
. - Checked Import: The frontend import statement is
import { registerAndEnhanceMember } from 'backend/memberRegistration.web';
. The.web
extension was necessary to resolve the initial “Cannot find module” error. - Saved & Published: The website has been saved and fully published multiple times after changes to both frontend and backend code.
- Reloaded Editor: The Wix Editor was reloaded multiple times (including hard refreshes).
- Simplified Backend Code: I replaced the content of
memberRegistration.web.js
with a minimal test function that only does aconsole.log
and returnstrue
(see simplified code below) – the... is not a function
error persisted. - Tested Default Export: I tried using
export default
in the backend and the correspondingimport funcName from...
in the frontend – the... is not a function
error persisted. - Checked Permissions: The web module permissions are set to allow invocation (“Anyone”).
Code Snippets:
1. Frontend Code (Page Code on page ‘Register’):
(This is the version without visual feedback, using alert()
, and the working import path)
// Page Code for the Registration Page
import { registerAndEnhanceMember } from 'backend/memberRegistration.web';
$w.onReady(function () {
console.log("Frontend: Registrierungs-Seite bereit.");
// --- Event Listener for Mitglied Form ---
$w('#submit-one').onClick(async () => {
console.log("DEBUG: Submit Button 1 (Mitglied) wurde geklickt!");
console.log("Frontend: Mitglied-Submit geklickt.");
const memberData = getFormData({
formName: "Mitglied", roleName: "Mitglied",
emailInput: $w('#mail-input-one'), usernameInput: $w('#username-input-one'),
passwordInput: $w('#passwort-input-one'), passwordConfirmInput: $w('#conf-pass-input-one'),
firstNameInput: $w('#first-name-input-one'), lastNameInput: $w('#last-name-input-one'),
datenschutzCheckbox: $w('#datenschutz-in-one'), agbCheckbox: $w('#agb-in-one'), nutzungCheckbox: $w('#nutzungsbedingungen-in-one'),
customFields: {}
});
if (memberData) { await submitRegistration(memberData, $w('#submit-one')); }
});
// --- Event Listener for Investor Form ---
$w('#submit-two').onClick(async () => {
console.log("Frontend: Investor-Submit geklickt.");
const memberData = getFormData({
formName: "Investor", roleName: "Investor",
emailInput: $w('#mail-input-two'), usernameInput: $w('#username-input-two'),
passwordInput: $w('#passwort-input-two'), passwordConfirmInput: $w('#pass-conf-input-two'),
firstNameInput: $w('#first-name-input-two'), lastNameInput: $w('#last-name-input-two'),
datenschutzCheckbox: $w('#datenschutz-in-two'), agbCheckbox: $w('#agb-in-two'), nutzungCheckbox: $w('#nutzungsbedingungen-in-two'),
customFields: { firmenname: $w('#compname-input-one').value, budget: parseFloat($w('#budget-input-one').value) || null, investmentInteresse: $w('#your-descri-input-one').value }
});
if (memberData) { await submitRegistration(memberData, $w('#submit-two')); }
});
// --- Event Listener for Mentor Form ---
$w('#submit-three').onClick(async () => {
console.log("Frontend: Mentor-Submit geklickt.");
const memberData = getFormData({
formName: "Mentor", roleName: "Mentor",
emailInput: $w('#mail-input-three'), usernameInput: $w('#username-input-three'),
passwordInput: $w('#pass-in-three'), passwordConfirmInput: $w('#pass-conf-in-three'),
firstNameInput: $w('#first-name-in-three'), lastNameInput: $w('#last-name-in-three'),
datenschutzCheckbox: $w('#datenschutz-in-three'), agbCheckbox: $w('#agb-in-three'), nutzungCheckbox: $w('#nutzungsbedingungen-in-three'),
customFields: { fachgebiete: $w('#division-in-one').value, linkedinProfil: $w('#linkedin-in-one').value, vorstellung: $w('#represent-in-one').value }
});
if (memberData) { await submitRegistration(memberData, $w('#submit-three')); }
});
}); // End of $w.onReady
function getFormData(config) {
console.log(`Frontend: getFormData for ${config.formName} started.`);
const email = config.emailInput.value;
const username = config.usernameInput.value;
const password = config.passwordInput.value;
const passwordConfirm = config.passwordConfirmInput.value;
const firstName = config.firstNameInput.value;
const lastName = config.lastNameInput.value;
const datenschutz = config.datenschutzCheckbox.checked;
const agb = config.agbCheckbox.checked;
const nutzung = config.nutzungCheckbox.checked;
let errorMessage = "";
if (!email || !username || !password || !passwordConfirm || !firstName || !lastName) { errorMessage = "Please fill in all required fields (Email, Username, Password, Name)."; }
else if (!email.includes('@') || !email.includes('.')) { errorMessage = "Please enter a valid email address."; config.emailInput.updateValidityIndication?.(); }
else if (password.length < 6) { errorMessage = "Password must be at least 6 characters long."; config.passwordInput.updateValidityIndication?.(); }
else if (password !== passwordConfirm) { errorMessage = "Passwords do not match."; config.passwordInput.updateValidityIndication?.(); config.passwordConfirmInput.updateValidityIndication?.(); }
else if (!datenschutz || !agb || !nutzung) { errorMessage = "Please agree to the Privacy Policy, Terms & Conditions, and Terms of Use."; }
if (errorMessage) {
console.error(`Frontend Validation Error (${config.formName}):`, errorMessage);
alert(`Validation Error: ${errorMessage}`);
return null;
}
console.log(`Frontend: Validation for ${config.formName} successful.`);
return {
email: email, password: password, roleName: config.roleName,
firstName: firstName, lastName: lastName, customData: config.customFields || {}
};
}
async function submitRegistration(memberData, submitButton) {
submitButton.disable();
console.log(`Frontend: Calling backend registerAndEnhanceMember for ${memberData.email}`);
try {
const result = await registerAndEnhanceMember(memberData); // <-- ERROR OCCURS HERE
if (result.success) {
console.log("Frontend: Registration successful in backend:", result.member);
alert("Registration successful!");
} else {
console.error("Frontend: Registration failed in backend:", result.error);
console.error("User-friendly error message:", result.userErrorMessage);
alert(`Registration failed: ${result.userErrorMessage || "Unknown error"}`);
}
} catch (error) {
console.error("Frontend: Critical error calling backend function:", error);
alert("A technical problem occurred. Please try again later.");
} finally {
submitButton.enable();
}
}
2. Backend Code (memberRegistration.web.js
):
(This is the functional version with role assignment commented out, which shows no errors in the editor but fails to be called correctly)
// backend/memberRegistration.web.js
import { authentication } from 'wix-members-backend';
// import wixUsersBackend from 'wix-users-backend'; // Role assignment commented out
import { contacts } from 'wix-crm-backend';
// --- Configuration ---
const ROLE_IDS = { /* ... Your Role IDs ... */ };
const CUSTOM_FIELDS = { /* ... Your Custom Field Keys ... */ };
// --- Main Registration Function ---
export async function registerAndEnhanceMember(memberData) {
const { email, password, roleName, firstName, lastName, customData } = memberData;
try {
// 1. Register member
console.log(`Backend: Attempting registration for ${email} (Role ${roleName} will NOT be assigned)`);
const registrationResult = await authentication.register(email, password, {
contactInfo: { firstName: firstName, lastName: lastName }
});
const memberId = registrationResult.member._id;
const contactId = registrationResult.member.contactId;
console.log(`Backend: Member registered: ${memberId}, Contact ID: ${contactId}`);
// 2. Role assignment is commented out
/*
const roleId = ROLE_IDS[roleName];
if (roleId) { ... }
*/
// 3. Update CRM Contact
const updatePayload = { name: { first: firstName, last: lastName }, customFields: {} };
let hasCustomFields = false;
for (const key in customData) { /* ... Code to populate customFields ... */
if (Object.prototype.hasOwnProperty.call(customData, key) && CUSTOM_FIELDS[key] && customData[key] !== null && customData[key] !== undefined && customData[key] !== '') {
updatePayload.customFields[CUSTOM_FIELDS[key]] = customData[key];
hasCustomFields = true;
}
}
if (CUSTOM_FIELDS.rolle) { updatePayload.customFields[CUSTOM_FIELDS.rolle] = roleName; hasCustomFields = true; }
if (hasCustomFields) {
console.log(`Backend: Attempting to get contact ${contactId} to retrieve revision.`);
const contactToUpdate = await contacts.getContact(contactId, { suppressAuth: true });
const revision = contactToUpdate.revision;
console.log(`Backend: Revision ${revision} for contact ${contactId} obtained.`);
await contacts.updateContact({ contactId: contactId, revision: revision }, updatePayload, { suppressAuth: true });
console.log(`Backend: Contact ${contactId} with revision ${revision} updated.`);
} else { /* ... no update needed ... */ }
return { success: true, member: registrationResult.member };
} catch (error) { /* ... Error handling ... */
console.error("Backend: Severe error in registerAndEnhanceMember:", error);
console.log("Error details:", JSON.stringify(error, Object.getOwnPropertyNames(error)));
let userErrorMessage = "Registration failed...";
/* ... specific error messages ... */
return { success: false, error: error.message || 'Unknown error', userErrorMessage: userErrorMessage };
}
}
3. Backend Code (Simplified Test Version):
(Even using this minimal code in memberRegistration.web.js
resulted in the ... is not a function
error)
// backend/memberRegistration.web.js (SIMPLIFIED TEST VERSION with NAMED Export)
// Export a very simple function with the expected name
export async function registerAndEnhanceMember(memberData) {
console.log("--- BACKEND NAMED EXPORT TEST ---");
console.log("registerAndEnhanceMember was called!");
console.log("Received data:", JSON.stringify(memberData));
console.log("--- BACKEND NAMED EXPORT TEST END ---");
// Return a simple success object
return {
success: true,
member: { _id: 'test-member-id', contactId: 'test-contact-id', revision: 123 }
};
}
My Request:
Could you please investigate why the function registerAndEnhanceMember
exported from backend/memberRegistration.web.js
is not recognized as a function at runtime in the frontend, even though the import path seems correct and even a minimal, correctly exported function fails in the same way? Could there be an issue with the Velo build process, module resolution, or a specific conflict on my site?
Link to Editor:
[PLEASE INSERT YOUR EDITOR LINK HERE]
Thank you very much for your help!