@meteorjs/rspack 2.0.1 → 2.1.0

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/swc.js CHANGED
@@ -14,7 +14,13 @@ function getMeteorAppSwcrc(file = '.swcrc') {
14
14
 
15
15
  if (file.endsWith('.ts')) {
16
16
  try {
17
- const swc = require('@swc/core');
17
+ let swc;
18
+ try {
19
+ swc = require(require.resolve('@swc/core', { paths: [process.cwd()] }));
20
+ } catch (e) {
21
+ if (e.code !== 'MODULE_NOT_FOUND') throw e;
22
+ swc = require('@swc/core');
23
+ }
18
24
  const result = swc.transformSync(content, {
19
25
  jsc: {
20
26
  parser: {
@@ -0,0 +1,66 @@
1
+ const { ProvidePlugin } = require("@rspack/core");
2
+
3
+ let meteorNodeStubs;
4
+ try {
5
+ const stubPath = require.resolve("meteor-node-stubs", { paths: [process.cwd()] });
6
+ meteorNodeStubs = require(stubPath);
7
+ } catch (e) {
8
+ if (e.code !== 'MODULE_NOT_FOUND') throw e;
9
+ try {
10
+ meteorNodeStubs = require("meteor-node-stubs");
11
+ } catch (fallbackError) {
12
+ if (fallbackError.code !== 'MODULE_NOT_FOUND') throw fallbackError;
13
+ // It's optional. If not installed, meteorNodeStubs remains undefined.
14
+ }
15
+ }
16
+
17
+ const TEST_CLIENT_NODE_POLYFILLS = [
18
+ "assert",
19
+ "buffer",
20
+ "constants",
21
+ "crypto",
22
+ "events",
23
+ "fs",
24
+ "http",
25
+ "https",
26
+ "os",
27
+ "path",
28
+ "querystring",
29
+ "stream",
30
+ "string_decoder",
31
+ "sys",
32
+ "timers",
33
+ "tty",
34
+ "url",
35
+ "util",
36
+ "vm",
37
+ "zlib",
38
+ ];
39
+
40
+ function createTestClientNodePolyfillConfig() {
41
+ const fallback = Object.fromEntries(
42
+ TEST_CLIENT_NODE_POLYFILLS.map((name) => [name, meteorNodeStubs?.[name] ?? false]),
43
+ );
44
+
45
+ const plugins = [];
46
+
47
+ if (meteorNodeStubs?.buffer) {
48
+ plugins.push(
49
+ new ProvidePlugin({
50
+ Buffer: [meteorNodeStubs.buffer, "Buffer"],
51
+ })
52
+ );
53
+ }
54
+
55
+ return {
56
+ resolve: {
57
+ alias: {
58
+ "timers/promises$": require.resolve("isomorphic-timers-promises"),
59
+ },
60
+ fallback,
61
+ },
62
+ plugins,
63
+ };
64
+ }
65
+
66
+ module.exports = { createTestClientNodePolyfillConfig };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meteorjs/rspack",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
4
4
  "description": "Configuration logic for using Rspack in Meteor projects",
5
5
  "main": "index.js",
6
6
  "type": "commonjs",
@@ -13,7 +13,7 @@
13
13
  "dependencies": {
14
14
  "fast-deep-equal": "^3.1.3",
15
15
  "ignore-loader": "^0.1.2",
16
- "node-polyfill-webpack-plugin": "^4.1.0",
16
+ "isomorphic-timers-promises": "^1.0.1",
17
17
  "webpack-merge": "^6.0.1"
18
18
  },
19
19
  "devDependencies": {
@@ -22,6 +22,12 @@
22
22
  "peerDependencies": {
23
23
  "@rspack/cli": ">=1.3.0",
24
24
  "@rspack/core": ">=1.3.0",
25
- "@swc/core": ">=1.3.0"
25
+ "@swc/core": ">=1.3.0",
26
+ "meteor-node-stubs": ">=1.2.0"
27
+ },
28
+ "peerDependenciesMeta": {
29
+ "meteor-node-stubs": {
30
+ "optional": true
31
+ }
26
32
  }
27
33
  }
@@ -13,6 +13,18 @@ const path = require('path');
13
13
  // Normalize a path to always use forward slashes (POSIX style).
14
14
  // Module identifiers in bundled JS must use '/' regardless of OS.
15
15
  const toPosix = (p) => p.replace(/\\/g, '/');
16
+ const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
17
+ const buildStandaloneRequireRegex = (pkg) =>
18
+ new RegExp(`^\\s*require\\('${escapeRegExp(pkg)}'\\);?.*(\\r?\\n)?`, 'gm');
19
+ const buildStandaloneImportRegex = (pkg) =>
20
+ new RegExp(
21
+ `^[\\t ]*import[\\t ]+'${escapeRegExp(pkg)}';?[^\\r\\n]*(?:\\r?\\n|$)`,
22
+ 'gm'
23
+ );
24
+ const MANAGED_IMPORT_BLOCK_REGEX =
25
+ /^\/\/\s*\(function\s+(?:eagerExternalImports\d+|lastImports(?:\d+)?)\s*\(\)\s*\{\s*\r?\n[\s\S]*?^\/\/\s*\}\)\s*(?:\r?\n|$)/gm;
26
+ const STANDALONE_REQUIRE_REGEX = /^\s*require\('([^']+)'\)/gm;
27
+ const STANDALONE_IMPORT_REGEX = /^\s*import\s+'([^']+)'/gm;
16
28
 
17
29
  class RequireExternalsPlugin {
18
30
  constructor({
@@ -173,15 +185,22 @@ class RequireExternalsPlugin {
173
185
  }
174
186
  }
175
187
 
176
- // 2b) Remove any requires that are no longer in `current`
188
+ // 2b) Remove any dependencies that are no longer in `current`
177
189
  const toRemove = [...existing].filter(p => !current.has(p));
178
190
  if (toRemove.length) {
179
191
  let content = fs.readFileSync(this.filePath, 'utf-8');
180
192
 
181
- // Strip stale require(...) lines
193
+ // Strip stale requires and imports generated by this plugin. Other
194
+ // standalone imports link Meteor entry and Rspack output files and
195
+ // must remain intact.
182
196
  for (const pkg of toRemove) {
183
- const re = new RegExp(`^.*require\\('${pkg}'\\);?.*(\\r?\\n)?`, 'gm');
184
- content = content.replace(re, '');
197
+ const requireRe = buildStandaloneRequireRegex(pkg);
198
+ const importRe = buildStandaloneImportRegex(pkg);
199
+ content = content.replace(requireRe, '');
200
+ content = content.replace(
201
+ MANAGED_IMPORT_BLOCK_REGEX,
202
+ (block) => block.replace(importRe, '')
203
+ );
185
204
  }
186
205
 
187
206
  // Strip out any now-empty helper functions:
@@ -206,11 +225,11 @@ class RequireExternalsPlugin {
206
225
  // Re-populate `existing` so the add-diff is accurate
207
226
  existing.clear();
208
227
  // Check for require statements
209
- for (const match of content.matchAll(/require\('([^']+)'\)/g)) {
228
+ for (const match of content.matchAll(STANDALONE_REQUIRE_REGEX)) {
210
229
  existing.add(match[1]);
211
230
  }
212
231
  // Also check for import statements (used in the new format)
213
- for (const match of content.matchAll(/import\s+'([^']+)'/g)) {
232
+ for (const match of content.matchAll(STANDALONE_IMPORT_REGEX)) {
214
233
  existing.add(match[1]);
215
234
  }
216
235
  }
@@ -481,15 +500,13 @@ class RequireExternalsPlugin {
481
500
  try {
482
501
  const content = fs.readFileSync(this.filePath, 'utf-8');
483
502
  // Check for require statements
484
- const requireRegex = /require\('([^']+)'\)/g;
485
503
  let match;
486
- while ((match = requireRegex.exec(content)) !== null) {
504
+ while ((match = STANDALONE_REQUIRE_REGEX.exec(content)) !== null) {
487
505
  existing.add(match[1]);
488
506
  }
489
507
 
490
508
  // Also check for import statements (used in the new format)
491
- const importRegex = /import\s+'([^']+)'/g;
492
- while ((match = importRegex.exec(content)) !== null) {
509
+ while ((match = STANDALONE_IMPORT_REGEX.exec(content)) !== null) {
493
510
  existing.add(match[1]);
494
511
  }
495
512
  } catch {
package/rspack.config.js CHANGED
@@ -3,7 +3,6 @@ const fs = require('fs');
3
3
  const { inspect } = require('node:util');
4
4
  const path = require('path');
5
5
  const { merge } = require('webpack-merge');
6
- const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');
7
6
 
8
7
  const { cleanOmittedPaths, mergeSplitOverlap } = require("./lib/mergeRulesSplitOverlap.js");
9
8
  const { getMeteorAppSwcConfig } = require('./lib/swc.js');
@@ -30,7 +29,7 @@ const {
30
29
  const { loadUserAndOverrideConfig } = require('./lib/meteorRspackConfigHelpers.js');
31
30
  const { prepareMeteorRspackConfig } = require("./lib/meteorRspackConfigFactory");
32
31
  const { extractLocalDependencies } = require('./lib/localDependenciesHelpers.js');
33
-
32
+ const { createTestClientNodePolyfillConfig } = require("./lib/testClientNodePolyfills.js");
34
33
 
35
34
  // Safe require that doesn't throw if the module isn't found
36
35
  function safeRequire(moduleName) {
@@ -127,15 +126,13 @@ function createSwcConfig({
127
126
  }) {
128
127
  const defaultConfig = {
129
128
  jsc: {
130
- baseUrl: process.cwd(),
131
- paths: { '/*': ['*', '/*'] },
132
129
  parser: {
133
130
  syntax: isTypescriptEnabled ? 'typescript' : 'ecmascript',
134
131
  ...(isTsxEnabled && { tsx: true }),
135
132
  ...(isJsxEnabled && { jsx: true }),
136
133
  ...(isAngularEnabled && { decorators: true }),
137
134
  },
138
- target: 'es2015',
135
+ target: isClient ? 'es2015' : 'es2022',
139
136
  ...(isReactEnabled && {
140
137
  transform: {
141
138
  react: {
@@ -426,7 +423,7 @@ module.exports = async function (inMeteor = {}, argv = {}) {
426
423
  // Additional ignore entries
427
424
  const additionalEntries = [
428
425
  "**/.meteor/local/**",
429
- "**/dist/**",
426
+ path.join(projectDir, "dist", "**").replace(/\\/g, "/"),
430
427
  ...(isTest && isTestEager
431
428
  ? [`**/${buildContext}/**`, "**/.meteor/local/**", "node_modules/**"]
432
429
  : []),
@@ -650,7 +647,7 @@ module.exports = async function (inMeteor = {}, argv = {}) {
650
647
  ...extraRules,
651
648
  ],
652
649
  },
653
- resolve: { extensions, alias, fallback },
650
+ resolve: { extensions, alias, fallback, roots: [path.resolve(projectDir)] },
654
651
  externals,
655
652
  plugins: [
656
653
  ...[
@@ -774,6 +771,7 @@ module.exports = async function (inMeteor = {}, argv = {}) {
774
771
  alias,
775
772
  modules: ["node_modules", path.resolve(projectDir)],
776
773
  conditionNames: ["import", "require", "node", "default"],
774
+ roots: [path.resolve(projectDir)],
777
775
  },
778
776
  externals,
779
777
  externalsPresets: { node: true },
@@ -841,7 +839,7 @@ module.exports = async function (inMeteor = {}, argv = {}) {
841
839
  optimization: {
842
840
  splitChunks: false,
843
841
  },
844
- plugins: [new NodePolyfillPlugin()],
842
+ ...createTestClientNodePolyfillConfig(),
845
843
  }
846
844
  : {};
847
845
 
@@ -1,10 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Bash(chmod +x:*)",
5
- "Bash(bash:*)",
6
- "Bash(npm install:*)",
7
- "Bash(node:*)"
8
- ]
9
- }
10
- }