From ec8849f1cbe88f66350bfbb7f60f77e8d8483c61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Codo=C3=B1er?= Date: Mon, 8 Sep 2025 09:03:26 +0200 Subject: [PATCH 1/5] ensure "jsc.target" is always forced to be the internal babel-compiler value set --- packages/babel-compiler/babel-compiler.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/babel-compiler/babel-compiler.js b/packages/babel-compiler/babel-compiler.js index 2cf561970d..7bfceb32d1 100644 --- a/packages/babel-compiler/babel-compiler.js +++ b/packages/babel-compiler/babel-compiler.js @@ -375,6 +375,7 @@ BCp.processOneFileForTarget = function (inputFile, source) { // Merge with app-level SWC config if (lastModifiedSwcConfig) { swcOptions = deepMerge(swcOptions, lastModifiedSwcConfig, [ + 'jsc.target', 'env.targets', 'module.type', ]); From 303d2294c442015af57e150e2b8b3153c40401df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Codo=C3=B1er?= Date: Mon, 8 Sep 2025 10:17:39 +0200 Subject: [PATCH 2/5] ensure support of yarn when install tool deps --- packages/rspack/lib/dependencies.js | 18 ++++- packages/rspack/rspack_plugin.js | 12 ++++ packages/tools-core/lib/npm.js | 101 ++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+), 3 deletions(-) diff --git a/packages/rspack/lib/dependencies.js b/packages/rspack/lib/dependencies.js index f458457a5c..feb67ef3a3 100644 --- a/packages/rspack/lib/dependencies.js +++ b/packages/rspack/lib/dependencies.js @@ -81,6 +81,9 @@ async function ensureDependenciesInstalled(dependencies, globalStateKey, package logInfo(` • ${dep}`); }); + // Check if this is a Yarn project + const isYarnProj = process.env.YARN_ENABLED === 'true'; + // Install dev dependencies const devDepsToInstall = allDepsToInstall.filter(dep => dep.dev === true || dep.dev == null); if (devDepsToInstall.length > 0) { @@ -88,6 +91,7 @@ async function ensureDependenciesInstalled(dependencies, globalStateKey, package success = await installNpmDependency(devDepsStrings, { cwd: appDir, dev: true, + yarn: isYarnProj, }); } @@ -95,22 +99,30 @@ async function ensureDependenciesInstalled(dependencies, globalStateKey, package const depsToInstall = allDepsToInstall.filter(dep => dep.dev === false); if (depsToInstall.length > 0) { const depsStrings = depsToInstall.map(dep => `${dep.name}@${dep.version}`); - const depsSuccess = await installNpmDependency(depsStrings, { + + let depsSuccess; + depsSuccess = await installNpmDependency(depsStrings, { cwd: appDir, dev: false, + yarn: isYarnProj, }); success = success && depsSuccess; } if (!success) { + const isYarnProj = process.env.YARN_ENABLED === 'true'; + const installCommand = isYarnProj + ? `yarn add --dev ${joinWithAnd(dependencyStrings)}` + : `meteor npm install -D ${joinWithAnd(dependencyStrings)}`; + logError(`\n┌─────────────────────────────────────────────────`); logError(`│ ❌ ${packageName} Installation Failed`); logError(`└─────────────────────────────────────────────────`); - logError(`Run: meteor npm install -D ${joinWithAnd(dependencyStrings)}`); + logError(`Run: ${installCommand}`); throw new Error( - `Failed to install ${packageName} dependencies. Please install them manually with: meteor npm install -D ${joinWithAnd(dependencyStrings)}` + `Failed to install ${packageName} dependencies. Please install them manually with: ${installCommand}` ); } diff --git a/packages/rspack/rspack_plugin.js b/packages/rspack/rspack_plugin.js index 737e590796..c76f6dbd2b 100644 --- a/packages/rspack/rspack_plugin.js +++ b/packages/rspack/rspack_plugin.js @@ -79,17 +79,29 @@ const { const { getNpxCommand, getNpmCommand, + getYarnCommand, + isYarnProject, } = require('meteor/tools-core/lib/npm'); if (isMeteorAppRun() || isMeteorAppBuild() || isMeteorAppTest()) { // Get entry points from Meteor configuration setGlobalState(GLOBAL_STATE_KEYS.INITIAL_ENTRYPONTS, getMeteorAppEntrypoints()); + let isYarnProj = process.env.YARN_ENABLED === 'true'; + console.log("--> (rspack_plugin.js-Line: 91)\n process.env.YARN_ENABLED: ", process.env.YARN_ENABLED); // Main entry point - using top-level await try { + // Check if the project is a Yarn project and store the result in environment variable if not already set + if (process.env.YARN_ENABLED === undefined) { + isYarnProj = isYarnProject(); + process.env.YARN_ENABLED = isYarnProj ? 'true' : 'false'; + } if (isMeteorAppDebug() || isMeteorAppConfigModernVerbose()) { logInfo(`[i] Meteor Npx prefix: ${getNpxCommand([])?.prefix}`); logInfo(`[i] Meteor Npm prefix: ${getNpmCommand([])?.prefix}`); + if (isYarnProj) { + logInfo(`[i] Meteor Yarn prefix: ${getYarnCommand([])?.prefix}`); + } } // Clean build context files only if they haven't been cleaned yet diff --git a/packages/tools-core/lib/npm.js b/packages/tools-core/lib/npm.js index a07bad0b1a..315b52fb06 100644 --- a/packages/tools-core/lib/npm.js +++ b/packages/tools-core/lib/npm.js @@ -136,6 +136,37 @@ function buildNpmInstallArgs(dependencies, options = {}) { return args; } +/** + * Builds yarn install arguments based on options and dependencies + * + * @param {string|string[]} dependencies - The npm dependency or dependencies to install + * @param {Object} [options] - Options for the installation + * @param {boolean} [options.dev=false] - If true, install as a dev dependency + * @param {boolean} [options.exact=false] - If true, install with exact version + * @returns {string[]} Array of arguments for the yarn add command + */ +function buildYarnInstallArgs(dependencies, options = {}) { + const args = ['add']; + + // Add flags based on options + if (options.dev) { + args.push('--dev'); + } + + if (options.exact) { + args.push('--exact'); + } + + // Add dependencies to the command + if (Array.isArray(dependencies)) { + args.push(...dependencies); + } else { + args.push(dependencies); + } + + return args; +} + /** * Executes a command and returns a promise that resolves to true if successful * @@ -161,17 +192,26 @@ function executeCommand(command, args, options) { /** * Installs a npm dependency using direct npm binary if available, otherwise falls back to `meteor npm install`. + * If yarn option is true, uses yarn instead. * * @param {string|string[]} dependencies - The npm dependency or dependencies to install * @param {Object} [options] - Options for the installation * @param {string} [options.cwd] - Current working directory (defaults to process.cwd()) * @param {boolean} [options.dev=false] - If true, install as a dev dependency * @param {boolean} [options.exact=false] - If true, install with exact version + * @param {boolean} [options.yarn=false] - If true, use yarn instead of npm * @returns {Promise} A promise that resolves to true if installation succeeded, false otherwise */ export function installNpmDependency(dependencies, options = {}) { const cwd = options.cwd || process.cwd(); + // If yarn option is true, use yarn + if (options.yarn) { + const { command, args: baseArgs } = getYarnCommand([]); + const args = buildYarnInstallArgs(dependencies, options); + return executeCommand(command, [...baseArgs, ...args], { cwd }); + } + // Try to get the npm binary path const npmBinaryPath = getNodeBinaryPath('npm'); @@ -319,3 +359,64 @@ export function getNpxCommand(args) { prefix: `meteor npx`, }; } + +/** + * Checks if the current project is a Yarn project. + * Looks for yarn.lock file in the current working directory and checks packageManager in package.json. + * + * @param {Object} [options] - Options for the check + * @param {string} [options.cwd] - Current working directory (defaults to process.cwd()) + * @returns {boolean} True if it's a Yarn project, false otherwise + */ +export function isYarnProject(options = {}) { + const cwd = options.cwd || process.cwd(); + + // Check if yarn.lock exists + const yarnLockPath = path.join(cwd, 'yarn.lock'); + if (fs.existsSync(yarnLockPath)) { + return true; + } + + // Check packageManager field in package.json + try { + const packageJsonPath = path.join(cwd, 'package.json'); + if (fs.existsSync(packageJsonPath)) { + const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); + + // Check if packageManager contains "yarn" + if (packageJson.packageManager && packageJson.packageManager.includes('yarn')) { + return true; + } + } + } catch (error) { + // If there's an error reading or parsing package.json, continue + } + + return false; +} + +/** + * Gets the yarn command and arguments + * @param {string[]} args - The arguments to pass to yarn + * @returns {Object} An object with command, args, and base properties + */ +export function getYarnCommand(args) { + // Try to get the yarn binary path + const yarnBinaryPath = getNodeBinaryPath('yarn'); + + // If we have a direct path to yarn, use it + if (yarnBinaryPath && fs.existsSync(yarnBinaryPath)) { + return { + command: yarnBinaryPath, + args, + prefix: `${yarnBinaryPath}`, + }; + } + + // Fall back to using 'yarn' directly + return { + command: 'yarn', + args, + prefix: `yarn`, + }; +} From f3fbc6471188dfc564345cb95acce786b54831d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Codo=C3=B1er?= Date: Mon, 8 Sep 2025 10:19:52 +0200 Subject: [PATCH 3/5] ensure support of yarn when install tool deps --- packages/rspack/rspack_plugin.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/rspack/rspack_plugin.js b/packages/rspack/rspack_plugin.js index c76f6dbd2b..2206883fe5 100644 --- a/packages/rspack/rspack_plugin.js +++ b/packages/rspack/rspack_plugin.js @@ -88,7 +88,6 @@ if (isMeteorAppRun() || isMeteorAppBuild() || isMeteorAppTest()) { setGlobalState(GLOBAL_STATE_KEYS.INITIAL_ENTRYPONTS, getMeteorAppEntrypoints()); let isYarnProj = process.env.YARN_ENABLED === 'true'; - console.log("--> (rspack_plugin.js-Line: 91)\n process.env.YARN_ENABLED: ", process.env.YARN_ENABLED); // Main entry point - using top-level await try { // Check if the project is a Yarn project and store the result in environment variable if not already set From 55b0e9b7f09fe391b6cdf459662d4984c1e46958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Codo=C3=B1er?= Date: Mon, 8 Sep 2025 10:29:00 +0200 Subject: [PATCH 4/5] add support for configurable dependency auto-installation --- packages/rspack/rspack_plugin.js | 14 +++++++++----- packages/tools-core/lib/meteor.js | 9 +++++++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/packages/rspack/rspack_plugin.js b/packages/rspack/rspack_plugin.js index 2206883fe5..4296cf98a3 100644 --- a/packages/rspack/rspack_plugin.js +++ b/packages/rspack/rspack_plugin.js @@ -82,6 +82,7 @@ const { getYarnCommand, isYarnProject, } = require('meteor/tools-core/lib/npm'); +const { getMeteorAppConfig, hasMeteorAppConfigAutoInstallDeps } = require("../tools-core/lib/meteor"); if (isMeteorAppRun() || isMeteorAppBuild() || isMeteorAppTest()) { // Get entry points from Meteor configuration @@ -109,12 +110,15 @@ if (isMeteorAppRun() || isMeteorAppBuild() || isMeteorAppTest()) { setGlobalState(GLOBAL_STATE_KEYS.BUILD_CONTEXT_FILES_CLEANED, true); } - // Ensure Rspack is installed - await ensureRspackInstalled(); + // Auto install deps (by default enabled) + if (hasMeteorAppConfigAutoInstallDeps()) { + // Ensure Rspack is installed + await ensureRspackInstalled(); - // Check if Rspack React is installed - if (checkReactInstalled()) { - await ensureRspackReactInstalled(); + // Check if Rspack React is installed + if (checkReactInstalled()) { + await ensureRspackReactInstalled(); + } } // Ensure the Rspack build context directory exists diff --git a/packages/tools-core/lib/meteor.js b/packages/tools-core/lib/meteor.js index 2e00f1f9fb..51803481e2 100644 --- a/packages/tools-core/lib/meteor.js +++ b/packages/tools-core/lib/meteor.js @@ -54,6 +54,15 @@ export function isMeteorAppConfigModernVerbose() { getMeteorAppConfigModern()?.transpiler?.verbose || false; } +/** + * Retrieves the auto install deps flag from the app's package.json. + * @returns {Boolean|*} + */ +export function hasMeteorAppConfigAutoInstallDeps() { + const { autoInstallDeps = true } = getMeteorAppConfig() || {}; + return autoInstallDeps; +} + /** * Retrieves the entry points for the Meteor application from the configuration. * Uses Plugin.getMeteorConfig() if available, otherwise falls back to getMeteorAppConfig(). From 5ad89cfea7fa8b7351640c2da6a62e3870f6303a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Codo=C3=B1er?= Date: Mon, 8 Sep 2025 14:58:00 +0200 Subject: [PATCH 5/5] ensure boolean conversion for dependency auto-installation config --- packages/tools-core/lib/meteor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tools-core/lib/meteor.js b/packages/tools-core/lib/meteor.js index 51803481e2..9cb98c6acb 100644 --- a/packages/tools-core/lib/meteor.js +++ b/packages/tools-core/lib/meteor.js @@ -60,7 +60,7 @@ export function isMeteorAppConfigModernVerbose() { */ export function hasMeteorAppConfigAutoInstallDeps() { const { autoInstallDeps = true } = getMeteorAppConfig() || {}; - return autoInstallDeps; + return !!autoInstallDeps; } /**