From 0850049dd033835c55f00ee3e0facecd3243eb1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Codo=C3=B1er?= Date: Mon, 8 Sep 2025 16:23:16 +0200 Subject: [PATCH] add TypeScript support for Meteor Rspack plugin when typescript npm dep exists --- packages/rspack/lib/constants.js | 1 + packages/rspack/lib/dependencies.js | 28 +++++++++++++++++++ packages/rspack/lib/processes.js | 13 +++++---- packages/rspack/rspack_plugin.js | 11 ++++++-- packages/tools-core/lib/meteor.js | 8 ++++++ .../apps/react-router/package.json | 3 +- .../apps/react-router/server/main.js | 2 ++ .../apps/react-router/server/ts/helpers.ts | 1 + 8 files changed, 59 insertions(+), 8 deletions(-) create mode 100644 tools/modern-tests/apps/react-router/server/ts/helpers.ts diff --git a/packages/rspack/lib/constants.js b/packages/rspack/lib/constants.js index 998fddf5e0..5349ed18e6 100644 --- a/packages/rspack/lib/constants.js +++ b/packages/rspack/lib/constants.js @@ -36,6 +36,7 @@ export const GLOBAL_STATE_KEYS = { RSPACK_REACT_INSTALLATION_CHECKED: 'rspack.rspackReactInstallationChecked', RSPACK_DOCTOR_INSTALLATION_CHECKED: 'rspack.rspackDoctorInstallationChecked', REACT_CHECKED: 'rspack.reactChecked', + TYPESCRIPT_CHECKED: 'rspack.typescriptChecked', INITIAL_ENTRYPONTS: 'meteor.initialEntrypoints', CLIENT_FIRST_COMPILE: 'rspack.clientFirstCompile', SERVER_FIRST_COMPILE: 'rspack.serverFirstCompile', diff --git a/packages/rspack/lib/dependencies.js b/packages/rspack/lib/dependencies.js index feb67ef3a3..df9bdebf11 100644 --- a/packages/rspack/lib/dependencies.js +++ b/packages/rspack/lib/dependencies.js @@ -211,3 +211,31 @@ export async function ensureRspackDoctorInstalled() { 'Rspack Doctor' ); } + +/** + * Checks if TypeScript is installed and sets global state accordingly + * Sets global state and environment variables based on TypeScript detection + * @returns {boolean} Whether TypeScript is installed + */ +export function checkTypescriptInstalled() { + // Skip if already checked + if (getGlobalState(GLOBAL_STATE_KEYS.TYPESCRIPT_CHECKED, false)) { + return; + } + + const appDir = getMeteorAppDir(); + // Check if TypeScript is a dependency in the project + const isTypescriptInstalled = checkNpmDependencyExists('typescript', { cwd: appDir }); + + if (isTypescriptInstalled) { + // Set environment variable to indicate TypeScript is enabled + process.env.METEOR_TYPESCRIPT_ENABLED = 'true'; + } else { + process.env.METEOR_TYPESCRIPT_ENABLED = 'false'; + } + + // Mark as checked + setGlobalState(GLOBAL_STATE_KEYS.TYPESCRIPT_CHECKED, true); + + return isTypescriptInstalled; +} diff --git a/packages/rspack/lib/processes.js b/packages/rspack/lib/processes.js index fbd4d1c787..d222cf118a 100644 --- a/packages/rspack/lib/processes.js +++ b/packages/rspack/lib/processes.js @@ -3,7 +3,7 @@ * @description Functions for managing Rspack processes */ import { checkNpmDependencyExists, getNpxCommand } from 'meteor/tools-core/lib/npm'; -import { getMeteorAppPort } from 'meteor/tools-core/lib/meteor'; +import { getMeteorAppPort, isMeteorTypescriptProject } from 'meteor/tools-core/lib/meteor'; /** * Calculates the devServerPort based on process.env.PORT @@ -136,11 +136,14 @@ export function getRspackEnv({ isClient, isServer, isTest: inIsTest }) { const entryKey = `${isTest && isTestModule ? 'test' : 'main'}${isClient ? 'Client' : 'Server'}`; const inputFilePath = isTest && isTestModule ? initialEntrypoints.testModule : initialEntrypoints[entryKey]; - const isTypescriptEnabled = inputFilePath?.endsWith('.ts') || inputFilePath?.endsWith('.tsx'); - const isTsxEnabled = inputFilePath?.endsWith('.tsx'); - const isJsxEnabled = inputFilePath?.endsWith('.jsx'); + const isTypescriptEnabled = process.env.METEOR_TYPESCRIPT_ENABLED === 'true' || + inputFilePath?.endsWith('.ts') || + inputFilePath?.endsWith('.tsx'); + + const isReactEnabled = process.env.METEOR_REACT_ENABLED === 'true'; + const isTsxEnabled = inputFilePath?.endsWith('.tsx') || isReactEnabled; + const isJsxEnabled = inputFilePath?.endsWith('.jsx') || isReactEnabled; - const isReactEnabled = !!process.env.METEOR_REACT_ENABLED; const isBlazeEnabled = isMeteorBlazeProject(); const isBlazeHotEnabled = isMeteorBlazeHotProject(); const isBundleVisualizerEnabled = isMeteorBundleVisualizerProject(); diff --git a/packages/rspack/rspack_plugin.js b/packages/rspack/rspack_plugin.js index 4296cf98a3..5892feb615 100644 --- a/packages/rspack/rspack_plugin.js +++ b/packages/rspack/rspack_plugin.js @@ -22,6 +22,7 @@ const { const { ensureRspackInstalled, checkReactInstalled, + checkTypescriptInstalled, ensureRspackReactInstalled, } = require('./lib/dependencies'); @@ -114,13 +115,19 @@ if (isMeteorAppRun() || isMeteorAppBuild() || isMeteorAppTest()) { if (hasMeteorAppConfigAutoInstallDeps()) { // Ensure Rspack is installed await ensureRspackInstalled(); + } - // Check if Rspack React is installed - if (checkReactInstalled()) { + // Check if Rspack React is installed + if (checkReactInstalled()) { + // Auto install deps (by default enabled) + if (hasMeteorAppConfigAutoInstallDeps()) { await ensureRspackReactInstalled(); } } + // Check if TypeScript is installed + checkTypescriptInstalled(); + // Ensure the Rspack build context directory exists ensureRspackBuildContextExists(); diff --git a/packages/tools-core/lib/meteor.js b/packages/tools-core/lib/meteor.js index 9cb98c6acb..0d69ba2283 100644 --- a/packages/tools-core/lib/meteor.js +++ b/packages/tools-core/lib/meteor.js @@ -421,6 +421,14 @@ export function isMeteorBundleVisualizerProject() { return getMeteorAppPackages().includes('bundle-visualizer'); } +/** + * Checks if the Meteor application is a Typescript project. + * @returns {boolean} True if the application is a Typescript project, false otherwise. + */ +export function isMeteorTypescriptProject() { + return getMeteorAppPackages().includes('typescript'); +} + /** * Checks if the current Meteor command is 'test-packages'. * @returns {boolean} True if the current command is 'test-packages', false otherwise. diff --git a/tools/modern-tests/apps/react-router/package.json b/tools/modern-tests/apps/react-router/package.json index 9e3c78d80b..753fec1e49 100644 --- a/tools/modern-tests/apps/react-router/package.json +++ b/tools/modern-tests/apps/react-router/package.json @@ -26,7 +26,8 @@ "babel-loader": "^9.1.3", "less": "^4.4.0", "less-loader": "^12.3.0", - "playwright": "^1.54.2" + "playwright": "^1.54.2", + "typescript": "^5.9.2" }, "meteor": { "mainModule": { diff --git a/tools/modern-tests/apps/react-router/server/main.js b/tools/modern-tests/apps/react-router/server/main.js index cdb3e6ccfd..4f036e6af4 100644 --- a/tools/modern-tests/apps/react-router/server/main.js +++ b/tools/modern-tests/apps/react-router/server/main.js @@ -5,8 +5,10 @@ import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/ import '@helper/alias'; import ReactAlias from '@react/alias'; import './resolve-extensions/first'; +import { TypescriptEnabled } from './ts/helpers'; console.log('@react/alias loaded', ReactAlias.version); +console.log('TypescriptEnabled', TypescriptEnabled); async function insertLink({ title, url }) { await LinksCollection.insertAsync({ title, url, createdAt: new Date() }); diff --git a/tools/modern-tests/apps/react-router/server/ts/helpers.ts b/tools/modern-tests/apps/react-router/server/ts/helpers.ts new file mode 100644 index 0000000000..67a82d6f6c --- /dev/null +++ b/tools/modern-tests/apps/react-router/server/ts/helpers.ts @@ -0,0 +1 @@ +export const TypescriptEnabled: boolean = true;