@meteorjs/rspack 1.1.0-beta.30 → 1.1.0-beta.32

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.
@@ -6,6 +6,96 @@
6
6
 
7
7
  const { outputMeteorRspack } = require('../lib/meteorRspackHelpers');
8
8
 
9
+ /**
10
+ * Extracts file extensions that rspack is configured to handle
11
+ * from the resolved module.rules test patterns.
12
+ * @param {import('@rspack/core').Compiler} compiler
13
+ * @returns {Set<string>} Set of extensions like .css, .less, .scss
14
+ */
15
+ function extractConfiguredExtensions(compiler) {
16
+ const delegatableExtensions = ['.css', '.less', '.scss', '.sass', '.styl'];
17
+ const found = new Set();
18
+
19
+ function inspectRules(rules) {
20
+ for (const rule of rules) {
21
+ if (!rule) continue;
22
+ if (rule.test) {
23
+ const testStr = rule.test instanceof RegExp
24
+ ? rule.test.source
25
+ : String(rule.test);
26
+ for (const ext of delegatableExtensions) {
27
+ const escaped = ext.replace('.', '\\.');
28
+ if (testStr.includes(escaped)) {
29
+ found.add(ext);
30
+ }
31
+ }
32
+ }
33
+ if (rule.oneOf) inspectRules(rule.oneOf);
34
+ if (rule.rules) inspectRules(rule.rules);
35
+ }
36
+ }
37
+
38
+ inspectRules(compiler.options.module?.rules || []);
39
+ return found;
40
+ }
41
+
42
+ /**
43
+ * Extracts file extensions that rspack both has rules for AND actually compiled
44
+ * from files within entry folder paths (e.g. client/, server/).
45
+ * An extension is only delegated if Rspack compiled a file with that extension
46
+ * from an entry folder. Files in non-entry folders (e.g. imports/) don't count,
47
+ * since delegation only ignores entry folder files for Meteor.
48
+ * @param {import('@rspack/core').Stats} stats
49
+ * @param {import('@rspack/core').Compiler} compiler
50
+ * @returns {string[]} Array of extensions like ['.css', '.less', '.scss']
51
+ */
52
+ function extractDelegatedExtensions(stats, compiler) {
53
+ const configured = extractConfiguredExtensions(compiler);
54
+ if (configured.size === 0) return [];
55
+
56
+ const path = require('path');
57
+ const fs = require('fs');
58
+ const appRoot = compiler.options.context || process.cwd();
59
+
60
+ // Read entry folders from package.json meteor.mainModule
61
+ const entryFolders = new Set();
62
+ try {
63
+ const pkgPath = path.join(appRoot, 'package.json');
64
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
65
+ const mainModule = pkg?.meteor?.mainModule || {};
66
+ for (const entry of Object.values(mainModule)) {
67
+ if (typeof entry === 'string') {
68
+ const folder = entry.split('/')[0];
69
+ if (folder) entryFolders.add(folder);
70
+ }
71
+ }
72
+ } catch (e) {
73
+ // If we can't read package.json, fall back to config-only
74
+ return Array.from(configured);
75
+ }
76
+
77
+ if (entryFolders.size === 0) return Array.from(configured);
78
+
79
+ const found = new Set();
80
+
81
+ for (const module of stats.compilation.modules) {
82
+ const resource = module.resource || module.userRequest;
83
+ if (!resource) continue;
84
+
85
+ const relativePath = path.relative(appRoot, resource);
86
+ const topFolder = relativePath.split(path.sep)[0];
87
+ if (!entryFolders.has(topFolder)) continue;
88
+
89
+ const ext = path.extname(resource);
90
+ if (configured.has(ext)) {
91
+ found.add(ext);
92
+ if (found.size === configured.size) break;
93
+ }
94
+ }
95
+
96
+ return Array.from(found);
97
+ }
98
+
9
99
  class MeteorRspackOutputPlugin {
10
100
  constructor(options = {}) {
11
101
  this.pluginName = 'MeteorRspackOutputPlugin';
@@ -26,6 +116,7 @@ class MeteorRspackOutputPlugin {
26
116
  ...(this.getData(stats, {
27
117
  compilationCount: this.compilationCount,
28
118
  isRebuild: this.compilationCount > 1,
119
+ compiler,
29
120
  }) || {}),
30
121
  };
31
122
  outputMeteorRspack(data);
@@ -33,4 +124,4 @@ class MeteorRspackOutputPlugin {
33
124
  }
34
125
  }
35
126
 
36
- module.exports = { MeteorRspackOutputPlugin };
127
+ module.exports = { MeteorRspackOutputPlugin, extractDelegatedExtensions };
@@ -10,6 +10,10 @@
10
10
  const fs = require('fs');
11
11
  const path = require('path');
12
12
 
13
+ // Normalize a path to always use forward slashes (POSIX style).
14
+ // Module identifiers in bundled JS must use '/' regardless of OS.
15
+ const toPosix = (p) => p.replace(/\\/g, '/');
16
+
13
17
  class RequireExternalsPlugin {
14
18
  constructor({
15
19
  filePath,
@@ -46,7 +50,7 @@ class RequireExternalsPlugin {
46
50
  // Prepare paths
47
51
  this.filePath = path.resolve(process.cwd(), filePath);
48
52
  this.backRoot = '../'.repeat(
49
- filePath.replace(/^\.?\/+/, '').split('/').length - 1
53
+ filePath.replace(/^\.?[/\\]+/, '').split(/[/\\]/).length - 1
50
54
  );
51
55
 
52
56
  // Initialize funcCount based on existing helpers in the file
@@ -96,14 +100,16 @@ class RequireExternalsPlugin {
96
100
  pkg &&
97
101
  (path.isAbsolute(pkg) ||
98
102
  pkg.startsWith('./') ||
103
+ pkg.startsWith('.\\') ||
99
104
  pkg.startsWith('../') ||
105
+ pkg.startsWith('..\\') ||
100
106
  !!depInfo.ext)
101
107
  ) {
102
108
  const module = this.externalsMeta.get(pkg);
103
109
  if (module) {
104
- return `${this.backRoot}${module.relativeRequest}`;
110
+ return `${this.backRoot}${toPosix(module.relativeRequest)}`;
105
111
  }
106
- return `${this.backRoot}${name}`;
112
+ return `${this.backRoot}${toPosix(name)}`;
107
113
  }
108
114
 
109
115
  return pkg;
@@ -132,7 +138,7 @@ class RequireExternalsPlugin {
132
138
  this.externalsMeta.set(externalRequest, {
133
139
  originalRequest: request,
134
140
  externalRequest,
135
- relativeRequest: path.join(relContext, request),
141
+ relativeRequest: toPosix(path.join(relContext, request)),
136
142
  });
137
143
 
138
144
  // tell Rspack "don't bundle this, import it at runtime"