Skip to content

Conversation

@rodrigok
Copy link
Member

@rodrigok rodrigok commented Nov 11, 2025

https://rocketchat.atlassian.net/browse/ARCH-1854

Reduces uncompressed image size from 3.4GB to 2.1GB (-1.3GB or 62% of the original size)
image

Reduces compressed image size from 601MB to 365MB (-236MB or 61% of the original size)
image

Proposed changes (including videos or screenshots)

Issue(s)

Steps to test or reproduce

Further comments

Summary by CodeRabbit

  • Chores

    • CI/build workflows now support a selectable run mode (production vs development) and split install paths; cache keys differentiate by run mode.
    • Source hash version bumped; removed legacy CI build script and automated translation-check step.
  • Bug Fixes / Optimizations

    • Build process now merges then restores dependency metadata to avoid leaking dev-dependencies into production builds.
    • Several bundle and image cleanups plus multi-stage image changes reduce final artifact sizes.

@rodrigok rodrigok requested a review from a team as a code owner November 11, 2025 18:24
@dionisio-bot
Copy link
Contributor

dionisio-bot bot commented Nov 11, 2025

Looks like this PR is ready to merge! 🎉
If you have any trouble, please check the PR guidelines

@changeset-bot
Copy link

changeset-bot bot commented Nov 11, 2025

⚠️ No Changeset found

Latest commit: 2a347fb

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 11, 2025

Walkthrough

Make CI/node setup type-aware (development vs production); add dependency-merge/restore and bundle size-reduction cleanup in Meteor/docker build steps; convert Alpine Dockerfile to multi-stage; remove translation-check task and root build:ci script; bump workflow SOURCE_HASH suffix.

Changes

