AE-87 [docs] Frontend development with ESM#1547
Conversation
✅ Deploy Preview for moodledevdocs ready!Built without sensitive environment variables
To edit notification comments on pull requests, go to your Netlify project configuration. |
There was a problem hiding this comment.
Pull request overview
Adds a new developer guide page describing the recommended approach for Moodle frontend development with ESM, React, and TypeScript, including templated mounting, props guidance, data-fetching patterns, and theming considerations.
Changes:
- Introduces a new “Frontend Development” guide under
docs/guides/frontend/. - Documents React auto-initialisation via the Mustache
{{#react}}helper and the default-export contract. - Provides guidance on props minimisation, service-module data fetching, and theming/styling compatibility.
| "teachers": [...], | ||
| "activities": [...] |
There was a problem hiding this comment.
This block is labeled as JSON but the example contains ... placeholders (e.g. "teachers": [...]) which makes it invalid JSON. Either make it valid JSON (using explicit arrays/objects) or switch the fence to something like js/javascript and call out that it’s pseudocode.
| "teachers": [...], | |
| "activities": [...] | |
| "teachers": [ | |
| { | |
| "id": 1, | |
| "fullname": "Dr. Smith" | |
| } | |
| ], | |
| "activities": [ | |
| { | |
| "id": 10, | |
| "name": "Assignment 1", | |
| "type": "assignment" | |
| } | |
| ] |
|
|
||
| Where ESM component wrappers are available, developers should prefer them. | ||
|
|
||
| Where they are not avaialable, AMD files may be accessed using compatibility helpers. |
There was a problem hiding this comment.
Typo: "avaialable" should be "available".
| Where they are not avaialable, AMD files may be accessed using compatibility helpers. | |
| Where they are not available, AMD files may be accessed using compatibility helpers. |
|
|
||
| ### Recommended pattern for Data Fetching | ||
|
|
||
| React components should avoid directly embedding data fetching lgic where possible. Instead, data should be handled through service modules. |
There was a problem hiding this comment.
Typo: "lgic" should be "logic".
| React components should avoid directly embedding data fetching lgic where possible. Instead, data should be handled through service modules. | |
| React components should avoid directly embedding data fetching logic where possible. Instead, data should be handled through service modules. |
| export const fetchCourse = async (courseid: number) => { | ||
| const [result] = await Ajax.call([{ | ||
| methodname: 'core_course_get_courses', | ||
| args: {ids: [courseid]} | ||
| }]); | ||
|
|
||
| return result[0]; |
There was a problem hiding this comment.
The await Ajax.call([...]) example is likely incorrect for Moodle’s core/ajax API: call() returns an array of Promises (one per request), so awaiting the array won’t resolve the underlying request and result will be a Promise rather than the response. Update the example to use the documented pattern (e.g. call([...])[0] and await that Promise, or await Promise.all(call([...]))) and consider using the same import style as docs/guides/javascript/ajax/index.md (import {call as fetchMany} from 'core/ajax';).
| export const fetchCourse = async (courseid: number) => { | |
| const [result] = await Ajax.call([{ | |
| methodname: 'core_course_get_courses', | |
| args: {ids: [courseid]} | |
| }]); | |
| return result[0]; | |
| import {call as fetchMany} from 'core/ajax'; | |
| export const fetchCourse = async (courseid: number) => { | |
| const [request] = fetchMany([{ | |
| methodname: 'core_course_get_courses', | |
| args: {ids: [courseid]} | |
| }]); | |
| const courses = await request; | |
| return courses[0]; |
| const [loading, setLoading] = useState(null); | ||
|
|
||
| useEffect(() => { | ||
| fetchCourse(courseid) | ||
| .then(setCourse) | ||
| .finally(() => setLoading(false)); |
There was a problem hiding this comment.
In this example loading is treated like a boolean (setLoading(false)), but it’s initialised with useState(null) and never set to true when the request starts. That makes the snippet harder to follow and doesn’t demonstrate the “loading and error states” bullet below; consider initialising loading as true/false consistently and showing where it is set at request start and on error.
| const [loading, setLoading] = useState(null); | |
| useEffect(() => { | |
| fetchCourse(courseid) | |
| .then(setCourse) | |
| .finally(() => setLoading(false)); | |
| const [loading, setLoading] = useState(false); | |
| const [error, setError] = useState<Error | null>(null); | |
| useEffect(() => { | |
| setLoading(true); | |
| setError(null); | |
| fetchCourse(courseid) | |
| .then(setCourse) | |
| .catch(setError) | |
| .finally(() => setLoading(false)); |
|
|
||
| ### Relationship to Reactive UI System | ||
|
|
||
| Moodle previously introduced a custom reactive UI system to support dynamic interfaces (link to other page. |
There was a problem hiding this comment.
This sentence contains a placeholder and unmatched parenthesis: "(link to other page.". It should be replaced with a real link (likely to the Reactive UI guide under docs/guides/javascript/reactive/) and the punctuation fixed so the paragraph renders correctly.
| Moodle previously introduced a custom reactive UI system to support dynamic interfaces (link to other page. | |
| Moodle previously introduced a custom reactive UI system to support dynamic interfaces; see the [Reactive UI guide](../javascript/reactive/). |
|
|
||
| In practice, this means exporting a function that returns JSX: | ||
|
|
||
| ```TypeScript |
There was a problem hiding this comment.
Code fence language identifiers here (and elsewhere in this page) use non-standard values like TypeScript/JSON. Elsewhere in the docs (e.g. docs/guides/javascript/react/profiler.md and docs/guides/javascript/react/reactautoinit.md) the convention is to use lower-case Prism ids like ts/tsx and json, which improves consistent syntax highlighting.
| ```TypeScript | |
| ```ts |
There was a problem hiding this comment.
This should be lowercase typescript, not ts.
tsx is also supported for react tsx.
|
|
||
| - hard coded colours | ||
| - hard coded spacing | ||
| - custom styles that duplicates the design system components |
There was a problem hiding this comment.
Grammar/typo: "custom styles that duplicates" should be "custom styles that duplicate".
| - custom styles that duplicates the design system components | |
| - custom styles that duplicate the design system components |
This provides some guidance for frontend development in Moodle going forward with our ESM system.