From 1be8c39a3bced1c22168d19e30f1bf0343b7f03f Mon Sep 17 00:00:00 2001 From: thenileshmishra Date: Mon, 26 Jan 2026 23:09:36 +0530 Subject: [PATCH 01/26] fix(typescript): enable skipLibCheck to avoid broken third-party d.ts failures --- tools/static-assets/skel-typescript/tsconfig.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/static-assets/skel-typescript/tsconfig.json b/tools/static-assets/skel-typescript/tsconfig.json index 5806f496d5..9d9742a7c5 100644 --- a/tools/static-assets/skel-typescript/tsconfig.json +++ b/tools/static-assets/skel-typescript/tsconfig.json @@ -36,7 +36,9 @@ "resolveJsonModule": true, "types": ["node", "mocha"], "esModuleInterop": true, - "preserveSymlinks": true + "preserveSymlinks": true, + "skipLibCheck": true + }, "exclude": [ "./.meteor/**", From 644952bff57b044566fb1304ec07f022e36be36c Mon Sep 17 00:00:00 2001 From: Harry Adel Date: Thu, 19 Feb 2026 02:40:26 +0200 Subject: [PATCH 02/26] Add absolute URLs to llms.txt --- v3-docs/docs/.vitepress/config.mts | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/v3-docs/docs/.vitepress/config.mts b/v3-docs/docs/.vitepress/config.mts index bef4db33ed..08b471f0d1 100644 --- a/v3-docs/docs/.vitepress/config.mts +++ b/v3-docs/docs/.vitepress/config.mts @@ -667,7 +667,27 @@ export default defineConfig({ vite: { plugins: [ llmstxt({ - title: "Meteor.js 3 Docs", + title: "Meteor.js 3 Documentation", + domain: "https://docs.meteor.com", + description: "Full-stack JavaScript platform for modern web and mobile applications.", + details: ` +Meteor is a full-stack JavaScript platform for developing web and mobile applications. + +Key capabilities: +- Real-time data synchronization with publications and subscriptions +- Built-in accounts and authentication system +- Frontend agnostic (React, Vue, Solid, Blaze, Svelte) +- Zero-config build system with modern tooling (SWC, Rspack) +- One-command deployment to Galaxy Cloud +- TypeScript support with full type inference + +Current version: Meteor 3.4 with Node.js 22.x support. + +## Structured API Data + +For complete API documentation in machine-readable format, see: +- [api-reference.json](/api-reference.json) - Full API reference with all functions, parameters, and types + `.trim(), }), ], }, From ded541a7bee5f25c1348d74d19ca951ce43c397c Mon Sep 17 00:00:00 2001 From: Harry Adel Date: Thu, 19 Feb 2026 02:40:44 +0200 Subject: [PATCH 03/26] Export API reference JSON --- v3-docs/docs/.gitignore | 5 +- .../generators/api-export/generateApiJson.js | 65 +++++++++++++++++++ v3-docs/docs/generators/codegen.js | 3 + 3 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 v3-docs/docs/generators/api-export/generateApiJson.js diff --git a/v3-docs/docs/.gitignore b/v3-docs/docs/.gitignore index bcd2cabb66..60c63498eb 100644 --- a/v3-docs/docs/.gitignore +++ b/v3-docs/docs/.gitignore @@ -3,4 +3,7 @@ /.vitepress/dist /data/data.js -/data/names.json \ No newline at end of file +/data/names.json + +# Generated API reference for LLMs +/public/api-reference.json \ No newline at end of file diff --git a/v3-docs/docs/generators/api-export/generateApiJson.js b/v3-docs/docs/generators/api-export/generateApiJson.js new file mode 100644 index 0000000000..1ab371ed9d --- /dev/null +++ b/v3-docs/docs/generators/api-export/generateApiJson.js @@ -0,0 +1,65 @@ +/** + * Generates a public JSON file from the JSDoc API data. + * This file is accessible to LLMs at /api-reference.json + */ + +const fs = require('fs'); +const path = require('path'); + +async function generateApiJson() { + console.log("πŸ“¦ Generating API reference JSON for LLMs..."); + + const dataPath = path.join(__dirname, '../../data/data.js'); + const publicDir = path.join(__dirname, '../../public'); + const outputPath = path.join(publicDir, 'api-reference.json'); + + // Check if data.js exists + if (!fs.existsSync(dataPath)) { + console.log("⚠️ data/data.js not found. Run 'npm run generate-jsdoc' first."); + return; + } + + // Read the data.js file + const dataContent = fs.readFileSync(dataPath, 'utf-8'); + + // Extract the JSON from the ES module export + // The file format is: // comment\nexport default{...}; + const jsonMatch = dataContent.match(/export default\s*(\{[\s\S]*\});?\s*$/); + + if (!jsonMatch) { + console.error("❌ Could not parse data/data.js"); + return; + } + + try { + // Parse the JSON + const apiData = JSON.parse(jsonMatch[1]); + + // Create public directory if it doesn't exist + if (!fs.existsSync(publicDir)) { + fs.mkdirSync(publicDir, { recursive: true }); + } + + // Add metadata + const output = { + _meta: { + generator: "Meteor Docs API Export", + generated: new Date().toISOString(), + description: "API reference for Meteor.js - for LLM consumption", + url: "https://docs.meteor.com/api-reference.json" + }, + apis: apiData + }; + + // Write the JSON file + fs.writeFileSync(outputPath, JSON.stringify(output, null, 2)); + + const apiCount = Object.keys(apiData).length; + console.log(`βœ… Generated api-reference.json with ${apiCount} APIs`); + + } catch (err) { + console.error("❌ Error generating API JSON:", err.message); + } +} + +module.exports = { generateApiJson }; diff --git a/v3-docs/docs/generators/codegen.js b/v3-docs/docs/generators/codegen.js index a6ed7ab00a..fae6b7a8af 100644 --- a/v3-docs/docs/generators/codegen.js +++ b/v3-docs/docs/generators/codegen.js @@ -1,11 +1,14 @@ const { generateChangelog } = require("./changelog/script.js"); const { listPackages } = require("./packages-listing/script.js"); const { generateMeteorVersions } = require("./meteor-versions/script.js"); +const { generateApiJson } = require("./api-export/generateApiJson.js"); + async function main() { console.log("πŸš‚ Started codegen πŸš‚"); await generateChangelog(); await listPackages(); await generateMeteorVersions(); + await generateApiJson(); console.log("πŸš€ Done codegen πŸš€"); } From d57e1499340174bf6583251ae9cabef4c111afdf Mon Sep 17 00:00:00 2001 From: shanky Date: Mon, 16 Feb 2026 20:14:06 +0530 Subject: [PATCH 04/26] fix: Add support for swc.config.ts in Meteor 3.4 --- npm-packages/meteor-rspack/lib/swc.js | 35 ++++++++++++++++----- npm-packages/meteor-rspack/rspack.config.js | 3 ++ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/npm-packages/meteor-rspack/lib/swc.js b/npm-packages/meteor-rspack/lib/swc.js index 8b43703059..61296d24d8 100644 --- a/npm-packages/meteor-rspack/lib/swc.js +++ b/npm-packages/meteor-rspack/lib/swc.js @@ -9,12 +9,32 @@ const vm = require('vm'); function getMeteorAppSwcrc(file = '.swcrc') { try { const filePath = `${process.cwd()}/${file}`; - if (file.endsWith('.js')) { + if (file.endsWith('.js') || file.endsWith('.ts')) { let content = fs.readFileSync(filePath, 'utf-8'); - // Check if the content uses ES module syntax (export default) - if (content.includes('export default')) { - // Transform ES module syntax to CommonJS - content = content.replace(/export\s+default\s+/, 'module.exports = '); + + if (file.endsWith('.ts')) { + try { + const esbuild = require('esbuild'); + const result = esbuild.transformSync(content, { + loader: 'ts', + format: 'cjs', + target: 'node14', + }); + content = result.code; + } catch (esbuildError) { + content = content + .replace(/import\s+type\s+.*?from\s+['"][^'"]+['"];?/g, '') + .replace(/import\s+.*?from\s+['"][^'"]+['"];?/g, '') + .replace(/import\s+['"][^'"]+['"];?/g, '') + .replace(/export\s+default\s+/, 'module.exports = ') + .replace(/export\s+/g, '') + .replace(/:\s*\w+(\[\])?(\s*=)/g, '$2') + .replace(/\(([^)]*?):\s*\w+(\[\])?\)/g, '($1)') + .replace(/\):\s*\w+(\[\])?\s*\{/g, ') {') + .replace(/interface\s+\w+\s*\{[^}]*\}/g, '') + .replace(/type\s+\w+\s*=\s*[^;]+;/g, '') + .replace(/as\s+\w+(\[\])?/g, ''); + } } const script = new vm.Script(` (function() { @@ -45,12 +65,13 @@ function getMeteorAppSwcrc(file = '.swcrc') { function getMeteorAppSwcConfig() { const hasSwcRc = fs.existsSync(`${process.cwd()}/.swcrc`); const hasSwcJs = !hasSwcRc && fs.existsSync(`${process.cwd()}/swc.config.js`); + const hasSwcTs = !hasSwcRc && !hasSwcJs && fs.existsSync(`${process.cwd()}/swc.config.ts`); - if (!hasSwcRc && !hasSwcJs) { + if (!hasSwcRc && !hasSwcJs && !hasSwcTs) { return undefined; } - const swcFile = hasSwcJs ? 'swc.config.js' : '.swcrc'; + const swcFile = hasSwcTs ? 'swc.config.ts' : hasSwcJs ? 'swc.config.js' : '.swcrc'; const config = getMeteorAppSwcrc(swcFile); // Set baseUrl to process.cwd() if it exists diff --git a/npm-packages/meteor-rspack/rspack.config.js b/npm-packages/meteor-rspack/rspack.config.js index 09138424a7..20da463411 100644 --- a/npm-packages/meteor-rspack/rspack.config.js +++ b/npm-packages/meteor-rspack/rspack.config.js @@ -52,6 +52,8 @@ function createCacheStrategy(mode, side, { projectConfigPath, configPath } = {}) const hasSwcrcConfig = fs.existsSync(swcrcPath); const swcJsPath = path.join(process.cwd(), 'swc.config.js'); const hasSwcJsConfig = fs.existsSync(swcJsPath); + const swcTsPath = path.join(process.cwd(), 'swc.config.ts'); + const hasSwcTsConfig = fs.existsSync(swcTsPath); const postcssConfigPath = path.join(process.cwd(), 'postcss.config.js'); const hasPostcssConfig = fs.existsSync(postcssConfigPath); const packageLockPath = path.join(process.cwd(), 'package-lock.json'); @@ -68,6 +70,7 @@ function createCacheStrategy(mode, side, { projectConfigPath, configPath } = {}) ...(hasBabelJsConfig ? [babelJsConfig] : []), ...(hasSwcrcConfig ? [swcrcPath] : []), ...(hasSwcJsConfig ? [swcJsPath] : []), + ...(hasSwcTsConfig ? [swcTsPath] : []), ...(hasPostcssConfig ? [postcssConfigPath] : []), ...(hasPackageLock ? [packageLockPath] : []), ...(hasYarnLock ? [yarnLockPath] : []), From 134b28d6879d3bc82c370b99b7a76e61688f3134 Mon Sep 17 00:00:00 2001 From: shanky Date: Wed, 18 Feb 2026 23:07:21 +0530 Subject: [PATCH 05/26] fix: Use @swc/core and add babel-compiler support for swc.config.ts --- npm-packages/meteor-rspack/lib/swc.js | 22 ++++++++---- packages/babel-compiler/babel-compiler.js | 41 ++++++++++++++++++++--- 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/npm-packages/meteor-rspack/lib/swc.js b/npm-packages/meteor-rspack/lib/swc.js index 61296d24d8..6a3a3ea869 100644 --- a/npm-packages/meteor-rspack/lib/swc.js +++ b/npm-packages/meteor-rspack/lib/swc.js @@ -14,14 +14,20 @@ function getMeteorAppSwcrc(file = '.swcrc') { if (file.endsWith('.ts')) { try { - const esbuild = require('esbuild'); - const result = esbuild.transformSync(content, { - loader: 'ts', - format: 'cjs', - target: 'node14', + const swc = require('@swc/core'); + const result = swc.transformSync(content, { + jsc: { + parser: { + syntax: 'typescript', + }, + target: 'es2015', + }, + module: { + type: 'commonjs', + }, }); content = result.code; - } catch (esbuildError) { + } catch (swcError) { content = content .replace(/import\s+type\s+.*?from\s+['"][^'"]+['"];?/g, '') .replace(/import\s+.*?from\s+['"][^'"]+['"];?/g, '') @@ -36,6 +42,10 @@ function getMeteorAppSwcrc(file = '.swcrc') { .replace(/as\s+\w+(\[\])?/g, ''); } } + + if (content.includes('export default')) { + content = content.replace(/export\s+default\s+/, 'module.exports = '); + } const script = new vm.Script(` (function() { const module = {}; diff --git a/packages/babel-compiler/babel-compiler.js b/packages/babel-compiler/babel-compiler.js index 0de0637df2..43324e11e5 100644 --- a/packages/babel-compiler/babel-compiler.js +++ b/packages/babel-compiler/babel-compiler.js @@ -101,16 +101,17 @@ let lastModifiedSwcConfigTime; BCp.initializeMeteorAppSwcrc = function () { const hasSwcRc = fs.existsSync(`${getMeteorAppDir()}/.swcrc`); const hasSwcJs = !hasSwcRc && fs.existsSync(`${getMeteorAppDir()}/swc.config.js`); - if (!lastModifiedSwcConfig && !hasSwcRc && !hasSwcJs) { + const hasSwcTs = !hasSwcRc && !hasSwcJs && fs.existsSync(`${getMeteorAppDir()}/swc.config.ts`); + if (!lastModifiedSwcConfig && !hasSwcRc && !hasSwcJs && !hasSwcTs) { return; } - const swcFile = hasSwcJs ? 'swc.config.js' : '.swcrc'; + const swcFile = hasSwcTs ? 'swc.config.ts' : hasSwcJs ? 'swc.config.js' : '.swcrc'; const filePath = `${getMeteorAppDir()}/${swcFile}`; const fileStats = fs.statSync(filePath); const fileModTime = fileStats?.mtime?.getTime(); let currentLastModifiedConfigTime; - if (hasSwcJs) { + if (hasSwcJs || hasSwcTs) { // For dynamic JS files, first get the resolved configuration const resolvedConfig = lastModifiedSwcConfigTime?.includes(`${fileModTime}`) ? lastModifiedSwcConfig || getMeteorAppSwcrc(swcFile) @@ -1073,8 +1074,40 @@ function getMeteorAppPackageJson() { function getMeteorAppSwcrc(file = '.swcrc') { try { const filePath = `${getMeteorAppDir()}/${file}`; - if (file.endsWith('.js')) { + if (file.endsWith('.js') || file.endsWith('.ts')) { let content = fs.readFileSync(filePath, 'utf-8'); + + if (file.endsWith('.ts')) { + try { + const swc = require('@meteorjs/swc-core'); + const result = swc.transformSync(content, { + jsc: { + parser: { + syntax: 'typescript', + }, + target: 'es2015', + }, + module: { + type: 'commonjs', + }, + }); + content = result.code; + } catch (swcError) { + content = content + .replace(/import\s+type\s+.*?from\s+['"][^'"]+['"];?/g, '') + .replace(/import\s+.*?from\s+['"][^'"]+['"];?/g, '') + .replace(/import\s+['"][^'"]+['"];?/g, '') + .replace(/export\s+default\s+/, 'module.exports = ') + .replace(/export\s+/g, '') + .replace(/:\s*\w+(\[\])?(\s*=)/g, '$2') + .replace(/\(([^)]*?):\s*\w+(\[\])?\)/g, '($1)') + .replace(/\):\s*\w+(\[\])?\s*\{/g, ') {') + .replace(/interface\s+\w+\s*\{[^}]*\}/g, '') + .replace(/type\s+\w+\s*=\s*[^;]+;/g, '') + .replace(/as\s+\w+(\[\])?/g, ''); + } + } + // Check if the content uses ES module syntax (export default) if (content.includes('export default')) { // Transform ES module syntax to CommonJS From d6242fe0da51bea7b50bff30ee8393916d241f89 Mon Sep 17 00:00:00 2001 From: Harry Adel Date: Sun, 1 Mar 2026 23:41:24 +0200 Subject: [PATCH 06/26] Get version dynamically --- v3-docs/docs/.vitepress/config.mts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v3-docs/docs/.vitepress/config.mts b/v3-docs/docs/.vitepress/config.mts index 08b471f0d1..d7644fd222 100644 --- a/v3-docs/docs/.vitepress/config.mts +++ b/v3-docs/docs/.vitepress/config.mts @@ -681,7 +681,7 @@ Key capabilities: - One-command deployment to Galaxy Cloud - TypeScript support with full type inference -Current version: Meteor 3.4 with Node.js 22.x support. +Current version: Meteor ${metadata.currentVersion}. ## Structured API Data From 78e1d397e6f5d23554338746297db489369d70a9 Mon Sep 17 00:00:00 2001 From: Harry Adel Date: Sun, 1 Mar 2026 23:41:50 +0200 Subject: [PATCH 07/26] Replace regex with dynamic import --- .../generators/api-export/generateApiJson.js | 33 +++++++------------ 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/v3-docs/docs/generators/api-export/generateApiJson.js b/v3-docs/docs/generators/api-export/generateApiJson.js index 1ab371ed9d..16e11fb3a3 100644 --- a/v3-docs/docs/generators/api-export/generateApiJson.js +++ b/v3-docs/docs/generators/api-export/generateApiJson.js @@ -5,41 +5,30 @@ const fs = require('fs'); const path = require('path'); +const { pathToFileURL } = require('url'); async function generateApiJson() { console.log("πŸ“¦ Generating API reference JSON for LLMs..."); - + const dataPath = path.join(__dirname, '../../data/data.js'); const publicDir = path.join(__dirname, '../../public'); const outputPath = path.join(publicDir, 'api-reference.json'); - + // Check if data.js exists if (!fs.existsSync(dataPath)) { console.log("⚠️ data/data.js not found. Run 'npm run generate-jsdoc' first."); return; } - - // Read the data.js file - const dataContent = fs.readFileSync(dataPath, 'utf-8'); - - // Extract the JSON from the ES module export - // The file format is: // comment\nexport default{...}; - const jsonMatch = dataContent.match(/export default\s*(\{[\s\S]*\});?\s*$/); - - if (!jsonMatch) { - console.error("❌ Could not parse data/data.js"); - return; - } - + try { - // Parse the JSON - const apiData = JSON.parse(jsonMatch[1]); - + // Dynamically import the ESM data module + const { default: apiData } = await import(pathToFileURL(dataPath).href); + // Create public directory if it doesn't exist if (!fs.existsSync(publicDir)) { fs.mkdirSync(publicDir, { recursive: true }); } - + // Add metadata const output = { _meta: { @@ -50,13 +39,13 @@ async function generateApiJson() { }, apis: apiData }; - + // Write the JSON file fs.writeFileSync(outputPath, JSON.stringify(output, null, 2)); - + const apiCount = Object.keys(apiData).length; console.log(`βœ… Generated api-reference.json with ${apiCount} APIs`); - + } catch (err) { console.error("❌ Error generating API JSON:", err.message); } From 8cf87eafad0e0911ccca68288ec39a541767c1ce Mon Sep 17 00:00:00 2001 From: shanky Date: Wed, 4 Mar 2026 00:26:48 +0530 Subject: [PATCH 08/26] fix: remove module CJS transform to prevent exports.default wrapping --- npm-packages/meteor-rspack/lib/swc.js | 7 +++---- packages/babel-compiler/babel-compiler.js | 9 ++++----- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/npm-packages/meteor-rspack/lib/swc.js b/npm-packages/meteor-rspack/lib/swc.js index 6a3a3ea869..e113ad1626 100644 --- a/npm-packages/meteor-rspack/lib/swc.js +++ b/npm-packages/meteor-rspack/lib/swc.js @@ -22,9 +22,6 @@ function getMeteorAppSwcrc(file = '.swcrc') { }, target: 'es2015', }, - module: { - type: 'commonjs', - }, }); content = result.code; } catch (swcError) { @@ -57,7 +54,9 @@ function getMeteorAppSwcrc(file = '.swcrc') { })() `); const context = vm.createContext({ process }); - return script.runInContext(context); + const result = script.runInContext(context); + // Handle CJS interop wrapper (e.g. { __esModule: true, default: config }) + return result && result.__esModule && result.default ? result.default : result; } else { // For .swcrc and other JSON files, parse as JSON return JSON.parse(fs.readFileSync(filePath, 'utf-8')); diff --git a/packages/babel-compiler/babel-compiler.js b/packages/babel-compiler/babel-compiler.js index 43324e11e5..2fdb836de0 100644 --- a/packages/babel-compiler/babel-compiler.js +++ b/packages/babel-compiler/babel-compiler.js @@ -112,7 +112,7 @@ BCp.initializeMeteorAppSwcrc = function () { let currentLastModifiedConfigTime; if (hasSwcJs || hasSwcTs) { - // For dynamic JS files, first get the resolved configuration + // For dynamic JS/TS files, first get the resolved configuration const resolvedConfig = lastModifiedSwcConfigTime?.includes(`${fileModTime}`) ? lastModifiedSwcConfig || getMeteorAppSwcrc(swcFile) : getMeteorAppSwcrc(swcFile); @@ -1087,9 +1087,6 @@ function getMeteorAppSwcrc(file = '.swcrc') { }, target: 'es2015', }, - module: { - type: 'commonjs', - }, }); content = result.code; } catch (swcError) { @@ -1124,7 +1121,9 @@ function getMeteorAppSwcrc(file = '.swcrc') { })() `); const context = vm.createContext({ process }); - return script.runInContext(context); + const result = script.runInContext(context); + // Handle CJS interop wrapper (e.g. { __esModule: true, default: config }) + return result && result.__esModule && result.default ? result.default : result; } else { // For .swcrc and other JSON files, parse as JSON return JSON.parse(fs.readFileSync(filePath, 'utf-8')); From ea217a8eeb6aa78b2826342edab358c743248175 Mon Sep 17 00:00:00 2001 From: Harry Adel Date: Sun, 8 Mar 2026 12:56:30 +0200 Subject: [PATCH 09/26] Apply @italojs changes --- .../generators/api-export/generateApiJson.js | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/v3-docs/docs/generators/api-export/generateApiJson.js b/v3-docs/docs/generators/api-export/generateApiJson.js index 16e11fb3a3..d58c53e3a7 100644 --- a/v3-docs/docs/generators/api-export/generateApiJson.js +++ b/v3-docs/docs/generators/api-export/generateApiJson.js @@ -5,9 +5,15 @@ const fs = require('fs'); const path = require('path'); -const { pathToFileURL } = require('url'); -async function generateApiJson() { +function parseApiData(dataSource) { + const json = dataSource + .replace(/^(?:\/\/.*\n\s*)*export default\s*/, '') + .replace(/;\s*$/, ''); + return JSON.parse(json); +} + +exports.generateApiJson = async function generateApiJson() { console.log("πŸ“¦ Generating API reference JSON for LLMs..."); const dataPath = path.join(__dirname, '../../data/data.js'); @@ -21,8 +27,7 @@ async function generateApiJson() { } try { - // Dynamically import the ESM data module - const { default: apiData } = await import(pathToFileURL(dataPath).href); + const apiData = parseApiData(fs.readFileSync(dataPath, 'utf8')); // Create public directory if it doesn't exist if (!fs.existsSync(publicDir)) { @@ -49,6 +54,4 @@ async function generateApiJson() { } catch (err) { console.error("❌ Error generating API JSON:", err.message); } -} - -module.exports = { generateApiJson }; +}; From 22ec1c6df9b0e8f7a0918a065f0060c270f0a589 Mon Sep 17 00:00:00 2001 From: Jan Dvorak Date: Thu, 12 Mar 2026 10:36:10 +0100 Subject: [PATCH 10/26] Add Wormhole to recommended community packages --- v3-docs/docs/community-packages/index.md | 4 + v3-docs/docs/community-packages/wormhole.md | 138 ++++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 v3-docs/docs/community-packages/wormhole.md diff --git a/v3-docs/docs/community-packages/index.md b/v3-docs/docs/community-packages/index.md index ee31736a45..7de8ec0565 100644 --- a/v3-docs/docs/community-packages/index.md +++ b/v3-docs/docs/community-packages/index.md @@ -24,6 +24,10 @@ Please bear in mind if you are adding a package to this list, try providing as m ## List of Community Packages +#### AI/LLM helpers + +- [Wormhole](./wormhole.md) Meteor Wormhole, MCP and REST API endpoint creator + #### Method/Subscription helpers - [`meteor-rpc`](./meteor-rpc.md), Meteor Methods Evolved with type checking and runtime validation diff --git a/v3-docs/docs/community-packages/wormhole.md b/v3-docs/docs/community-packages/wormhole.md new file mode 100644 index 0000000000..5ddd5a72f4 --- /dev/null +++ b/v3-docs/docs/community-packages/wormhole.md @@ -0,0 +1,138 @@ +# Jam Method + +- `Who maintains the package` – [William Reiske](https://github.com/wreiske/meteor-wormhole/commits?author=wreiske) + +[[toc]] + +## What Is It? + +Meteor Wormhole is a **server-only, Meteor 3.4+ package** that bridges your Meteor methods to the outside world through: + +- **[MCP (Model Context Protocol)](https://modelcontextprotocol.io/)** β€” The open standard for connecting AI assistants to tools and data. Your methods become MCP tools that Claude, GPT, Cursor, VS Code Copilot, and any MCP-compatible client can discover and invoke. +- **REST API** β€” Every exposed method also gets a `POST /api/` endpoint. +- **OpenAPI 3.1 spec** β€” Auto-generated from your method schemas. +- **Swagger UI** β€” Built-in interactive API docs at `/api/docs`. + +## How It Works + +Two lines to get started: + +```js +import { Wormhole } from 'meteor/wreiske:meteor-wormhole'; + +Wormhole.init(); // That's it β€” all your methods are now MCP tools +``` + +By default it runs in **"all-in" mode**, which automatically exposes every `Meteor.methods()` call (minus DDP internals, private `_`-prefixed methods, and Accounts methods). You can also run in **"opt-in" mode** for explicit control: + +```js +Wormhole.init({ mode: 'opt-in' }); + +Wormhole.expose('todos.add', { + description: 'Add a new todo item', + inputSchema: { + type: 'object', + properties: { + title: { type: 'string', description: 'The todo title' }, + priority: { type: 'string', enum: ['low', 'medium', 'high'] } + }, + required: ['title'] + } +}); +``` + +Add richer schemas and descriptions, and AI agents get better context about what your tools do and how to call them. + +## Features at a Glance + +- **Zero-config MCP server** β€” Streamable HTTP transport at `/mcp`, session management, JSON-RPC 2.0 +- **Optional REST bridge** β€” Enable with `rest: { enabled: true }` for traditional HTTP clients +- **Auto-generated OpenAPI 3.1 spec** with Swagger UI +- **Optional API key auth** β€” Covers both MCP and REST endpoints +- **Smart exclusions** β€” Automatically skips DDP internals, `_private` methods, and Accounts methods; add your own patterns +- **Input validation** β€” JSON Schema β†’ Zod conversion for parameter validation +- **Error propagation** β€” `Meteor.Error` details are properly passed through to clients +- **Enrich existing methods** β€” Add descriptions and schemas to auto-registered methods with `Wormhole.expose()` + +## Configuration Options + +```js +Wormhole.init({ + mode: 'all', // 'all' or 'opt-in' + path: '/mcp', // MCP endpoint path + name: 'my-app', // MCP server name + apiKey: 'secret', // Optional bearer token auth + exclude: [/^admin\./], // Additional exclusion patterns + rest: { + enabled: true, // Enable REST API + path: '/api', // REST base path + docs: true // Swagger UI at /api/docs + } +}); +``` + +## Point Your MCP Client at It + +If you use Claude Desktop, Cursor, VS Code Copilot, or any other MCP-compatible client, you can connect to a Wormhole-enabled app and your AI assistant will immediately see all the exposed methods as callable tools. Just point it at your app's `/mcp` endpoint. + +## API Reference + +### `Wormhole.init(options)` + +Initialize the MCP bridge. + +| Option | Type | Default | Description | +| --------- | ---------------------- | ------------------- | ---------------------------------- | +| `mode` | `'all' \| 'opt-in'` | `'all'` | Exposure mode | +| `path` | `string` | `'/mcp'` | HTTP endpoint path | +| `name` | `string` | `'meteor-wormhole'` | MCP server name | +| `version` | `string` | `'1.0.0'` | MCP server version | +| `apiKey` | `string \| null` | `null` | Bearer token for auth | +| `exclude` | `(string \| RegExp)[]` | `[]` | Methods to exclude (all-in mode) | +| `rest` | `object \| boolean` | `false` | REST API configuration (see below) | + +#### `rest` options + +| Option | Type | Default | Description | +| --------- | ---------------- | ----------- | -------------------------------------------- | +| `enabled` | `boolean` | `false` | Enable REST endpoints | +| `path` | `string` | `'/api'` | Base path for REST endpoints | +| `docs` | `boolean` | `true` | Serve Swagger UI at `/docs` | +| `apiKey` | `string \| null` | _inherited_ | API key for REST (defaults to main `apiKey`) | + +Shorthand: `rest: true` enables REST with all defaults. + +### `Wormhole.expose(methodName, options)` + +Explicitly expose a method as an MCP tool. + +| Option | Type | Description | +| -------------- | -------- | --------------------------------------------------------------------------------------- | +| `description` | `string` | Human-readable tool description | +| `inputSchema` | `object` | JSON Schema for method parameters | +| `outputSchema` | `object` | JSON Schema for the return value (wrapped inside `{ result }` envelope in OpenAPI/REST) | + +### `Wormhole.unexpose(methodName)` + +Remove a method from MCP exposure. + +## How It Works + +1. **Registration**: In all-in mode, the package monkey-patches `Meteor.methods` to intercept every method registration. In opt-in mode, you call `Wormhole.expose()` manually. + +2. **MCP Server**: A Streamable HTTP MCP server is mounted at the configured path (default `/mcp`) on Meteor's `WebApp`. + +3. **Tool Mapping**: Each exposed Meteor method becomes an MCP tool. Method names are sanitized (e.g., `todos.add` β†’ `todos_add`). + +4. **Invocation**: When an AI agent calls a tool, the bridge invokes the corresponding Meteor method via `Meteor.callAsync()` and returns the result. + +5. **REST API** (optional): When enabled, a parallel REST bridge mounts at the configured path. Each method gets a `POST` endpoint. An OpenAPI 3.1 spec is auto-generated from the registry's metadata and input schemas, and Swagger UI provides interactive documentation. + + +## Links + +- **GitHub:** https://github.com/wreiske/meteor-wormhole +- **Live Demo:** https://wormhole.meteorapp.com/ +- **Swagger UI:** https://wormhole.meteorapp.com/api/docs +- **Atmosphere:** [https://atmospherejs.com/wreiske/meteor-wormhole](https://atmospherejs.com/wreiske/meteor-wormhole) +- **Packosphere:** [https://packosphere.com/wreiske/meteor-wormhole](https://packosphere.com/wreiske/meteor-wormhole) From 59796fedb0a8cb8921c2a7f0dfae6fa8c3c336f0 Mon Sep 17 00:00:00 2001 From: Harry Adel Date: Thu, 12 Mar 2026 20:53:17 +0200 Subject: [PATCH 11/26] Fix puppeteer_runner.js using broken msg._text API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When puppeteer was bumped from 20.4.0 to 23.6.0 in d8c8c3db77, the ConsoleMessage class switched from underscore-prefixed _text property to ES2022 private #text field, accessible only via msg.text(). The runner code was never updated, so msg._text is always undefined and test output silently falls through to the else branch, printing only "Test number: N" with no actual test results. The text variable from msg.text() is already computed on line 15 for the Permissions policy filter β€” reuse it instead of the broken msg._text. --- packages/test-in-console/puppeteer_runner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/test-in-console/puppeteer_runner.js b/packages/test-in-console/puppeteer_runner.js index 991bbd4631..7065341278 100644 --- a/packages/test-in-console/puppeteer_runner.js +++ b/packages/test-in-console/puppeteer_runner.js @@ -16,7 +16,7 @@ async function runNextUrl(browser) { if (text.includes('Permissions policy violation')) { return; } - if (msg._text !== undefined) console.log(msg._text); + if (text) console.log(text); else { testNumber++; const currentClientTest = From cec38c47a242b9c09efa6680a4acff21908fffca Mon Sep 17 00:00:00 2001 From: Harry Adel Date: Thu, 12 Mar 2026 21:07:22 +0200 Subject: [PATCH 12/26] Docs: guide LLMs to use test-in-console/run.sh for package tests AGENTS.md listed `./meteor test-packages` but not the headless alternative. That command starts a web server and waits for a browser, producing no terminal output, which causes LLM agents to hang. Add `./packages/test-in-console/run.sh` alongside the existing test-packages command in AGENTS.md with a note explaining the difference. Also add package name examples and the PUPPETEER_DOWNLOAD_PATH hint to the testing skill. --- .github/skills/testing/SKILL.md | 5 ++++- AGENTS.md | 8 +++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/skills/testing/SKILL.md b/.github/skills/testing/SKILL.md index 160ba85c97..b4275b99a3 100644 --- a/.github/skills/testing/SKILL.md +++ b/.github/skills/testing/SKILL.md @@ -22,8 +22,11 @@ Test patterns, commands, and utilities for the Meteor codebase. ./meteor test-packages mongo # Test specific package TINYTEST_FILTER="collection" ./meteor test-packages # Filter specific tests -# Package tests in console (headless via Puppeteer) +# Package tests in console (headless via Puppeteer β€” prints results to terminal) +# Use this for automation or when you need terminal output without a browser. PUPPETEER_DOWNLOAD_PATH=~/.npm/chromium ./packages/test-in-console/run.sh +./packages/test-in-console/run.sh # Test all core packages +./packages/test-in-console/run.sh "mongo" # Test specific package # Modern E2E tests (Jest + Playwright) npm run install:modern # Install dependencies diff --git a/AGENTS.md b/AGENTS.md index 22f14547ae..2b774d8e66 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -8,11 +8,17 @@ Full-stack JavaScript platform for modern web and mobile applications. ./meteor run # Run from source ./meteor create my-app # Create app ./meteor self-test # CLI tests -./meteor test-packages ./packages/ # Package tests +./meteor test-packages ./packages/ # Package tests (browser UI at localhost:3000) +./packages/test-in-console/run.sh "" # Package tests (terminal output via Puppeteer) npm run test:unit # Unit tests (Jest) npm run test:e2e # E2E tests (Jest + Playwright) ``` +> **Note:** `./meteor test-packages` starts a web server and waits for a browser β€” +> it produces no terminal output. For automated/headless runs, use +> `./packages/test-in-console/run.sh ""` instead, which runs the same tests +> via Puppeteer and prints pass/fail results to stdout. + ## Structure ``` From 68698cca33e4957aec226c72e5fa7e73e8b2d2f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Codo=C3=B1er?= Date: Fri, 13 Mar 2026 14:46:49 +0100 Subject: [PATCH 13/26] add `RSPACK_NATIVE` flag to disable dev HMR proxy in native mode --- packages/rspack/rspack_plugin.js | 5 +++++ packages/rspack/rspack_server.js | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/rspack/rspack_plugin.js b/packages/rspack/rspack_plugin.js index 502f49ae82..73c6a6eb5c 100644 --- a/packages/rspack/rspack_plugin.js +++ b/packages/rspack/rspack_plugin.js @@ -177,6 +177,11 @@ if (isMeteorAppRun() || isMeteorAppBuild() || isMeteorAppTest()) { // Configure Meteor settings for Rspack configureMeteorForRspack(); + // Set native mode flag so the server module can skip dev proxy setup + if (isMeteorAppNative()) { + process.env.RSPACK_NATIVE = 'true'; + } + // Calculate and set the devServerPort at boot if (!process.env.RSPACK_DEVSERVER_PORT) { process.env.RSPACK_DEVSERVER_PORT = calculateDevServerPort(); diff --git a/packages/rspack/rspack_server.js b/packages/rspack/rspack_server.js index 97ca990878..9c55294738 100644 --- a/packages/rspack/rspack_server.js +++ b/packages/rspack/rspack_server.js @@ -28,7 +28,11 @@ const RSPACK_ASSETS_REGEX = new RegExp( `^\/${rspackAssetsContext}\/(.+)$`, ); -if (global?.Package?.['tools-core'] != null && Meteor.isDevelopment) { +const shouldEnableDevHMRProxy = + global?.Package?.["tools-core"] != null && + Meteor.isDevelopment && + !process.env.RSPACK_NATIVE; +if (shouldEnableDevHMRProxy) { const { shuffleString } = require('meteor/tools-core/lib/string'); const { createProxyMiddleware } = require('http-proxy-middleware'); From aea76aff0da774989ef5be33154b03c179950920 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Codo=C3=B1er?= Date: Fri, 13 Mar 2026 17:31:10 +0100 Subject: [PATCH 14/26] add check for `isMeteorAppNative` to disable dev HMR proxy in native apps --- packages/rspack/lib/config.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/rspack/lib/config.js b/packages/rspack/lib/config.js index 5fab01f4d4..5771d25fb2 100644 --- a/packages/rspack/lib/config.js +++ b/packages/rspack/lib/config.js @@ -15,6 +15,7 @@ const { isMeteorAppDevelopment, isMeteorAppRun, isMeteorAppBuild, + isMeteorAppNative, isMeteorAppDebug, isMeteorAppTest, isMeteorAppTestFullApp, @@ -370,7 +371,7 @@ export function configureMeteorForRspack() { ensureModuleFilesExist(); // Write content to module files - if (isMeteorAppRun() && isMeteorAppDevelopment()) { + if (isMeteorAppRun() && isMeteorAppDevelopment() && !isMeteorAppNative()) { const customScriptUrl = `/__rspack__/${getBuildFilePath({ ...env, isMain: true, From 396af247f335d0815416071d50316a6604bd2c95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Codo=C3=B1er?= Date: Fri, 13 Mar 2026 17:50:06 +0100 Subject: [PATCH 15/26] refactor TypeScript template self-test: convert to async and clean up legacy code. --- tools/tests/typescript.js | 56 ++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/tools/tests/typescript.js b/tools/tests/typescript.js index 2828cc6a2b..6add91d12b 100644 --- a/tools/tests/typescript.js +++ b/tools/tests/typescript.js @@ -1,27 +1,29 @@ -// var selftest = require('../tool-testing/selftest.js'); -// var Sandbox = selftest.Sandbox; -// -// selftest.define("typescript template works", function () { -// const s = new Sandbox; -// -// let run = s.run("create", "--typescript", "typescript"); -// -// run.waitSecs(60); -// run.match("Created a new Meteor app in 'typescript'."); -// run.match("To run your new app"); -// -// s.cd("typescript"); -// -// run = s.run("npm", "install"); -// run.expectExit(0); -// -// run = s.run("lint"); -// run.waitSecs(60); -// run.match("[zodern:types] Exiting \"meteor lint\" early"); -// run.expectExit(0); -// -// run = s.run("npx", "tsc"); -// run.waitSecs(60); -// run.expectEnd(); -// run.expectExit(0); -// }); +var selftest = require('../tool-testing/selftest.js'); +var Sandbox = selftest.Sandbox; +console.log("--> (typescript.js-Line: 3)\n Sandbox: ", Sandbox); + +selftest.define("typescript template works", async function () { + const s = new Sandbox; + await s.init(); + + let run = s.run("create", "--typescript", "typescript"); + + run.waitSecs(60); + await run.match("Created a new Meteor app in 'typescript'."); + await run.match("To run your new app"); + + s.cd("typescript"); + + run = s.run("npm", "install"); + run.expectExit(0); + + run = s.run("lint"); + run.waitSecs(60); + await run.match("[zodern:types] Exiting \"meteor lint\" early"); + run.expectExit(0); + + run = s.run("npx", "tsc"); + run.waitSecs(60); + run.expectEnd(); + run.expectExit(0); +}); From 1bd0fd4f6a10a0d7bd231262e160c2a347b15641 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Codo=C3=B1er?= Date: Fri, 13 Mar 2026 17:52:07 +0100 Subject: [PATCH 16/26] refactor TypeScript template self-test: update to use `await` syntax --- tools/tests/typescript.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/tests/typescript.js b/tools/tests/typescript.js index 6add91d12b..a6d34a4c2f 100644 --- a/tools/tests/typescript.js +++ b/tools/tests/typescript.js @@ -3,7 +3,7 @@ var Sandbox = selftest.Sandbox; console.log("--> (typescript.js-Line: 3)\n Sandbox: ", Sandbox); selftest.define("typescript template works", async function () { - const s = new Sandbox; + const s = new Sandbox(); await s.init(); let run = s.run("create", "--typescript", "typescript"); @@ -15,15 +15,15 @@ selftest.define("typescript template works", async function () { s.cd("typescript"); run = s.run("npm", "install"); - run.expectExit(0); + await run.expectExit(0); run = s.run("lint"); run.waitSecs(60); - await run.match("[zodern:types] Exiting \"meteor lint\" early"); - run.expectExit(0); + await run.match('[zodern:types] Exiting "meteor lint" early'); + await run.expectExit(0); run = s.run("npx", "tsc"); run.waitSecs(60); - run.expectEnd(); - run.expectExit(0); + await run.expectEnd(); + await run.expectExit(0); }); From fe44650406e9e24eb0b267e560d9d66ebdf7eb6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Codo=C3=B1er?= Date: Fri, 13 Mar 2026 18:02:23 +0100 Subject: [PATCH 17/26] remove trailing breakline --- tools/static-assets/skel-typescript/tsconfig.json | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/static-assets/skel-typescript/tsconfig.json b/tools/static-assets/skel-typescript/tsconfig.json index deb12b4a50..aff98434d9 100644 --- a/tools/static-assets/skel-typescript/tsconfig.json +++ b/tools/static-assets/skel-typescript/tsconfig.json @@ -38,7 +38,6 @@ "esModuleInterop": true, "preserveSymlinks": true, "skipLibCheck": true - }, "exclude": [ "./.meteor/**", From 7538fd13914268841b5ae32bfa84554f3818b6e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Codo=C3=B1er?= Date: Fri, 13 Mar 2026 18:05:22 +0100 Subject: [PATCH 18/26] remove debug `console.log` from typescript.js --- tools/tests/typescript.js | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/tests/typescript.js b/tools/tests/typescript.js index a6d34a4c2f..7933ee5265 100644 --- a/tools/tests/typescript.js +++ b/tools/tests/typescript.js @@ -1,6 +1,5 @@ var selftest = require('../tool-testing/selftest.js'); var Sandbox = selftest.Sandbox; -console.log("--> (typescript.js-Line: 3)\n Sandbox: ", Sandbox); selftest.define("typescript template works", async function () { const s = new Sandbox(); From 753b22e6dfb71c8e28fadbfabc9dad35b2a5c5e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Codo=C3=B1er?= Date: Tue, 17 Mar 2026 17:27:44 +0100 Subject: [PATCH 19/26] add support for `swc.config.ts` in docs and improve SWC configuration handling --- npm-packages/meteor-rspack/index.d.ts | 13 +++++- .../meteor-rspack/lib/meteorRspackHelpers.js | 36 +++++++++++++-- npm-packages/meteor-rspack/rspack.config.js | 11 +++-- .../e2e-tests/apps/typescript/client/main.tsx | 1 - .../apps/typescript/imports/ui/App.tsx | 1 - .../apps/typescript/imports/ui/Hello.tsx | 2 +- .../apps/typescript/imports/ui/Info.tsx | 1 - tools/e2e-tests/apps/typescript/package.json | 1 + tools/e2e-tests/apps/typescript/swc.config.ts | 13 ++++++ .../meteor-bundler-optimizations.md | 4 +- .../rspack-bundler-integration.md | 46 +++++++++++++++++-- 11 files changed, 112 insertions(+), 17 deletions(-) create mode 100644 tools/e2e-tests/apps/typescript/swc.config.ts diff --git a/npm-packages/meteor-rspack/index.d.ts b/npm-packages/meteor-rspack/index.d.ts index 449e6d1a85..20a17a1e7d 100644 --- a/npm-packages/meteor-rspack/index.d.ts +++ b/npm-packages/meteor-rspack/index.d.ts @@ -57,10 +57,21 @@ type MeteorEnv = Record & { */ splitVendorChunk: () => Record; /** - * Extend Rspack SWC loader config. + * Extend the SWC loader config by smart-merging custom options on top of + * Meteor's defaults. Only the properties you specify are overridden; + * everything else is preserved. + * @param swcConfig - SWC loader options to merge with defaults * @returns A config object with SWC loader config */ extendSwcConfig: (swcConfig: SwcLoaderOptions) => Record; + /** + * Replace the SWC loader config entirely, discarding Meteor's defaults. + * Use this when you need full control over SWC options and don't want any + * automatic merging with Meteor's built-in configuration. + * @param swcConfig - Complete SWC loader options (replaces defaults) + * @returns A config object with SWC loader config + */ + replaceSwcConfig: (swcConfig: SwcLoaderOptions) => Record; /** * Extend Rspack configs. * @returns A config object with merged configs diff --git a/npm-packages/meteor-rspack/lib/meteorRspackHelpers.js b/npm-packages/meteor-rspack/lib/meteorRspackHelpers.js index d287773000..2fbbac3027 100644 --- a/npm-packages/meteor-rspack/lib/meteorRspackHelpers.js +++ b/npm-packages/meteor-rspack/lib/meteorRspackHelpers.js @@ -132,10 +132,14 @@ function splitVendorChunk() { } /** - * Extend SWC loader config - * Usage: extendSwcConfig() + * Extend SWC loader config by smart-merging custom options on top of Meteor's + * defaults (via `mergeSplitOverlap`). Only the properties you specify are + * overridden; everything else is preserved. * - * @returns {Record} `{ meteorRspackConfigX: { optimization: { ... } } }` + * Usage: Meteor.extendSwcConfig({ jsc: { parser: { decorators: true } } }) + * + * @param {object} swcConfig - SWC loader options to merge with defaults + * @returns {Record} config fragment for spreading into rspack config */ function extendSwcConfig(swcConfig) { return prepareMeteorRspackConfig({ @@ -152,6 +156,31 @@ function extendSwcConfig(swcConfig) { }); } +/** + * Replace the SWC loader config entirely, discarding Meteor's defaults. + * Use this when you need full control over SWC options and don't want any + * automatic merging with Meteor's built-in configuration. + * + * Usage: Meteor.replaceSwcConfig({ jsc: { parser: { syntax: 'typescript' }, target: 'es2020' } }) + * + * @param {object} swcConfig - Complete SWC loader options (replaces defaults) + * @returns {Record} config fragment for spreading into rspack config + */ +function replaceSwcConfig(swcConfig) { + return prepareMeteorRspackConfig({ + module: { + rules: [ + { + test: /\.(?:[mc]?js|jsx|[mc]?ts|tsx)$/i, + exclude: /node_modules|\.meteor\/local/, + loader: 'builtin:swc-loader', + options: swcConfig, + }, + ], + }, + }); +} + /** * Signal that `Meteor.isDevelopment` and `Meteor.isProduction` should be omitted * from DefinePlugin, making the bundle portable across Meteor environments. @@ -227,6 +256,7 @@ module.exports = { setCache, splitVendorChunk, extendSwcConfig, + replaceSwcConfig, makeWebNodeBuiltinsAlias, disablePlugins, outputMeteorRspack, diff --git a/npm-packages/meteor-rspack/rspack.config.js b/npm-packages/meteor-rspack/rspack.config.js index 0bfb343543..55c2bfbad9 100644 --- a/npm-packages/meteor-rspack/rspack.config.js +++ b/npm-packages/meteor-rspack/rspack.config.js @@ -19,6 +19,7 @@ const { setCache, splitVendorChunk, extendSwcConfig, + replaceSwcConfig, makeWebNodeBuiltinsAlias, disablePlugins, outputMeteorRspack, @@ -325,7 +326,11 @@ module.exports = async function (inMeteor = {}, argv = {}) { setCache(!!enabled, enabled === "memory" ? undefined : cacheStrategy); Meteor.splitVendorChunk = () => splitVendorChunk(); Meteor.extendSwcConfig = (customSwcConfig) => - extendSwcConfig(customSwcConfig); + extendSwcConfig( + mergeSplitOverlap(Meteor.swcConfigOptions, customSwcConfig) + ); + Meteor.replaceSwcConfig = (customSwcConfig) => + replaceSwcConfig(customSwcConfig); Meteor.extendConfig = (...configs) => mergeSplitOverlap(...configs); Meteor.disablePlugins = (matchers) => prepareMeteorRspackConfig({ @@ -817,9 +822,9 @@ module.exports = async function (inMeteor = {}, argv = {}) { delete config["meteor.enablePortableBuild"]; - // if (Meteor.isDebug || Meteor.isVerbose) { + if (Meteor.isDebug || Meteor.isVerbose) { console.log("Config:", inspect(config, { depth: null, colors: true })); - // } + } // Check if lazyCompilation is enabled and warn the user if ( diff --git a/tools/e2e-tests/apps/typescript/client/main.tsx b/tools/e2e-tests/apps/typescript/client/main.tsx index e576e1b803..4eb40f49d1 100644 --- a/tools/e2e-tests/apps/typescript/client/main.tsx +++ b/tools/e2e-tests/apps/typescript/client/main.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { createRoot } from 'react-dom/client'; import { Meteor } from 'meteor/meteor'; import { App } from '@ui/App'; diff --git a/tools/e2e-tests/apps/typescript/imports/ui/App.tsx b/tools/e2e-tests/apps/typescript/imports/ui/App.tsx index 52f71448cc..94679c5547 100644 --- a/tools/e2e-tests/apps/typescript/imports/ui/App.tsx +++ b/tools/e2e-tests/apps/typescript/imports/ui/App.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import './Global.scss'; import { Hello } from './Hello'; import { Info } from './Info'; diff --git a/tools/e2e-tests/apps/typescript/imports/ui/Hello.tsx b/tools/e2e-tests/apps/typescript/imports/ui/Hello.tsx index 15e0f185ac..527d5af607 100644 --- a/tools/e2e-tests/apps/typescript/imports/ui/Hello.tsx +++ b/tools/e2e-tests/apps/typescript/imports/ui/Hello.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; export const Hello = () => { const [counter, setCounter] = useState(0); diff --git a/tools/e2e-tests/apps/typescript/imports/ui/Info.tsx b/tools/e2e-tests/apps/typescript/imports/ui/Info.tsx index 23cb8f07a3..809fbc6716 100644 --- a/tools/e2e-tests/apps/typescript/imports/ui/Info.tsx +++ b/tools/e2e-tests/apps/typescript/imports/ui/Info.tsx @@ -1,4 +1,3 @@ -import React from "react"; import { useFind, useSubscribe } from "meteor/react-meteor-data"; import { LinksCollection, Link } from "../api/links"; diff --git a/tools/e2e-tests/apps/typescript/package.json b/tools/e2e-tests/apps/typescript/package.json index d1ac310541..f0359b6094 100644 --- a/tools/e2e-tests/apps/typescript/package.json +++ b/tools/e2e-tests/apps/typescript/package.json @@ -15,6 +15,7 @@ "react-dom": "^18.2.0" }, "devDependencies": { + "@swc/core": "^1.15.18", "@types/meteor": "^2.9.9", "@types/mocha": "^8.2.3", "@types/node": "^22.10.6", diff --git a/tools/e2e-tests/apps/typescript/swc.config.ts b/tools/e2e-tests/apps/typescript/swc.config.ts new file mode 100644 index 0000000000..699a33a40d --- /dev/null +++ b/tools/e2e-tests/apps/typescript/swc.config.ts @@ -0,0 +1,13 @@ +import type { Config } from "@swc/core"; + +const config: Config = { + jsc: { + transform: { + react: { + runtime: "automatic", + }, + }, + }, +}; + +export default config; diff --git a/v3-docs/docs/about/modern-build-stack/meteor-bundler-optimizations.md b/v3-docs/docs/about/modern-build-stack/meteor-bundler-optimizations.md index 6c76240f18..6c3d84cb53 100644 --- a/v3-docs/docs/about/modern-build-stack/meteor-bundler-optimizations.md +++ b/v3-docs/docs/about/modern-build-stack/meteor-bundler-optimizations.md @@ -165,7 +165,9 @@ You can use `.swcrc` config in the root of your project to describe specific [SW You can also configure other options using the `.swcrc` format. For custom SWC configs, see the [SWC configuration API](https://swc.rs/docs/configuration/compilation). -Use `swc.config.js` in your project root for dynamic configuration. Meteor will import and apply the SWC config automatically. This lets you choose a config based on environment variables or other runtime factors. +Use `swc.config.js` in your project root for dynamic configuration. Meteor will import and apply the SWC config automatically. This lets you choose a config based on environment variables or other runtime factors. If you prefer TypeScript, `swc.config.ts` is also supported, Meteor will transpile and load it automatically. + +Meteor checks for config files in this order: `.swcrc` > `swc.config.js` > `swc.config.ts`. Only the first one found is used. You can also review these migration topics that use custom `.swcrc` configs: diff --git a/v3-docs/docs/about/modern-build-stack/rspack-bundler-integration.md b/v3-docs/docs/about/modern-build-stack/rspack-bundler-integration.md index 35a34f1295..f053475cf8 100644 --- a/v3-docs/docs/about/modern-build-stack/rspack-bundler-integration.md +++ b/v3-docs/docs/about/modern-build-stack/rspack-bundler-integration.md @@ -157,7 +157,8 @@ You can use flags to control the final configuration based on the environment. T | `compileWithRspack` | function | Forces given npm deps ([Condition](https://rspack.rs/config/module#condition)[]) to be compiled by Rspack | | `setCache` | function | Enables or disables cache. Accepts true (persistent, default), false, or 'memory' | | `splitVendorChunk` | function | Splits vendor libraries so they are automatically served from a separate chunk | -| `extendSwcConfig` | function | Extends the [SWC loader configuration](https://rspack.rs/guide/features/builtin-swc-loader#options) to apply only to the app code | +| `extendSwcConfig` | function | Smart-merges custom options into Meteor's default [SWC loader configuration](https://rspack.rs/guide/features/builtin-swc-loader#options), applying only to app code | +| `replaceSwcConfig` | function | Replaces Meteor's default [SWC loader configuration](https://rspack.rs/guide/features/builtin-swc-loader#options) entirely with the provided options, applying only to app code | | `extendConfig` | function | Extends the config by applying merged object configs | | `enablePortableBuild` | function | Omits `Meteor.isDevelopment` and `Meteor.isProduction` from the bundle, making it portable across environments | @@ -628,27 +629,62 @@ module.exports = defineConfig(Meteor => ({ This is a quick configuration for split chunks all within `node_modules` as a `vendor` chunk, if you need more control you can use the [official Rspack split chunks integration guide](https://rspack.rs/guide/optimization/code-splitting#splitchunksplugin). -### Extending SWC config +### Customizing SWC config Rspack uses the SWC configuration to transpile your app code. By default, it inherits any settings from the `.swcrc` file, which also [impacts how Meteor transpiles core and package code](meteor-bundler-optimizations.md#custom-swcrc). -If you want a configuration to apply only to your app code, you can extend the SWC setup using the `Meteor.extendSwcConfig` helper: +If you want a configuration to apply only to your app code (not Meteor packages), two helpers are available: + +#### `Meteor.extendSwcConfig` - smart merge (recommended) + +Merges your custom options on top of Meteor's defaults using a deep merge strategy (the same used by `Meteor.extendConfig`). Only the properties you specify are overridden; everything else (parser settings, React refresh, external helpers, etc) is preserved. ```js const { defineConfig } = require('@meteorjs/rspack'); module.exports = defineConfig(Meteor => ({ - // Extend SWC config + // Add decorator support while keeping all Meteor defaults ...Meteor.extendSwcConfig({ jsc: { parser: { - syntax: 'typescript', + decorators: true, }, }, }), })); ``` +#### `Meteor.replaceSwcConfig` - full replacement + +Discards Meteor's defaults entirely and uses the provided config as-is. Use this when you need complete control over SWC and the smart merge doesn't fit your use case. + +```js +const { defineConfig } = require('@meteorjs/rspack'); + +module.exports = defineConfig(Meteor => ({ + // Full SWC config β€” no Meteor defaults applied + ...Meteor.replaceSwcConfig({ + jsc: { + parser: { + syntax: 'typescript', + tsx: true, + decorators: true, + }, + target: 'es2020', + transform: { + react: { + runtime: 'automatic', + }, + }, + }, + }), +})); +``` + +:::warning +When using `replaceSwcConfig`, you are responsible for providing all necessary SWC options. Features like React refresh, external helpers and parser defaults that Meteor configures (`Meteor.swcConfigOptions`) will not be applied unless you include them yourself. +::: + ### Interop for Default Imports Meteor originally handled default imports from CommonJS modules automatically. This allowed you to write: From d307c9c1ebcb1dce94fce439595a0bc18590e0ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Codo=C3=B1er?= Date: Tue, 17 Mar 2026 17:41:35 +0100 Subject: [PATCH 20/26] update `E2E_COVERAGE.md` to document `swc.config.ts` and extended TypeScript SWC scenarios --- dev/modern-tools/rspack/E2E_COVERAGE.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/dev/modern-tools/rspack/E2E_COVERAGE.md b/dev/modern-tools/rspack/E2E_COVERAGE.md index 8b1a8c20fc..5c3fc81315 100644 --- a/dev/modern-tools/rspack/E2E_COVERAGE.md +++ b/dev/modern-tools/rspack/E2E_COVERAGE.md @@ -85,16 +85,19 @@ Full Blaze app (with `imports/` structure for tests). ### typescript -TypeScript with SCSS, type checking, and `.ts` rspack config. +TypeScript with SCSS, type checking, `.ts` rspack config, and `.ts` SWC config. | What is covered | Phase | |----------------|-------| | TypeScript rspack config (`rspack.config.ts`) | All | +| TypeScript SWC config (`swc.config.ts`) with automatic JSX runtime | All | +| `@swc/core` used to transpile `.ts` config at load time | All | | Custom build dir (`build`) | All | | Custom asset/chunk context dirs (`assets`, `chunks`) | All | | SCSS styles support (`white-space: break-spaces`) | Run, Prod | | TypeScript + TSX environment detection | Run, Prod, Test, Build | | Portable build (Meteor.isDevelopment/isProduction not defined) | Run, Prod, Build | +| `Meteor.extendSwcConfig` with path aliases (`@ui/*`, `@api/*`) | All | | `TsCheckerRspackPlugin` type checking (no errors) | Run | | `.meteor/local/types` directory generated | Run | | Separate client/server test files | Test | @@ -232,11 +235,12 @@ Several apps import specific npm packages to verify that Meteor + Rspack handles | `@apollo/server/express4` | ESM subpath export (middleware from deep path) | | `graphql` | Peer dependency, dual CJS/ESM package | -### typescript (`apps/typescript/rspack.config.ts`) +### typescript (`apps/typescript/rspack.config.ts`, `apps/typescript/swc.config.ts`) | Package | Reason | |---------|--------| | `node:module` (`createRequire`) | Node.js built-in in a `.ts` config file β€” tests CJS interop via `createRequire(import.meta.url)` in an ESM context | +| `@swc/core` | Used at load time to transpile `swc.config.ts` from TypeScript before applying the SWC configuration | --- @@ -250,6 +254,7 @@ Where each feature is tested across apps and skeletons. | HMR disabled (prod) | all apps with HMR | | | HMR incompatible | blaze, full-blaze | | | Custom rspack config | react (.cjs), react-router, babel (.mjs), monorepo (.cjs), typescript (.ts) | | +| Custom SWC config (.ts) | typescript | | | Config override file | react-router, monorepo | | | Custom build dir | react, typescript | | | Custom asset/chunk context dirs | typescript | | @@ -272,6 +277,7 @@ Where each feature is tested across apps and skeletons. | Module rules override | babel | | | Custom NODE_ENV compilation | babel | | | Portable build (no isDev/isProd defines) | typescript | | +| `Meteor.extendSwcConfig` (path aliases) | typescript | | | `meteor reset` cleanup | all apps | all skeletons | | Skeleton creation | | all 14 skeletons | | Body style assertions | | react, tailwind (custom); most others (default) | From 7a29dd9aa0279a596c24f1e4bc02f823aa63eca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Codo=C3=B1er?= Date: Tue, 17 Mar 2026 17:43:24 +0100 Subject: [PATCH 21/26] update `E2E_COVERAGE.md` to clarify `@swc/core` usage as type-only import in `swc.config.ts` --- dev/modern-tools/rspack/E2E_COVERAGE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/modern-tools/rspack/E2E_COVERAGE.md b/dev/modern-tools/rspack/E2E_COVERAGE.md index 5c3fc81315..1199c73a50 100644 --- a/dev/modern-tools/rspack/E2E_COVERAGE.md +++ b/dev/modern-tools/rspack/E2E_COVERAGE.md @@ -91,7 +91,7 @@ TypeScript with SCSS, type checking, `.ts` rspack config, and `.ts` SWC config. |----------------|-------| | TypeScript rspack config (`rspack.config.ts`) | All | | TypeScript SWC config (`swc.config.ts`) with automatic JSX runtime | All | -| `@swc/core` used to transpile `.ts` config at load time | All | +| `@swc/core` type-only import for SWC config typings | All | | Custom build dir (`build`) | All | | Custom asset/chunk context dirs (`assets`, `chunks`) | All | | SCSS styles support (`white-space: break-spaces`) | Run, Prod | @@ -240,7 +240,7 @@ Several apps import specific npm packages to verify that Meteor + Rspack handles | Package | Reason | |---------|--------| | `node:module` (`createRequire`) | Node.js built-in in a `.ts` config file β€” tests CJS interop via `createRequire(import.meta.url)` in an ESM context | -| `@swc/core` | Used at load time to transpile `swc.config.ts` from TypeScript before applying the SWC configuration | +| `@swc/core` | Type-only import (`import type { Config }`) β€” provides typings for `swc.config.ts`, stripped at compile time | --- From 79f1c05d6de5626a4803341e12ec82596eaefea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Codo=C3=B1er?= Date: Thu, 19 Mar 2026 10:16:06 +0100 Subject: [PATCH 22/26] re-run checks From f61bcbe4fd51627ce64a43f56d8fb3b29dc48711 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Codo=C3=B1er?= Date: Thu, 19 Mar 2026 11:34:02 +0100 Subject: [PATCH 23/26] improve error handling in E2E test assertion for missing files --- tools/e2e-tests/assertions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/e2e-tests/assertions.js b/tools/e2e-tests/assertions.js index 437bdec437..5abaad4daf 100644 --- a/tools/e2e-tests/assertions.js +++ b/tools/e2e-tests/assertions.js @@ -102,7 +102,7 @@ export async function assertFileExist(tempDir, filePath, options = {}) { return checkFile(); } // If we've exceeded the timeout, fail the test - expect(fileExists).toBe(true); + throw new Error(`Expected file to exist but it was not found: ${fullPath}`); return false; } From 54f4b478f313dc500810d3d44417ab797a81ea50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Codo=C3=B1er?= Date: Thu, 19 Mar 2026 11:57:13 +0100 Subject: [PATCH 24/26] [Rspack][CI] Add warning for NPM_LINK_RSPACK in tests and CI logs --- .github/workflows/e2e-tests.yml | 1 + tools/e2e-tests/test-helpers.js | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index ed3d711da6..ce29d07dfb 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -79,6 +79,7 @@ jobs: echo "Current branch: ${{ github.head_ref || github.ref_name }}" if [[ "${{ github.head_ref || github.ref_name }}" == release-* ]]; then echo "NPM_LINK_RSPACK=false" >> $GITHUB_ENV + echo "::warning::NPM_LINK_RSPACK=false on release branch. E2E tests will install @meteorjs/rspack from npm β€” make sure the latest version is published or tests may fail." fi - name: Prepare Meteor diff --git a/tools/e2e-tests/test-helpers.js b/tools/e2e-tests/test-helpers.js index f1728472d5..52c11201f3 100644 --- a/tools/e2e-tests/test-helpers.js +++ b/tools/e2e-tests/test-helpers.js @@ -35,6 +35,12 @@ const isCI = process.env.GITHUB_ACTIONS === "true"; // Link local npm-packages/meteor-rspack so tests run against the latest dev version. // Set NPM_LINK_RSPACK=false to disable. const npmLinkLocalRspack = process.env.NPM_LINK_RSPACK !== 'false'; +if (!npmLinkLocalRspack) { + console.warn( + '\x1b[33m⚠ NPM_LINK_RSPACK=false β€” tests will install @meteorjs/rspack from npm.\n' + + ' If CI fails, ensure the latest @meteorjs/rspack version has been published.\x1b[0m' + ); +} const WAIT_ON = isCI ? 2000 : 500; From 366bf354a25acc9670085441dc9bbdefebeffa93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Codo=C3=B1er?= Date: Thu, 19 Mar 2026 12:11:11 +0100 Subject: [PATCH 25/26] bump `@meteorjs/rspack` to version `1.1.0-beta.31` in all templates and constants --- npm-packages/meteor-rspack/package-lock.json | 4 ++-- npm-packages/meteor-rspack/package.json | 2 +- packages/rspack/lib/constants.js | 2 +- tools/e2e-tests/apps/solid/package.json | 2 +- tools/e2e-tests/apps/svelte/package.json | 2 +- tools/e2e-tests/apps/vue/package.json | 2 +- tools/static-assets/skel-angular/package.json | 2 +- tools/static-assets/skel-apollo/package.json | 2 +- tools/static-assets/skel-babel/package.json | 2 +- tools/static-assets/skel-blaze/package.json | 2 +- tools/static-assets/skel-chakra-ui/package.json | 2 +- tools/static-assets/skel-coffeescript/package.json | 2 +- tools/static-assets/skel-full/package.json | 2 +- tools/static-assets/skel-react/package.json | 2 +- tools/static-assets/skel-solid/package.json | 2 +- tools/static-assets/skel-svelte/package.json | 2 +- tools/static-assets/skel-tailwind/package.json | 2 +- tools/static-assets/skel-typescript/package.json | 2 +- tools/static-assets/skel-vue/package.json | 2 +- 19 files changed, 20 insertions(+), 20 deletions(-) diff --git a/npm-packages/meteor-rspack/package-lock.json b/npm-packages/meteor-rspack/package-lock.json index 0919f2882e..7792758d69 100644 --- a/npm-packages/meteor-rspack/package-lock.json +++ b/npm-packages/meteor-rspack/package-lock.json @@ -1,12 +1,12 @@ { "name": "@meteorjs/rspack", - "version": "1.1.0-beta.30", + "version": "1.1.0-beta.31", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@meteorjs/rspack", - "version": "1.1.0-beta.30", + "version": "1.1.0-beta.31", "license": "ISC", "dependencies": { "fast-deep-equal": "^3.1.3", diff --git a/npm-packages/meteor-rspack/package.json b/npm-packages/meteor-rspack/package.json index 3d530801ac..2bcbb679c2 100644 --- a/npm-packages/meteor-rspack/package.json +++ b/npm-packages/meteor-rspack/package.json @@ -1,6 +1,6 @@ { "name": "@meteorjs/rspack", - "version": "1.1.0-beta.30", + "version": "1.1.0-beta.31", "description": "Configuration logic for using Rspack in Meteor projects", "main": "index.js", "type": "commonjs", diff --git a/packages/rspack/lib/constants.js b/packages/rspack/lib/constants.js index 718ca52301..1341f54ce7 100644 --- a/packages/rspack/lib/constants.js +++ b/packages/rspack/lib/constants.js @@ -7,7 +7,7 @@ import path from 'path'; export const DEFAULT_RSPACK_VERSION = '1.7.1'; -export const DEFAULT_METEOR_RSPACK_VERSION = '1.1.0-beta.30'; +export const DEFAULT_METEOR_RSPACK_VERSION = '1.1.0-beta.31'; export const DEFAULT_METEOR_RSPACK_REACT_HMR_VERSION = '1.4.3'; diff --git a/tools/e2e-tests/apps/solid/package.json b/tools/e2e-tests/apps/solid/package.json index 104f5258ef..5ce93de638 100644 --- a/tools/e2e-tests/apps/solid/package.json +++ b/tools/e2e-tests/apps/solid/package.json @@ -22,7 +22,7 @@ "modern": true }, "devDependencies": { - "@meteorjs/rspack": "^0.0.29", + "@meteorjs/rspack": "^1.1.0-beta.31", "@rspack/cli": "^1.4.8", "@rspack/core": "^1.4.8", "babel-loader": "10.0.0", diff --git a/tools/e2e-tests/apps/svelte/package.json b/tools/e2e-tests/apps/svelte/package.json index a9873d4aa5..cba0d4e7a0 100644 --- a/tools/e2e-tests/apps/svelte/package.json +++ b/tools/e2e-tests/apps/svelte/package.json @@ -13,7 +13,7 @@ "meteor-node-stubs": "^1.2.12" }, "devDependencies": { - "@meteorjs/rspack": "^0.0.28", + "@meteorjs/rspack": "^1.1.0-beta.31", "@rspack/cli": "^1.4.8", "@rspack/core": "^1.4.8", "playwright": "1.58.0", diff --git a/tools/e2e-tests/apps/vue/package.json b/tools/e2e-tests/apps/vue/package.json index 4d13d28fd1..31c39838ad 100644 --- a/tools/e2e-tests/apps/vue/package.json +++ b/tools/e2e-tests/apps/vue/package.json @@ -17,7 +17,7 @@ "vue-router": "^4.2.5" }, "devDependencies": { - "@meteorjs/rspack": "^1.0.0-beta.1", + "@meteorjs/rspack": "^1.1.0-beta.31", "@rspack/cli": "^1.4.8", "@rspack/core": "^1.4.8", "@tailwindcss/postcss": "^4.1.12", diff --git a/tools/static-assets/skel-angular/package.json b/tools/static-assets/skel-angular/package.json index 1140972385..fa3105b024 100644 --- a/tools/static-assets/skel-angular/package.json +++ b/tools/static-assets/skel-angular/package.json @@ -22,7 +22,7 @@ }, "devDependencies": { "@angular/compiler-cli": "^20.0.0", - "@meteorjs/rspack": "^1.0.0-beta.1", + "@meteorjs/rspack": "^1.1.0-beta.31", "@nx/angular-rspack": "^21.1.0", "@rsdoctor/rspack-plugin": "^1.2.3", "@rspack/cli": "^1.7.1", diff --git a/tools/static-assets/skel-apollo/package.json b/tools/static-assets/skel-apollo/package.json index 50c58e0f22..5fd18f2131 100644 --- a/tools/static-assets/skel-apollo/package.json +++ b/tools/static-assets/skel-apollo/package.json @@ -20,7 +20,7 @@ "devDependencies": { "@graphql-tools/webpack-loader": "^7.0.0", "@rsdoctor/rspack-plugin": "^1.2.3", - "@meteorjs/rspack": "^1.0.0-beta.1", + "@meteorjs/rspack": "^1.1.0-beta.31", "@rspack/cli": "^1.7.1", "@rspack/core": "^1.7.1", "@rspack/plugin-react-refresh": "^1.4.3", diff --git a/tools/static-assets/skel-babel/package.json b/tools/static-assets/skel-babel/package.json index 647024e2c8..8c9c45753f 100644 --- a/tools/static-assets/skel-babel/package.json +++ b/tools/static-assets/skel-babel/package.json @@ -17,7 +17,7 @@ "devDependencies": { "@babel/preset-env": "^7.28.3", "@babel/preset-react": "^7.23.3", - "@meteorjs/rspack": "^1.0.0-beta.1", + "@meteorjs/rspack": "^1.1.0-beta.31", "@rsdoctor/rspack-plugin": "^1.2.3", "@rspack/cli": "^1.7.1", "@rspack/core": "^1.7.1", diff --git a/tools/static-assets/skel-blaze/package.json b/tools/static-assets/skel-blaze/package.json index 4d1b0a785e..6dd838aaf6 100644 --- a/tools/static-assets/skel-blaze/package.json +++ b/tools/static-assets/skel-blaze/package.json @@ -14,7 +14,7 @@ "meteor-node-stubs": "^1.2.12" }, "devDependencies": { - "@meteorjs/rspack": "^1.0.0-beta.1", + "@meteorjs/rspack": "^1.1.0-beta.31", "@rsdoctor/rspack-plugin": "^1.2.3", "@rspack/cli": "^1.7.1", "@rspack/core": "^1.7.1", diff --git a/tools/static-assets/skel-chakra-ui/package.json b/tools/static-assets/skel-chakra-ui/package.json index 6e3e3f7c8d..a30ef9f180 100644 --- a/tools/static-assets/skel-chakra-ui/package.json +++ b/tools/static-assets/skel-chakra-ui/package.json @@ -21,7 +21,7 @@ "react-dom": "^18.2.0" }, "devDependencies": { - "@meteorjs/rspack": "^1.0.0-beta.1", + "@meteorjs/rspack": "^1.1.0-beta.31", "@rsdoctor/rspack-plugin": "^1.2.3", "@rspack/cli": "^1.7.1", "@rspack/core": "^1.7.1", diff --git a/tools/static-assets/skel-coffeescript/package.json b/tools/static-assets/skel-coffeescript/package.json index af84b38f91..6f2ebbce93 100644 --- a/tools/static-assets/skel-coffeescript/package.json +++ b/tools/static-assets/skel-coffeescript/package.json @@ -15,7 +15,7 @@ "react-dom": "^18.2.0" }, "devDependencies": { - "@meteorjs/rspack": "^1.0.0-beta.1", + "@meteorjs/rspack": "^1.1.0-beta.31", "@rsdoctor/rspack-plugin": "^1.2.3", "@rspack/cli": "^1.7.1", "@rspack/core": "^1.7.1", diff --git a/tools/static-assets/skel-full/package.json b/tools/static-assets/skel-full/package.json index 8c77c7dbb5..e7f8bb952e 100644 --- a/tools/static-assets/skel-full/package.json +++ b/tools/static-assets/skel-full/package.json @@ -12,7 +12,7 @@ "meteor-node-stubs": "^1.2.12" }, "devDependencies": { - "@meteorjs/rspack": "^1.0.0-beta.1", + "@meteorjs/rspack": "^1.1.0-beta.31", "@rsdoctor/rspack-plugin": "^1.2.3", "@rspack/cli": "^1.7.1", "@rspack/core": "^1.7.1", diff --git a/tools/static-assets/skel-react/package.json b/tools/static-assets/skel-react/package.json index 77d0137aaf..1091b1727a 100644 --- a/tools/static-assets/skel-react/package.json +++ b/tools/static-assets/skel-react/package.json @@ -15,7 +15,7 @@ "react-dom": "^18.2.0" }, "devDependencies": { - "@meteorjs/rspack": "^1.0.0-beta.1", + "@meteorjs/rspack": "^1.1.0-beta.31", "@rsdoctor/rspack-plugin": "^1.2.3", "@rspack/cli": "^1.7.1", "@rspack/core": "^1.7.1", diff --git a/tools/static-assets/skel-solid/package.json b/tools/static-assets/skel-solid/package.json index 6e2cc4ba61..d14262c517 100644 --- a/tools/static-assets/skel-solid/package.json +++ b/tools/static-assets/skel-solid/package.json @@ -14,7 +14,7 @@ "picocolors": "^1.1.1" }, "devDependencies": { - "@meteorjs/rspack": "^1.0.0-beta.1", + "@meteorjs/rspack": "^1.1.0-beta.31", "@rsdoctor/rspack-plugin": "^1.2.3", "@rspack/cli": "^1.7.1", "@rspack/core": "^1.7.1", diff --git a/tools/static-assets/skel-svelte/package.json b/tools/static-assets/skel-svelte/package.json index 937c185741..d864cf7c23 100644 --- a/tools/static-assets/skel-svelte/package.json +++ b/tools/static-assets/skel-svelte/package.json @@ -13,7 +13,7 @@ "meteor-node-stubs": "^1.2.12" }, "devDependencies": { - "@meteorjs/rspack": "^1.0.0-beta.1", + "@meteorjs/rspack": "^1.1.0-beta.31", "@rsdoctor/rspack-plugin": "^1.2.3", "@rspack/cli": "^1.7.1", "@rspack/core": "^1.7.1", diff --git a/tools/static-assets/skel-tailwind/package.json b/tools/static-assets/skel-tailwind/package.json index 482a0bcab0..79935caba4 100644 --- a/tools/static-assets/skel-tailwind/package.json +++ b/tools/static-assets/skel-tailwind/package.json @@ -16,7 +16,7 @@ "react-dom": "^17.0.2" }, "devDependencies": { - "@meteorjs/rspack": "^1.0.0-beta.1", + "@meteorjs/rspack": "^1.1.0-beta.31", "@rsdoctor/rspack-plugin": "^1.2.3", "@rspack/cli": "^1.7.1", "@rspack/core": "^1.7.1", diff --git a/tools/static-assets/skel-typescript/package.json b/tools/static-assets/skel-typescript/package.json index af8e9e10c5..59017498e0 100644 --- a/tools/static-assets/skel-typescript/package.json +++ b/tools/static-assets/skel-typescript/package.json @@ -15,7 +15,7 @@ "react-dom": "^18.2.0" }, "devDependencies": { - "@meteorjs/rspack": "^1.0.0-beta.1", + "@meteorjs/rspack": "^1.1.0-beta.31", "@rsdoctor/rspack-plugin": "^1.2.3", "@rspack/cli": "^1.7.1", "@rspack/core": "^1.7.1", diff --git a/tools/static-assets/skel-vue/package.json b/tools/static-assets/skel-vue/package.json index 0f4debcbdd..a156645d98 100644 --- a/tools/static-assets/skel-vue/package.json +++ b/tools/static-assets/skel-vue/package.json @@ -17,7 +17,7 @@ "vue-router": "^4.2.5" }, "devDependencies": { - "@meteorjs/rspack": "^1.0.0-beta.1", + "@meteorjs/rspack": "^1.1.0-beta.31", "@rsdoctor/rspack-plugin": "^1.2.3", "@rspack/cli": "^1.7.1", "@rspack/core": "^1.7.1", From f95cab0e54ef7535c5837720581a0a404eea1f3c Mon Sep 17 00:00:00 2001 From: dupontbertrand Date: Fri, 20 Mar 2026 00:57:42 +0100 Subject: [PATCH 26/26] docs: add CSS Modules section to rspack bundler integration guide The CSS Modules setup was missing from the rspack documentation, causing confusion for users trying to use .module.css files with TypeScript projects. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../rspack-bundler-integration.md | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/v3-docs/docs/about/modern-build-stack/rspack-bundler-integration.md b/v3-docs/docs/about/modern-build-stack/rspack-bundler-integration.md index 2ddbe1dc53..2c7bf79134 100644 --- a/v3-docs/docs/about/modern-build-stack/rspack-bundler-integration.md +++ b/v3-docs/docs/about/modern-build-stack/rspack-bundler-integration.md @@ -397,6 +397,46 @@ With the Meteor–Rspack integration, `zodern:melte` no longer works. Use the of Meteor-Rspack comes with built-in CSS support. You can import any CSS file into your code, and it will be processed and included in your HTML skeleton automatically. In addition, any CSS file placed in the same folder as your Meteor entry point will be processed and added as global styles without the need for explicit imports. +### CSS Modules + +[CSS Modules](https://rspack.rs/guide/tech/css#css-modules) are supported out of the box β€” any file named `*.module.css` is automatically scoped locally. + +By default, rspack uses **named exports**, so imports look like: + +``` js +import { app } from './App.module.css'; +``` + +If you prefer **default imports** (`import styles from './App.module.css'`), disable `namedExports` on both the `css/auto` and `css/module` parsers: + +``` js +module.exports = defineConfig(Meteor => ({ + module: { + parser: { + 'css/auto': { + namedExports: false, + }, + 'css/module': { + namedExports: false, + }, + }, + }, +})); +``` + +#### TypeScript + +When using CSS Modules with TypeScript, add a declaration file (e.g. `imports/css-modules.d.ts`) so the compiler recognizes `.module.css` imports: + +``` typescript +declare module '*.module.css' { + const classes: { readonly [key: string]: string }; + export default classes; +} +``` + +For more details, check [the official Rspack CSS Modules guide](https://rspack.rs/guide/tech/css#css-modules). + ### Less Less support is available in Meteor-Rspack. You need to replace the existing [Meteor `less` package](https://github.com/meteor/meteor/tree/master/packages/non-core/less) or similar with the Rspack configuration.