@meteorjs/rspack 1.1.0-beta.21 → 1.1.0-beta.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.ts CHANGED
@@ -75,6 +75,12 @@ type MeteorEnv = Record<string, any> & {
75
75
  disablePlugins: (
76
76
  matchers: string | RegExp | ((plugin: any, index: number) => boolean) | Array<string | RegExp | ((plugin: any, index: number) => boolean)>
77
77
  ) => Record<string, any>;
78
+ /**
79
+ * Omit `Meteor.isDevelopment` and `Meteor.isProduction` from the DefinePlugin so
80
+ * the bundle is not tied to a specific Meteor environment (portable / isomorphic builds).
81
+ * @returns A config fragment with `meteor.enablePortableBuild: true`
82
+ */
83
+ enablePortableBuild: () => Record<string, any>;
78
84
  }
79
85
 
80
86
  export type ConfigFactory = (
@@ -152,6 +152,19 @@ function extendSwcConfig(swcConfig) {
152
152
  });
153
153
  }
154
154
 
155
+ /**
156
+ * Signal that `Meteor.isDevelopment` and `Meteor.isProduction` should be omitted
157
+ * from DefinePlugin, making the bundle portable across Meteor environments.
158
+ * Usage: return Meteor.enablePortableBuild() in your rspack.config.js
159
+ *
160
+ * @returns {Record<string, object>} config fragment with `meteor.enablePortableBuild: true`
161
+ */
162
+ function enablePortableBuild() {
163
+ return prepareMeteorRspackConfig({
164
+ "meteor.enablePortableBuild": true,
165
+ });
166
+ }
167
+
155
168
  /**
156
169
  * Remove plugins from a Rspack config by name, RegExp, predicate, or array of them.
157
170
  * When using a function predicate, it receives both the plugin and its index in the plugins array.
@@ -210,4 +223,5 @@ module.exports = {
210
223
  extendSwcConfig,
211
224
  makeWebNodeBuiltinsAlias,
212
225
  disablePlugins,
226
+ enablePortableBuild,
213
227
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meteorjs/rspack",
3
- "version": "1.1.0-beta.21",
3
+ "version": "1.1.0-beta.22",
4
4
  "description": "Configuration logic for using Rspack in Meteor projects",
5
5
  "main": "index.js",
6
6
  "type": "commonjs",
package/rspack.config.js CHANGED
@@ -20,6 +20,7 @@ const {
20
20
  extendSwcConfig,
21
21
  makeWebNodeBuiltinsAlias,
22
22
  disablePlugins,
23
+ enablePortableBuild,
23
24
  } = require('./lib/meteorRspackHelpers.js');
24
25
  const { loadUserAndOverrideConfig } = require('./lib/meteorRspackConfigHelpers.js');
25
26
  const { prepareMeteorRspackConfig } = require("./lib/meteorRspackConfigFactory");
@@ -214,6 +215,7 @@ module.exports = async function (inMeteor = {}, argv = {}) {
214
215
  const isTestLike = !!Meteor.isTestLike;
215
216
  const swcExternalHelpers = !!Meteor.swcExternalHelpers;
216
217
  const isNative = !!Meteor.isNative;
218
+ const devServerPort = Meteor.devServerPort || 8080;
217
219
 
218
220
  const projectDir = process.cwd();
219
221
  const projectConfigPath =
@@ -225,17 +227,6 @@ module.exports = async function (inMeteor = {}, argv = {}) {
225
227
  const outputDir = path.dirname(Meteor.outputPath || "");
226
228
  Meteor.buildOutputDir = path.resolve(projectDir, buildContext, outputDir);
227
229
 
228
- // Defined here so it can be called both before and after the first config load;
229
- // without loaded configs it falls through to argv/Meteor flags.
230
- const getModeFromConfig = (userConfig = undefined, overrideConfig = undefined) => {
231
- if (overrideConfig?.mode) return overrideConfig.mode;
232
- if (userConfig?.mode) return userConfig.mode;
233
- if (argv.mode) return argv.mode;
234
- if (Meteor.isProduction) return "production";
235
- if (Meteor.isDevelopment) return "development";
236
- return null;
237
- };
238
-
239
230
  // Meteor flags derived purely from input; independent of loaded user/override configs
240
231
  const isTest = !!Meteor.isTest;
241
232
  const isClient = !!Meteor.isClient;
@@ -247,16 +238,33 @@ module.exports = async function (inMeteor = {}, argv = {}) {
247
238
  const isTestEager = !!Meteor.isTestEager;
248
239
  const isTestFullApp = !!Meteor.isTestFullApp;
249
240
  const isTypescriptEnabled = Meteor.isTypescriptEnabled || false;
250
- const isJsxEnabled = Meteor.isJsxEnabled || (!isTypescriptEnabled && isReactEnabled) || false;
251
- const isTsxEnabled = Meteor.isTsxEnabled || (isTypescriptEnabled && isReactEnabled) || false;
241
+ const isJsxEnabled =
242
+ Meteor.isJsxEnabled || (!isTypescriptEnabled && isReactEnabled) || false;
243
+ const isTsxEnabled =
244
+ Meteor.isTsxEnabled || (isTypescriptEnabled && isReactEnabled) || false;
252
245
  const isBundleVisualizerEnabled = Meteor.isBundleVisualizerEnabled || false;
253
246
  const isAngularEnabled = Meteor.isAngularEnabled || false;
254
247
  const enableSwcExternalHelpers = !isServer && swcExternalHelpers;
255
248
 
249
+ // Defined here so it can be called both before and after the first config load;
250
+ // without loaded configs it falls through to argv/Meteor flags.
251
+ const getModeFromConfig = (userConfig, overrideConfig) => {
252
+ if (overrideConfig?.mode) return overrideConfig.mode;
253
+ if (userConfig?.mode) return userConfig.mode;
254
+ if (argv.mode) return argv.mode;
255
+ if (Meteor.isProduction) return "production";
256
+ if (Meteor.isDevelopment) return "development";
257
+ return null;
258
+ };
259
+
256
260
  // Initial mode before user/override configs are loaded
257
261
  const initialCurrentMode = getModeFromConfig();
258
- const initialIsProd = initialCurrentMode ? initialCurrentMode === "production" : !!Meteor.isProduction;
259
- const initialIsDev = initialCurrentMode ? initialCurrentMode === "development" : !!Meteor.isDevelopment || !initialIsProd;
262
+ const initialIsProd = initialCurrentMode
263
+ ? initialCurrentMode === "production"
264
+ : !!Meteor.isProduction;
265
+ const initialIsDev = initialCurrentMode
266
+ ? initialCurrentMode === "development"
267
+ : !!Meteor.isDevelopment || !initialIsProd;
260
268
  const initialMode = initialIsProd ? "production" : "development";
261
269
 
262
270
  // Initialized with pre-load values so helpers work during the first config load;
@@ -294,6 +302,7 @@ module.exports = async function (inMeteor = {}, argv = {}) {
294
302
  prepareMeteorRspackConfig({
295
303
  disablePlugins: matchers,
296
304
  });
305
+ Meteor.enablePortableBuild = () => enablePortableBuild();
297
306
 
298
307
  // Add HtmlRspackPlugin function to Meteor
299
308
  Meteor.HtmlRspackPlugin = (options = {}) => {
@@ -319,8 +328,10 @@ module.exports = async function (inMeteor = {}, argv = {}) {
319
328
 
320
329
  // First pass: resolve user/override configs early so mode overrides (e.g. "production")
321
330
  // are available before computing isProd/isDev and the rest of the build flags.
322
- let { nextUserConfig, nextOverrideConfig } =
323
- await loadUserAndOverrideConfig(projectConfigPath, Meteor, argv);
331
+ // Skipped for Angular since it manages its own mode via the second pass.
332
+ let { nextUserConfig, nextOverrideConfig } = isAngularEnabled
333
+ ? {}
334
+ : await loadUserAndOverrideConfig(projectConfigPath, Meteor, argv);
324
335
 
325
336
  // Determine the final mode with loaded configs
326
337
  const currentMode = getModeFromConfig(nextUserConfig, nextOverrideConfig);
@@ -331,6 +342,10 @@ module.exports = async function (inMeteor = {}, argv = {}) {
331
342
  ? currentMode === "development"
332
343
  : !!Meteor.isDevelopment || !isProd;
333
344
  const mode = isProd ? "production" : "development";
345
+ const isPortableBuild = !!(
346
+ nextUserConfig?.["meteor.enablePortableBuild"] ||
347
+ nextOverrideConfig?.["meteor.enablePortableBuild"]
348
+ );
334
349
  const configPath = Meteor.configPath;
335
350
  const testEntry = Meteor.testEntry;
336
351
 
@@ -564,8 +579,10 @@ module.exports = async function (inMeteor = {}, argv = {}) {
564
579
  "Meteor.isServer": JSON.stringify(false),
565
580
  "Meteor.isTest": JSON.stringify(isTestLike && !isTestFullApp),
566
581
  "Meteor.isAppTest": JSON.stringify(isTestLike && isTestFullApp),
567
- "Meteor.isDevelopment": JSON.stringify(isDev),
568
- "Meteor.isProduction": JSON.stringify(isProd),
582
+ ...(!isPortableBuild && {
583
+ "Meteor.isDevelopment": JSON.stringify(isDev),
584
+ "Meteor.isProduction": JSON.stringify(isProd),
585
+ }),
569
586
  }),
570
587
  ...bannerPluginConfig,
571
588
  Meteor.HtmlRspackPlugin(),
@@ -586,7 +603,7 @@ module.exports = async function (inMeteor = {}, argv = {}) {
586
603
  hot: true,
587
604
  liveReload: true,
588
605
  ...(Meteor.isBlazeEnabled && { hot: false }),
589
- port: Meteor.devServerPort || 8080,
606
+ port: devServerPort,
590
607
  devMiddleware: {
591
608
  writeToDisk: (filePath) =>
592
609
  /\.(html)$/.test(filePath) && !filePath.includes(".hot-update."),
@@ -662,15 +679,19 @@ module.exports = async function (inMeteor = {}, argv = {}) {
662
679
  ? {
663
680
  "Meteor.isTest": JSON.stringify(isTest && !isTestFullApp),
664
681
  "Meteor.isAppTest": JSON.stringify(isTest && isTestFullApp),
665
- "Meteor.isDevelopment": JSON.stringify(isDev),
682
+ ...(!isPortableBuild && {
683
+ "Meteor.isDevelopment": JSON.stringify(isDev),
684
+ }),
666
685
  }
667
686
  : {
668
687
  "Meteor.isClient": JSON.stringify(false),
669
688
  "Meteor.isServer": JSON.stringify(true),
670
689
  "Meteor.isTest": JSON.stringify(isTestLike && !isTestFullApp),
671
690
  "Meteor.isAppTest": JSON.stringify(isTestLike && isTestFullApp),
672
- "Meteor.isDevelopment": JSON.stringify(isDev),
673
- "Meteor.isProduction": JSON.stringify(isProd),
691
+ ...(!isPortableBuild && {
692
+ "Meteor.isDevelopment": JSON.stringify(isDev),
693
+ "Meteor.isProduction": JSON.stringify(isProd),
694
+ }),
674
695
  }
675
696
  ),
676
697
  ...bannerPluginConfig,
@@ -692,7 +713,7 @@ module.exports = async function (inMeteor = {}, argv = {}) {
692
713
  const angularExpandConfig = isAngularEnabled
693
714
  ? {
694
715
  mode: isProd ? "production" : "development",
695
- devServer: { port: Meteor.devServerPort },
716
+ devServer: { port: devServerPort },
696
717
  stats: { preset: "normal" },
697
718
  infrastructureLogging: { level: "info" },
698
719
  ...(isProd && isClient && { output: { module: false } }),
@@ -719,23 +740,24 @@ module.exports = async function (inMeteor = {}, argv = {}) {
719
740
  }
720
741
  : {};
721
742
 
743
+
722
744
  // Second pass: re-run only when a mode override was detected, so the user config
723
745
  // can depend on fully-computed Meteor flags and helpers (swcConfigOptions, buildOutputDir, etc.).
724
- if (nextUserConfig?.mode || nextOverrideConfig?.mode) {
725
- ({ nextUserConfig, nextOverrideConfig } =
726
- await loadUserAndOverrideConfig(projectConfigPath, Meteor, argv));
746
+ if (nextUserConfig?.mode || nextOverrideConfig?.mode || isAngularEnabled) {
747
+ ({ nextUserConfig, nextOverrideConfig } = await loadUserAndOverrideConfig(
748
+ projectConfigPath,
749
+ Meteor,
750
+ argv
751
+ ));
727
752
  }
728
-
729
- let config = mergeSplitOverlap(
730
- isClient ? clientConfig : serverConfig,
731
- angularExpandConfig
732
- );
733
- config = mergeSplitOverlap(config, testClientExpandConfig);
734
-
753
+ let config = isClient ? clientConfig : serverConfig;
735
754
  if (nextUserConfig) {
736
755
  config = mergeSplitOverlap(config, nextUserConfig);
737
756
  }
738
757
 
758
+ config = mergeSplitOverlap(config, angularExpandConfig);
759
+ config = mergeSplitOverlap(config, testClientExpandConfig);
760
+
739
761
  if (nextOverrideConfig) {
740
762
  config = mergeSplitOverlap(config, nextOverrideConfig);
741
763
  }
@@ -746,9 +768,11 @@ module.exports = async function (inMeteor = {}, argv = {}) {
746
768
  delete config.disablePlugins;
747
769
  }
748
770
 
749
- if (Meteor.isDebug || Meteor.isVerbose) {
771
+ delete config["meteor.enablePortableBuild"];
772
+
773
+ // if (Meteor.isDebug || Meteor.isVerbose) {
750
774
  console.log("Config:", inspect(config, { depth: null, colors: true }));
751
- }
775
+ // }
752
776
 
753
777
  // Check if lazyCompilation is enabled and warn the user
754
778
  if (