Cohort / File(s) Summary
Setup Node Action
/.github/actions/setup-node/action.yml
Add type input (development
Meteor Build Action
/.github/actions/meteor-build/action.yml
Add step to merge dependencies into apps/meteor/package.json (backup/restore); invoke setup-node with type: production; add size-reduction cleanup (remove swc/core, TS/babel artifacts and .d.ts files) before bundle publish; remove translation-check step.
Build Docker Action
/.github/actions/build-docker/action.yml
Add service-aware SWC pruning: detect arch (arm64/x64) and remove non-matching core-* swc-core directories for rocketchat service before publish/load.
Workflow Config
/.github/workflows/ci.yml
Bump SOURCE_HASH suffix (e.g., -v3 -> -v8).
Root package.json
./package.json
Remove scripts.build:ci entry.
Turbo config
./turbo.json
Remove translation-check task from tasks.
Alpine Dockerfile
apps/meteor/.docker/Dockerfile.alpine
Convert to multi-stage builder/final image; copy app from builder; remove final-stage installs and build-time dependency tricks; set WORKDIR /app/bundle, expose 3000, run as non-root rocketchat user.

Sequence Diagram(s)

sequenceDiagram
  participant CI as Workflow
  participant Setup as setup-node action
  participant Cache as Cache
  participant Yarn as Yarn
  participant Meteor as meteor-build action
  rect rgb(245,250,255)
  CI->>Setup: invoke (install: true, type: production)
  end
  Setup->>Cache: lookup node-modules:production:...:SOURCE_HASH-v8
  alt cache hit
    Cache-->>Setup: restore node_modules
  else cache miss
    Setup->>Yarn: run "yarn workspaces focus --all --production"
    Yarn-->>Setup: node_modules populated
    Setup->>Cache: save node-modules:production:...-v8
  end
  CI->>Meteor: start meteor build (production)
  Meteor->>Meteor: merge deps -> apps/meteor/package.json (backup)
  Meteor->>Yarn: cd apps/meteor && yarn workspaces focus --all --production
  Meteor->>Meteor: remove swc/core, TS/babel paths and .d.ts files
  Meteor->>Meteor: restore original apps/meteor/package.json
Loading
sequenceDiagram
  participant BuildDocker as build-docker action
  participant FS as Filesystem
  Note over BuildDocker,FS: Pre-publish SWC pruning for rocketchat
  BuildDocker->>FS: detect arch -> swc_arch
  BuildDocker->>FS: list swc-core/core-*
  BuildDocker->>FS: remove core-* except linux-${swc_arch}-gnu
  FS-->>BuildDocker: sizes reduced
  BuildDocker->>BuildDocker: continue publish/load
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Areas needing extra attention:
    • /.github/actions/meteor-build/action.yml — dependency merge/restore correctness and race/permission edge cases.
    • SWC pruning logic in /.github/actions/build-docker/action.yml and the size-reduction loop in meteor-build (ensure correct globbing, arch detection, and no accidental deletions).
    • apps/meteor/.docker/Dockerfile.alpine — multi-stage correctness, file ownership, runtime paths, and removed install/cleanup implications.
    • Cache key changes and SOURCE_HASH bump across workflows to avoid cache misses or unintended invalidation.

Possibly related PRs

Suggested reviewers

  • ggazzo
  • KevLehman
  • tassoevan
  • sampaiodiego

Poem

🐇 I nibbled YAML, trimmed the bulk,

Merged the deps and cleared the sulk,
Pruned swc roots with tidy paws,
Built in stages — no more claws,
🥕 Hop, bundle, ship — applause!

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately reflects the main objective: preventing dev dependencies from being included in Docker images, which is substantiated by changes across build workflows, Node setup actions, and Dockerfile configurations.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/build-with-production

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@rodrigok rodrigok force-pushed the chore/build-with-production branch from 3fc4c6d to 8df22a1 Compare November 11, 2025 18:46
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/actions/setup-node/action.yml (1)

76-84: Both install steps execute unconditionally when install: true, defeating production mode logic.

Currently, both the regular yarn step (line 76-79) and yarn workspaces focus --all --production step (line 81-84) share the same if: inputs.install condition. This means when production: true is set:

  1. The regular yarn installs all dependencies (including dev)
  2. Then yarn workspaces focus --all --production runs but cannot retroactively remove already-installed dev dependencies

Result: Dev dependencies remain in node_modules despite production: true.

The conditional logic should be:

  • Regular install should only run when production mode is disabled: if: inputs.install && inputs.production != true
  • Production install should only run when production mode is enabled: if: inputs.install && inputs.production == true
    - name: yarn install
-      if: inputs.install
+      if: inputs.install && inputs.production != true
       shell: bash
       run: YARN_ENABLE_HARDENED_MODE=${{ inputs.HARDENED_MODE }} yarn

    - name: yarn install production
-      if: inputs.install
+      if: inputs.install && inputs.production == true
       shell: bash
       run: YARN_ENABLE_HARDENED_MODE=${{ inputs.HARDENED_MODE }} yarn workspaces focus --all --production
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3fc4c6d and 8df22a1.

📒 Files selected for processing (3)
  • .github/actions/meteor-build/action.yml (1 hunks)
  • .github/actions/setup-node/action.yml (3 hunks)
  • .github/workflows/ci.yml (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • .github/workflows/ci.yml
  • .github/actions/meteor-build/action.yml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: CodeQL-Build
  • GitHub Check: CodeQL-Build
🔇 Additional comments (1)
.github/actions/setup-node/action.yml (1)

15-18: Input definition looks good.

The new production input is properly defined with appropriate type and description.

@rodrigok rodrigok force-pushed the chore/build-with-production branch 2 times, most recently from 8464929 to 13c5678 Compare November 11, 2025 19:07
@codecov
Copy link

codecov bot commented Nov 11, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 68.99%. Comparing base (7d90c9d) to head (2a347fb).
⚠️ Report is 1 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop   #37481      +/-   ##
===========================================
+ Coverage    68.97%   68.99%   +0.01%     
===========================================
  Files         3358     3358              
  Lines       114240   114240              
  Branches     20537    20537              
===========================================
+ Hits         78798    78816      +18     
+ Misses       33349    33341       -8     
+ Partials      2093     2083      -10     
Flag Coverage Δ
e2e 57.44% <ø> (-0.03%) ⬇️
e2e-api 43.80% <ø> (+1.00%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@rodrigok rodrigok force-pushed the chore/build-with-production branch 6 times, most recently from aac2fdb to 48d8992 Compare November 11, 2025 20:00
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 13c5678 and 48d8992.

📒 Files selected for processing (3)
  • .github/actions/meteor-build/action.yml (1 hunks)
  • .github/actions/setup-node/action.yml (3 hunks)
  • .github/workflows/ci.yml (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • .github/workflows/ci.yml
  • .github/actions/meteor-build/action.yml
🔇 Additional comments (2)
.github/actions/setup-node/action.yml (2)

54-54: ✅ Cache key correctly differentiates by type.

The cache key now includes type-${{ inputs.type }}, ensuring development and production dependency trees maintain separate caches. This prevents cache pollution and aligns with the PR objective.

Note: The syntax error flagged in a prior review (extra closing brace) appears to be resolved.


78-85: ✅ Production install correctly excludes dev dependencies.

The conditional logic properly splits into two paths:

  • yarn install for development (line 78)
  • yarn workspaces focus --all --production for production (line 83-85)

The --production flag on the production path correctly excludes dev dependencies, achieving the PR objective. The mutually exclusive conditions prevent accidental double-installs.

@rodrigok rodrigok force-pushed the chore/build-with-production branch from 48d8992 to 8cb77db Compare November 11, 2025 20:07
@ggazzo ggazzo modified the milestones: 7.10.3, 7.13.0 Nov 11, 2025
@rodrigok rodrigok force-pushed the chore/build-with-production branch from 8cb77db to 421ee5f Compare November 11, 2025 21:20
@rodrigok rodrigok marked this pull request as draft November 11, 2025 22:03
@rodrigok rodrigok force-pushed the chore/build-with-production branch 8 times, most recently from ce1dbfe to 52b89a7 Compare November 12, 2025 12:32
@rodrigok rodrigok force-pushed the chore/build-with-production branch 16 times, most recently from ab695d5 to 428c82a Compare November 14, 2025 14:56
@rodrigok rodrigok force-pushed the chore/build-with-production branch from 428c82a to 2a347fb Compare November 14, 2025 15:02
@rodrigok rodrigok marked this pull request as ready for review November 14, 2025 15:02
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
.github/actions/build-docker/action.yml (1)

78-86: Minor: Typo in comment.

Line 78 has "sized" which should be "size" ("reduce image size" not "reduce image sized").

-        # Removes unnecessary swc cores to reduce image sized
+        # Removes unnecessary swc cores to reduce image size
.github/actions/meteor-build/action.yml (1)

180-192: Improve error handling and logging in cleanup loop.

The cleanup loop could fail silently or with unclear messages. Consider improving robustness:

  • Current: Simply echoes "Path not found" if directory doesn't exist
  • Risk: Typos in paths would be silently ignored, causing fewer modules to be removed than expected

Consider adding a summary at the end showing how many directories were actually removed vs. expected.

+        removed_count=0
+        total_count=${#meter_modules_to_remove[@]}
+
         for dir_path in "${meter_modules_to_remove[@]}"; do
           path=/tmp/dist/bundle/programs/server/npm/node_modules/${dir_path}
 
           if [ -d "$path" ]; then
               rm -rf "$path"
+              ((removed_count++))
               echo "Removed directory: $path"
           else
               echo "Path is not a directory or does not exist: $path"
           fi
         done
+
+        echo "Successfully removed $removed_count of $total_count expected directories"
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 421ee5f and 2a347fb.

📒 Files selected for processing (7)
  • .github/actions/build-docker/action.yml (1 hunks)
  • .github/actions/meteor-build/action.yml (3 hunks)
  • .github/actions/setup-node/action.yml (3 hunks)
  • .github/workflows/ci.yml (1 hunks)
  • apps/meteor/.docker/Dockerfile.alpine (3 hunks)
  • package.json (0 hunks)
  • turbo.json (0 hunks)
💤 Files with no reviewable changes (2)
  • package.json
  • turbo.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • .github/actions/setup-node/action.yml
  • .github/workflows/ci.yml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: 📦 Build Packages
  • GitHub Check: CodeQL-Build
  • GitHub Check: CodeQL-Build
🔇 Additional comments (9)
apps/meteor/.docker/Dockerfile.alpine (4)

1-19: Multi-stage build correctly achieves production-only image.

The builder stage properly installs only production dependencies via --omit=dev (line 12), and the final stage copies the built bundle from the builder without re-running npm install. Build tools (python3, make, g++) stay in the builder context and don't bloat the final image. This approach aligns with the PR goal of removing dev dependencies and should deliver the reported size reductions.


11-19: Verify sharp architecture-specific binary handling works as intended.

The sharp reininstall logic (lines 15–19) appears designed to refresh architecture-specific native bindings in @img, but the sequence—reinstalling sharp's dependencies within its own directory, then relocating @img to the parent scope, then discarding sharp's entire node_modules—is non-standard. Confirm that:

  1. The relocated @img folder is correctly discovered and used by the sharp module at runtime.
  2. The final image can successfully load sharp and its native bindings after this relocation.

Consider testing the built image against sharp-dependent functionality to ensure no runtime ENOENT or binding-load errors occur.


39-44: User and package setup is sound.

The shadow utility (line 39) is correctly used for non-root user creation (lines 43–44). The detailed comment block (lines 27–38) justifying the nogrouprocketchat remapping shows good security and compatibility reasoning. OpenSSL upgrade (line 42) and the explicit CVE reference are also appropriate for runtime security.


57-57: Correct use of COPY --from with ownership.

The COPY --from=builder --chown=rocketchat:rocketchat directive (line 57) ensures the app bundle is owned by the non-root user, maintaining proper file permissions and reducing privilege escalation risk.

.github/actions/build-docker/action.yml (1)

78-86: Path structure verified—cleanup logic is sound.

The hardcoded path /tmp/build/bundle/programs/server/npm/node_modules/meteor/babel-compiler/node_modules/@meteorjs/swc-core/.swc/node_modules/@swc is correct. The meteor-build action removes specific arch-specific SWC binaries during the build phase, and the build-docker action completes the cleanup by removing any remaining core-* directories not matching the target architecture. Both workflows reference the identical structure, confirming it exists as documented.

.github/actions/meteor-build/action.yml (4)

163-164: Clarify the purpose of package.json restoration before the build.

The workflow merges devDependencies into dependencies, installs with type='production', then restores the original package.json (with devDependencies listed) before building. This creates a mismatch: package.json lists devDependencies but node_modules doesn't contain them.

Verify that Meteor build doesn't rely on package.json matching node_modules contents, or explain why this restoration is necessary.


54-63: No issues found—setup-node action correctly supports type='production'.

The verification confirms that the .github/actions/setup-node action properly accepts the type input and implements the intended behavior: when type='production' is passed, it runs yarn workspaces focus --all --production, which excludes devDependencies as expected. The mechanism used in this PR is correctly implemented.


45-52: ****

The jq merge command at line 52 is safe. Analysis shows apps/meteor/package.json has 244 dependencies and 156 devDependencies with no overlapping packages. Since each package appears in only one list, the merge order is inconsequential, and no version conflicts can occur. The original concern about differing versions for the same package does not apply to this codebase.


168-197: The review comment contains misunderstandings about the cleanup logic.

The cleanup happens after yarn build:ci completes successfully. This is post-build size optimization, not pre-build removal:

  1. Platform-specific swc removal (lines 169-171): These removals target meteor/babel-compiler/node_modules/@swc/core-* binaries from Meteor's internal build tools, not the runtime. Since the build already succeeded, these unused architecture binaries can safely be removed from the bundle. The cache key includes ${{ runner.arch }}, so each architecture's build is cached separately.

  2. @babel handling (line 177): The commented removal is correct—root-level @babel is intentionally preserved. The code removes only meteor/babel-compiler/node_modules/@babel (Meteor's build-time @babel), not the production @babel package needed at runtime.

  3. .d.ts removal (line 196): Safe—these are build-time type definitions, verified by script showing no @babel/runtime imports in runtime code and no Minimongo dependency.

@sampaiodiego sampaiodiego added the stat: QA assured Means it has been tested and approved by a company insider label Nov 14, 2025
@dionisio-bot dionisio-bot bot added the stat: ready to merge PR tested and approved waiting for merge label Nov 14, 2025
@kodiakhq kodiakhq bot merged commit 0691514 into develop Nov 14, 2025
52 checks passed
@kodiakhq kodiakhq bot deleted the chore/build-with-production branch November 14, 2025 19:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stat: QA assured Means it has been tested and approved by a company insider stat: ready to merge PR tested and approved waiting for merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants