Skip to content

[WIP] fix: add script to install node_modules in mounted mfes #232

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: release
Choose a base branch
from

Conversation

hinakhadim
Copy link
Contributor

@hinakhadim hinakhadim commented Oct 31, 2024

WIP -> The jobs run on tutor dev only

Description

These code changes introduce improvements to the Tutor MFE (Micro-Frontend) plugin by adding automation and efficiency for managing and running tasks in environments where MFEs are mounted. When MFEs are mounted, it will run npm clean-install as part of the run tutor dev launch. The "mfe" init task npm-install.sh is taking care of installing the node_modules, as it is done in the LMS

Test Cases:

  • It will run the npm-install script when MFEs are implicitly and expicitly mounted using the Tutor format: tutor mounts add $(pwd)/frontend-app-* & tutor mounts add [mfe-name]:$(pwd)/frontend-app-*:/openedx/app.
  • The job should run for all mounted MFEs
  • The job will run only in tutor dev, not tutor local, as MFEs mount only in tutor dev environment.
  • If no node_modules are present, it should install node_modules.
  • If the node_modules directory exists but is empty or outdated, it should install node_modules.
  • If the package-lock.json file changes slightly, it should trigger reinstallation of node_modules.
  • If node_modules are installed and then reinstallation is attempted without changes to package-lock.json, it should not reinstall node_modules.

Closes #218

Special thanks to @Danyal-Faheem for collaborating with me on this and helping to reach a solution. 🙌

@hinakhadim hinakhadim added the bug Something isn't working label Oct 31, 2024
@hinakhadim hinakhadim marked this pull request as draft October 31, 2024 11:48
@hinakhadim hinakhadim changed the title fix: add script to install node_modules in mounted mfes [WIP] fix: add script to install node_modules in mounted mfes Oct 31, 2024
def _run_jobs_in_mounted_mfes(config: Config) -> None:
mounts = get_typed(config, "MOUNTS", list, [])

pattern = re.compile(r'frontend-app-(\w+)')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can use the REPO_PREFIX variable defined above here instead of a hardcoded string.

@tutor_hooks.Actions.CONFIG_LOADED.add()
def _run_jobs_in_mounted_mfes(config: Config) -> None:
mounts = get_typed(config, "MOUNTS", list, [])

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can return here if no mounts exist in the config.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

@@ -0,0 +1,11 @@
{%- for app_name, app in iter_mfes() %}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this patch needed?

pattern = re.compile(r'frontend-app-(\w+)')
mounted_mfes = [match.group(1) for mount in mounts if (match := pattern.search(mount))]

mfe_task_file = os.path.join(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mfe_npm_install could be a better name as this action is related only to npm install.

sha1sum "$PACKAGE_LOCK" | awk '{print $1}'
}

# Check if node_modules exists and fingerprint is valid
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this comment can be broken down and mentioned against the appropriate if-elif-else block.



@tutor_hooks.Actions.CONFIG_LOADED.add()
def _run_jobs_in_mounted_mfes(config: Config) -> None:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a big fan of adding callbacks to the CONFIG_LOADED action. It means we have to manually parse MOUNTS and this is bound to fail in many edge cases. Also, we have to start using Context objects, which is VERY dirty.

Instead, I suggest the following:

@tutor_hooks.Filters.CLI_DO_INIT_TASKS.add()
def _mfe_npm_install(tasks):
    for mfe in get_mfes():
        if hooks.Filters.COMPOSE_MOUNTS.apply([], f"frontend-app-{mfe}"):
            tasks.append((mfe, "... contents of npm-install.sh..."))

What do you think?

@HammadYousaf01 HammadYousaf01 moved this from In Progress to In review in Tutor project management May 6, 2025
@Danyal-Faheem Danyal-Faheem self-requested a review May 13, 2025 11:45

# Store the new fingerprint after installation
generate_fingerprint > "$FINGERPRINT_FILE"
echo "✅ Dependencies installed and fingerprint updated."
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: add extra line at end of file

- {{ mount }}
{%- endfor %}
{%- endif %}
{%- endfor %}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: add extra line at end of file

@@ -0,0 +1,11 @@
{%- for app_name, app in iter_mfes() %}
{%- set mounts = iter_mounts(MOUNTS, app_name)|list %}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We moved from iter_mounts to a cleaner MFEMountData object in #241. We should use the similar format here for consistency.

@@ -0,0 +1,7 @@
{%- for app_name, app in iter_mfes() %}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this patch necessary? Don't we just need to run the init job in dev?

return None

pattern = re.compile(rf'{re.escape(REPO_PREFIX)}(\w+)')
mounted_mfes = [match.group(1) for mount in mounts if (match := pattern.search(mount))]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking back, we should be able to use MFEMountData here as well instead of using a regex. What do you think?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
Status: In review
Development

Successfully merging this pull request may close these issues.

Mounted MFEs with node_modules missing fail to start the server
5 participants