@meteorjs/rspack 1.0.0 → 1.1.0-beta.10

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/lib/ignore.js CHANGED
@@ -117,7 +117,7 @@ function createIgnoreRegex(globPatterns) {
117
117
 
118
118
  // For absolute paths, we don't want to force the pattern to match from the beginning
119
119
  // but we still want to ensure it matches to the end of the path segment
120
- regexPattern = '(?:^|/)' + regexPattern + '$';
120
+ regexPattern = '(?:^|/)' + regexPattern;
121
121
 
122
122
  return regexPattern;
123
123
  }).filter(pattern => pattern !== null);
@@ -202,6 +202,12 @@ function disablePlugins(config, matchers) {
202
202
  return config;
203
203
  }
204
204
 
205
+ function outputMeteorRspack(data) {
206
+ const jsonString = JSON.stringify(data);
207
+ const output = `[Meteor-Rspack]${jsonString}[/Meteor-Rspack]`;
208
+ console.log(output);
209
+ }
210
+
205
211
  module.exports = {
206
212
  compileWithMeteor,
207
213
  compileWithRspack,
@@ -210,4 +216,5 @@ module.exports = {
210
216
  extendSwcConfig,
211
217
  makeWebNodeBuiltinsAlias,
212
218
  disablePlugins,
219
+ outputMeteorRspack,
213
220
  };
package/lib/test.js CHANGED
@@ -9,17 +9,20 @@ const { createIgnoreRegex, createIgnoreGlobConfig } = require("./ignore.js");
9
9
  * @param {string} options.projectDir - The project directory
10
10
  * @param {string} options.buildContext - The build context
11
11
  * @param {string[]} options.ignoreEntries - Array of ignore patterns
12
+ * @param {string[]} options.meteorIgnoreEntries - Array of meteor ignore patterns
12
13
  * @param {string} options.extraEntry - Extra entry to load
13
14
  * @returns {string} The path to the generated file
14
15
  */
15
16
  const generateEagerTestFile = ({
16
- isAppTest,
17
- projectDir,
18
- buildContext,
19
- ignoreEntries: inIgnoreEntries = [],
20
- prefix: inPrefix = '',
21
- extraEntry,
22
- }) => {
17
+ isAppTest,
18
+ projectDir,
19
+ buildContext,
20
+ ignoreEntries: inIgnoreEntries = [],
21
+ meteorIgnoreEntries: inMeteorIgnoreEntries = [],
22
+ prefix: inPrefix = '',
23
+ extraEntry,
24
+ globalImportPath,
25
+ }) => {
23
26
  const distDir = path.resolve(projectDir, ".meteor/local/test");
24
27
  if (!fs.existsSync(distDir)) {
25
28
  fs.mkdirSync(distDir, { recursive: true });
@@ -39,6 +42,11 @@ const generateEagerTestFile = ({
39
42
  const excludeFoldersRegex = createIgnoreRegex(
40
43
  createIgnoreGlobConfig(ignoreEntries)
41
44
  );
45
+ console.log("inMeteorIgnoreEntries", inMeteorIgnoreEntries);
46
+ // Create regex from meteor ignore entries
47
+ const excludeMeteorIgnoreRegex = inMeteorIgnoreEntries.length > 0
48
+ ? createIgnoreRegex(createIgnoreGlobConfig(inMeteorIgnoreEntries))
49
+ : null;
42
50
 
43
51
  const prefix = (inPrefix && `${inPrefix}-`) || "";
44
52
  const filename = isAppTest
@@ -49,25 +57,39 @@ const generateEagerTestFile = ({
49
57
  ? "/\\.app-(?:test|spec)s?\\.[^.]+$/"
50
58
  : "/\\.(?:test|spec)s?\\.[^.]+$/";
51
59
 
52
- const content = `{
53
- const ctx = import.meta.webpackContext('/', {
60
+ const content = `${
61
+ globalImportPath ? `import '${globalImportPath}';\n\n` : ""
62
+ }${
63
+ excludeMeteorIgnoreRegex
64
+ ? `const MeteorIgnoreRegex = ${excludeMeteorIgnoreRegex.toString()};`
65
+ : ""
66
+ }
67
+ {
68
+ const ctx = import.meta.webpackContext('${projectDir}', {
54
69
  recursive: true,
55
70
  regExp: ${regExp},
56
71
  exclude: ${excludeFoldersRegex.toString()},
57
72
  mode: 'eager',
58
73
  });
59
- ctx.keys().forEach(ctx);
74
+ ctx.keys().filter((k) => {
75
+ ${
76
+ excludeMeteorIgnoreRegex
77
+ ? `// Only exclude based on *relative* path segments.
78
+ return !MeteorIgnoreRegex.test(k);`
79
+ : "return true;"
80
+ }
81
+ }).forEach(ctx);
60
82
  ${
61
83
  extraEntry
62
84
  ? `const extra = import.meta.webpackContext('${path.dirname(
63
- extraEntry
64
- )}', {
85
+ extraEntry
86
+ )}', {
65
87
  recursive: false,
66
88
  regExp: ${new RegExp(`${path.basename(extraEntry)}$`).toString()},
67
89
  mode: 'eager',
68
90
  });
69
91
  extra.keys().forEach(extra);`
70
- : ''
92
+ : ""
71
93
  }
72
94
  }`;
73
95
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meteorjs/rspack",
3
- "version": "1.0.0",
3
+ "version": "1.1.0-beta.10",
4
4
  "description": "Configuration logic for using Rspack in Meteor projects",
5
5
  "main": "index.js",
6
6
  "type": "commonjs",
@@ -0,0 +1,36 @@
1
+ // MeteorRspackOutputPlugin.js
2
+ //
3
+ // This plugin outputs a JSON stringified with a tag delimiter each time
4
+ // a new Rspack compilation happens. The JSON content is configurable
5
+ // via plugin instantiation options.
6
+
7
+ const { outputMeteorRspack } = require('../lib/meteorRspackHelpers');
8
+
9
+ class MeteorRspackOutputPlugin {
10
+ constructor(options = {}) {
11
+ this.pluginName = 'MeteorRspackOutputPlugin';
12
+ this.options = options;
13
+ this.compilationCount = 0;
14
+ // The data to be output as JSON, can be a static object or a function
15
+ this.getData =
16
+ typeof options.getData === 'function'
17
+ ? options.getData
18
+ : () => options.data || {};
19
+ }
20
+
21
+ apply(compiler) {
22
+ // Hook into the 'done' event which fires after each compilation completes
23
+ compiler.hooks.done.tap(this.pluginName, stats => {
24
+ this.compilationCount++;
25
+ const data = {
26
+ ...(this.getData(stats, {
27
+ compilationCount: this.compilationCount,
28
+ isRebuild: this.compilationCount > 1,
29
+ }) || {}),
30
+ };
31
+ outputMeteorRspack(data);
32
+ });
33
+ }
34
+ }
35
+
36
+ module.exports = { MeteorRspackOutputPlugin };
package/rspack.config.js CHANGED
@@ -10,6 +10,7 @@ const { getMeteorAppSwcConfig } = require('./lib/swc.js');
10
10
  const HtmlRspackPlugin = require('./plugins/HtmlRspackPlugin.js');
11
11
  const { RequireExternalsPlugin } = require('./plugins/RequireExtenalsPlugin.js');
12
12
  const { AssetExternalsPlugin } = require('./plugins/AssetExternalsPlugin.js');
13
+ const { MeteorRspackOutputPlugin } = require('./plugins/MeteorRspackOutputPlugin.js');
13
14
  const { generateEagerTestFile } = require("./lib/test.js");
14
15
  const { getMeteorIgnoreEntries, createIgnoreGlobConfig } = require("./lib/ignore");
15
16
  const { mergeMeteorRspackFragments } = require("./lib/meteorRspackConfigFactory.js");
@@ -21,6 +22,7 @@ const {
21
22
  extendSwcConfig,
22
23
  makeWebNodeBuiltinsAlias,
23
24
  disablePlugins,
25
+ outputMeteorRspack,
24
26
  } = require('./lib/meteorRspackHelpers.js');
25
27
  const { prepareMeteorRspackConfig } = require("./lib/meteorRspackConfigFactory");
26
28
 
@@ -225,13 +227,13 @@ module.exports = async function (inMeteor = {}, argv = {}) {
225
227
  const isTestLike = !!Meteor.isTestLike;
226
228
  const swcExternalHelpers = !!Meteor.swcExternalHelpers;
227
229
  const isNative = !!Meteor.isNative;
230
+ const isProfile = !!Meteor.isProfile;
231
+ const isVerbose = !!Meteor.isVerbose;
228
232
  const mode = isProd ? 'production' : 'development';
229
233
  const projectDir = process.cwd();
230
234
  const projectConfigPath = Meteor.projectConfigPath || path.resolve(projectDir, 'rspack.config.js');
231
235
  const configPath = Meteor.configPath;
232
236
  const testEntry = Meteor.testEntry;
233
- const testClientEntry = Meteor.testClientEntry;
234
- const testServerEntry = Meteor.testServerEntry;
235
237
 
236
238
  const isTypescriptEnabled = Meteor.isTypescriptEnabled || false;
237
239
  const isJsxEnabled =
@@ -429,30 +431,36 @@ module.exports = async function (inMeteor = {}, argv = {}) {
429
431
  : [];
430
432
  // Not supported in Meteor yet (Rspack 1.7+ is enabled by default)
431
433
  const lazyCompilationConfig = { lazyCompilation: false };
434
+ const shouldLogVerbose = isProfile || isVerbose;
435
+ const loggingConfig = shouldLogVerbose
436
+ ? {}
437
+ : { stats: "errors-warnings", infrastructureLogging: { level: "warn" } };
432
438
 
433
439
  const clientEntry =
434
- isTest && isTestEager && isTestFullApp
440
+ isClient && isTest && isTestEager && isTestFullApp
435
441
  ? generateEagerTestFile({
436
442
  isAppTest: true,
437
443
  projectDir,
438
444
  buildContext,
439
- ignoreEntries: [...meteorIgnoreEntries, "**/server/**"],
445
+ ignoreEntries: ["**/server/**"],
446
+ meteorIgnoreEntries,
440
447
  prefix: "client",
441
448
  extraEntry: path.resolve(process.cwd(), Meteor.mainClientEntry),
449
+ globalImportPath: path.resolve(projectDir, buildContext, entryPath),
442
450
  })
443
- : isTest && isTestEager
451
+ : isClient && isTest && isTestEager
444
452
  ? generateEagerTestFile({
445
453
  isAppTest: false,
446
454
  isClient: true,
447
455
  projectDir,
448
456
  buildContext,
449
- ignoreEntries: [...meteorIgnoreEntries, "**/server/**"],
457
+ ignoreEntries: ["**/server/**"],
458
+ meteorIgnoreEntries,
450
459
  prefix: "client",
460
+ globalImportPath: path.resolve(projectDir, buildContext, entryPath),
451
461
  })
452
- : isTest && testEntry
462
+ : isClient && isTest && testEntry
453
463
  ? path.resolve(process.cwd(), testEntry)
454
- : isTest && testClientEntry
455
- ? path.resolve(process.cwd(), testClientEntry)
456
464
  : path.resolve(process.cwd(), buildContext, entryPath);
457
465
  const clientNameConfig = `[${(isTest && 'test-') || ''}client-rspack]`;
458
466
  // Base client config
@@ -545,33 +553,43 @@ module.exports = async function (inMeteor = {}, argv = {}) {
545
553
  writeToDisk: filePath =>
546
554
  /\.(html)$/.test(filePath) && !filePath.includes('.hot-update.'),
547
555
  },
556
+ onListening(devServer) {
557
+ if (!devServer) return;
558
+ const { host, port } = devServer.options;
559
+ const protocol = devServer.options.server?.type === "https" ? "https" : "http";
560
+ const devServerUrl = `${protocol}://${host || "localhost"}:${port}`;
561
+ outputMeteorRspack({ devServerUrl });
562
+ },
548
563
  },
549
564
  }),
550
565
  ...merge(cacheStrategy, { experiments: { css: true } }),
551
566
  ...lazyCompilationConfig,
567
+ ...loggingConfig,
552
568
  };
553
569
 
554
570
  const serverEntry =
555
- isTest && isTestEager && isTestFullApp
571
+ isServer && isTest && isTestEager && isTestFullApp
556
572
  ? generateEagerTestFile({
557
573
  isAppTest: true,
558
574
  projectDir,
559
575
  buildContext,
560
- ignoreEntries: [...meteorIgnoreEntries, "**/client/**"],
576
+ ignoreEntries: ["**/client/**"],
577
+ meteorIgnoreEntries,
561
578
  prefix: "server",
579
+ globalImportPath: path.resolve(projectDir, buildContext, entryPath),
562
580
  })
563
- : isTest && isTestEager
581
+ : isServer && isTest && isTestEager
564
582
  ? generateEagerTestFile({
565
583
  isAppTest: false,
566
584
  projectDir,
567
585
  buildContext,
568
- ignoreEntries: [...meteorIgnoreEntries, "**/client/**"],
586
+ ignoreEntries: ["**/client/**"],
587
+ meteorIgnoreEntries,
569
588
  prefix: "server",
589
+ globalImportPath: path.resolve(projectDir, buildContext, entryPath),
570
590
  })
571
- : isTest && testEntry
591
+ : isServer && isTest && testEntry
572
592
  ? path.resolve(process.cwd(), testEntry)
573
- : isTest && testServerEntry
574
- ? path.resolve(process.cwd(), testServerEntry)
575
593
  : path.resolve(projectDir, buildContext, entryPath);
576
594
  const serverNameConfig = `[${(isTest && 'test-') || ''}server-rspack]`;
577
595
  // Base server config
@@ -637,6 +655,7 @@ module.exports = async function (inMeteor = {}, argv = {}) {
637
655
  ...((isDevEnvironment || (isTest && !isTestEager) || isNative) &&
638
656
  cacheStrategy),
639
657
  ...lazyCompilationConfig,
658
+ ...loggingConfig,
640
659
  };
641
660
 
642
661
  // Helper function to load and process config files
@@ -696,6 +715,8 @@ module.exports = async function (inMeteor = {}, argv = {}) {
696
715
  // Load and apply project-level overrides for the selected build
697
716
  // Check if we're in a Meteor package directory by looking at the path
698
717
  const isMeteorPackageConfig = projectDir.includes('/packages/rspack');
718
+ // Track if user config overrides stats and infrastructureLogging
719
+ let statsOverrided = false;
699
720
  if (fs.existsSync(projectConfigPath) && !isMeteorPackageConfig) {
700
721
  // Check if there's a .mjs or .cjs version of the config file
701
722
  const mjsConfigPath = projectConfigPath.replace(/\.js$/, '.mjs');
@@ -716,7 +737,11 @@ module.exports = async function (inMeteor = {}, argv = {}) {
716
737
  isAngularEnabled
717
738
  );
718
739
 
740
+ // Track if user config overrides stats
719
741
  if (nextUserConfig) {
742
+ if (nextUserConfig.stats != null) {
743
+ statsOverrided = true;
744
+ }
720
745
  if (Meteor.isClient) {
721
746
  clientConfig = mergeSplitOverlap(clientConfig, nextUserConfig);
722
747
  }
@@ -807,5 +832,20 @@ module.exports = async function (inMeteor = {}, argv = {}) {
807
832
  );
808
833
  }
809
834
 
835
+ // Add MeteorRspackOutputPlugin as the last plugin to output compilation info
836
+ const meteorRspackOutputPlugin = new MeteorRspackOutputPlugin({
837
+ getData: (stats, { isRebuild, compilationCount }) => ({
838
+ name: config.name,
839
+ mode: config.mode,
840
+ hasErrors: stats.hasErrors(),
841
+ hasWarnings: stats.hasWarnings(),
842
+ timestamp: Date.now(),
843
+ statsOverrided,
844
+ compilationCount,
845
+ isRebuild,
846
+ }),
847
+ });
848
+ config.plugins = [meteorRspackOutputPlugin, ...(config.plugins || [])];
849
+
810
850
  return [config];
811
851
  }