Merge pull request #14016 from meteor/legacy-fixes-new-bundler

Legacy bundle fixes for modern build stack
This commit is contained in:
Nacho Codoñer
2025-11-24 18:00:30 +01:00
committed by GitHub
7 changed files with 62 additions and 44 deletions

View File

@@ -43,7 +43,7 @@ type MeteorEnv = Record<string, any> & {
* @param options - Optional configuration options
* @returns A config object with module rules configuration
*/
compileWithRspack: (deps: RuleSetConditions) => Record<string, object>;
compileWithRspack: (deps: RuleSetConditions, options?: SwcLoaderOptions) => Record<string, object>;
/**
* Enable or disable Rspack cache config.
* @param enabled - Whether to enable caching
@@ -61,6 +61,11 @@ type MeteorEnv = Record<string, any> & {
* @returns A config object with SWC loader config
*/
extendSwcConfig: (swcConfig: SwcLoaderOptions) => Record<string, object>;
/**
* Extend Rspack configs.
* @returns A config object with merged configs
*/
extendConfig: (...configs: Record<string, object>[]) => Record<string, object>;
}
export type ConfigFactory = (

View File

@@ -443,13 +443,18 @@ class RequireExternalsPlugin {
_ensureGlobalThisModule() {
const block = [
`/* Polyfill globalThis.module & exports */`,
`if (typeof globalThis.module === 'undefined') {`,
` globalThis.module = { exports: {} };`,
`/* Polyfill globalThis.module, exports & module for legacy */`,
`if (typeof globalThis !== 'undefined') {`,
` if (typeof globalThis.module === 'undefined') {`,
` globalThis.module = { exports: {} };`,
` }`,
` if (typeof globalThis.exports === 'undefined') {`,
` globalThis.exports = globalThis.module.exports;`,
` }`,
`}`,
`if (typeof window.module === 'undefined') {`,
` window.module = { exports: {} };`,
`}`,
`if (typeof globalThis.exports === 'undefined') {`,
` globalThis.exports = globalThis.module.exports;`,
`}`
].join('\n') + '\n';
let content = '';

View File

@@ -274,9 +274,9 @@ module.exports = async function (inMeteor = {}, argv = {}) {
// Expose Meteor's helpers to expand Rspack configs
Meteor.compileWithMeteor = deps => compileWithMeteor(deps);
Meteor.compileWithRspack = deps =>
Meteor.compileWithRspack = (deps, options = {}) =>
compileWithRspack(deps, {
options: Meteor.swcConfigOptions,
options: mergeSplitOverlap(Meteor.swcConfigOptions, options),
});
Meteor.setCache = enabled =>
setCache(
@@ -285,6 +285,7 @@ module.exports = async function (inMeteor = {}, argv = {}) {
);
Meteor.splitVendorChunk = () => splitVendorChunk();
Meteor.extendSwcConfig = (customSwcConfig) => extendSwcConfig(customSwcConfig);
Meteor.extendConfig = (...configs) => mergeSplitOverlap(...configs);
// Add HtmlRspackPlugin function to Meteor
Meteor.HtmlRspackPlugin = (options = {}) => {

View File

@@ -142,16 +142,6 @@ BCp.initializeMeteorAppSwcrc = function () {
return lastModifiedSwcConfig;
};
let lastModifiedSwcLegacyConfig;
BCp.initializeMeteorAppLegacyConfig = function () {
const swcLegacyConfig = convertBabelTargetsForSwc(Babel.getMinimumModernBrowserVersions());
if (this.isVerbose() && !lastModifiedSwcLegacyConfig) {
logConfigBlock('SWC Legacy Config', swcLegacyConfig);
}
lastModifiedSwcLegacyConfig = swcLegacyConfig;
return lastModifiedSwcConfig;
};
// Helper function to check if @swc/helpers is available
function hasSwcHelpers() {
return fs.existsSync(`${getMeteorAppDir()}/node_modules/@swc/helpers`);
@@ -196,7 +186,6 @@ BCp.processFilesForTarget = function (inputFiles) {
this.initializeMeteorAppConfig();
this.initializeMeteorAppSwcrc();
this.initializeMeteorAppLegacyConfig();
this.initializeMeteorAppSwcHelpersAvailable();
inputFiles.forEach(function (inputFile) {
@@ -242,11 +231,13 @@ BCp.processOneFileForTarget = function (inputFile, source) {
sourceMap: null,
bare: !! fileOptions.bare
};
const arch = inputFile.getArch();
const isLegacyWebArch = arch.includes('legacy');
// Check if the file is a Rspack output file
// If it is, bypass SWC/Babel and just read the file and its map file
// as the contents are already transpiled by Rspack.
if (Plugin?.rspackHelpers?.isRspackOutputFile(inputFilePath)) {
if (Plugin?.rspackHelpers?.isRspackOutputFile(inputFilePath) && !isLegacyWebArch) {
try {
// Get the full path to the file
const fullPath = inputFile.getPathInPackage();
@@ -290,7 +281,6 @@ if (Plugin?.rspackHelpers?.isRspackOutputFile(inputFilePath)) {
! excludedFileExtensionPattern.test(inputFilePath)) {
const features = Object.assign({}, this.extraFeatures);
const arch = inputFile.getArch();
const isNodeTarget = arch.startsWith("os.");
if (isNodeTarget) {
@@ -381,7 +371,22 @@ if (Plugin?.rspackHelpers?.isRspackOutputFile(inputFilePath)) {
filename,
sourceFileName: filename,
...(isLegacyWebArch && {
env: { targets: lastModifiedSwcLegacyConfig || {} },
env: {
targets: {
chrome: '49',
edge: '15',
firefox: '30',
safari: '10',
ios: '10',
android: '5',
opera: '42',
ie: '11',
node: '8',
electron: '1.6',
},
mode: 'entry',
coreJs: '3.37',
},
}),
};
@@ -414,7 +419,6 @@ if (Plugin?.rspackHelpers?.isRspackOutputFile(inputFilePath)) {
const isNodeModulesCode = packageName == null && inputFilePath.includes("node_modules/");
const isAppCode = packageName == null && !isNodeModulesCode;
const isPackageCode = packageName != null;
const isLegacyWebArch = arch.includes('legacy');
const transpConfig = getMeteorConfig()?.modern?.transpiler;
const hasModernTranspiler = transpConfig != null && transpConfig !== false;

View File

@@ -49,6 +49,7 @@ export class MeteorMinifier {
const NODE_ENV = process.env.NODE_ENV || 'development';
let content = file.getContentsAsString();
const isLegacyWebArch = file?._arch === 'web.browser.legacy';
return swc.minifySync(
content,
@@ -60,6 +61,7 @@ export class MeteorMinifier {
unused: true,
dead_code: true,
typeofs: false,
...(isLegacyWebArch && { defaults: false }),
global_defs: {
'process.env.NODE_ENV': NODE_ENV,

View File

@@ -235,7 +235,6 @@ selftest.define("modern build stack - transpiler boolean-like options", async fu
/* check verbose logs */
await run.match(/SWC Custom Config/, false, true);
await run.match(/SWC Legacy Config/, false, true);
await run.match(/Meteor Config/, false, true);
/* check transpiler options */
@@ -331,7 +330,6 @@ console.log('Loaded NPM package "config"', require('config').id);`);
/* check verbose logs */
await run.match(/SWC Custom Config/, false, true);
await run.match(/SWC Legacy Config/, false, true);
await run.match(/Meteor Config/, false, true);
/* check transpiler options */

View File

@@ -141,23 +141,24 @@ module.exports = defineConfig(Meteor => {
You can use flags to control the final configuration based on the environment. The available flags are passed in the `Meteor` parameter.
| Flag | Type | Description |
|---------------------| -------- |-----------------------------------------------------------------------------------------------------------|
| `isDevelopment` | boolean | True when running in development mode |
| `isProduction` | boolean | True when running in production mode |
| `isClient` | boolean | True when building or running client code |
| `isServer` | boolean | True when building or running server code |
| `isTest` | boolean | True when running in test mode |
| `isDebug` | boolean | True when debug mode is enabled |
| `isRun` | boolean | True when running the project with `meteor run` |
| `isBuild` | boolean | True when building the project with `meteor build` |
| `swcConfigOptions` | object | Project-level SWC config available for reusing |
| `HtmlRspackPlugin` | function | Custom HtmlRspackPlugin function for extending the config |
| `compileWithMeteor` | function | Forces given npm deps ([Condition](https://rspack.rs/config/module#condition)[]) to be compiled by Meteor |
| `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 |
| Flag | Type | Description |
|---------------------| -------- |-----------------------------------------------------------------------------------------------------------------------------------|
| `isDevelopment` | boolean | True when running in development mode |
| `isProduction` | boolean | True when running in production mode |
| `isClient` | boolean | True when building or running client code |
| `isServer` | boolean | True when building or running server code |
| `isTest` | boolean | True when running in test mode |
| `isDebug` | boolean | True when debug mode is enabled |
| `isRun` | boolean | True when running the project with `meteor run` |
| `isBuild` | boolean | True when building the project with `meteor build` |
| `swcConfigOptions` | object | Project-level SWC config available for reusing |
| `HtmlRspackPlugin` | function | Custom HtmlRspackPlugin function for extending the config |
| `compileWithMeteor` | function | Forces given npm deps ([Condition](https://rspack.rs/config/module#condition)[]) to be compiled by Meteor |
| `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 |
| `extendConfig` | function | Extends the config by applying merged object configs |
Some configurations in the Rspack config are reserved for the Meteor-Rspack setup to work, such as Rspack options inside the `entry` and `output` objects. These will trigger warnings if modified. All other settings can be overridden, giving you the flexibility to make any setup compatible with the modern bundler.
@@ -520,7 +521,7 @@ You can still use HTML files near your Meteor client entry point to define custo
### Delegating Dependencies to Rspack
**Meteor.compileWithRspack(deps: [Condition](https://rspack.rs/config/module#condition)[])**
**Meteor.compileWithRspack(deps: [Condition](https://rspack.rs/config/module#condition)[], options?: [SwcLoaderOptions](https://v0.rspack.dev/guide/features/builtin-swc-loader#options))**
This helper forces **Rspack (via SWC and custom loaders)** to parse and transpile specific npm dependencies during the build.
@@ -536,6 +537,8 @@ const { defineConfig } = require('@meteorjs/rspack');
module.exports = defineConfig(Meteor => ({
// Force-compile modern or local packages via SWC
...Meteor.compileWithRspack(['grubba-rpc']),
// Force-compile zod with ES5 target
...Meteor.compileWithRspack(['zod'], { jsc: { target: 'es5' } }),
}));
```