@meteorjs/rspack 0.0.19 → 0.0.21

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
@@ -5,6 +5,7 @@ import {
5
5
  defineConfig as _rspackDefineConfig,
6
6
  Configuration as _RspackConfig,
7
7
  } from '@rspack/cli';
8
+ import { HtmlRspackPluginOptions } from '@rspack/core';
8
9
 
9
10
  export interface MeteorRspackConfig extends _RspackConfig {
10
11
  meteor?: {
@@ -34,3 +35,15 @@ export type ConfigFactory = (
34
35
  export function defineConfig(
35
36
  factory: ConfigFactory
36
37
  ): ReturnType<typeof _rspackDefineConfig>;
38
+
39
+ /**
40
+ * A plugin that composes the original HtmlRspackPlugin from @rspack/core
41
+ * and RspackMeteorHtmlPlugin, in that order.
42
+ */
43
+ export class HtmlRspackPlugin {
44
+ constructor(options?: HtmlRspackPluginOptions);
45
+ apply(compiler: any): void;
46
+ }
47
+
48
+ // Re-export HtmlRspackPluginOptions from @rspack/cli
49
+ export { HtmlRspackPluginOptions };
package/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { defineConfig as rspackDefineConfig } from '@rspack/cli';
2
+ import HtmlRspackPlugin from './plugins/HtmlRspackPlugin.js';
2
3
 
3
4
  /**
4
5
  * @typedef {import('rspack').Configuration & {
@@ -21,3 +22,6 @@ export function defineConfig(factory) {
21
22
 
22
23
  // Export our helper plus passthrough
23
24
  export default defineConfig;
25
+
26
+ // Export the HtmlRspackPlugin
27
+ export { HtmlRspackPlugin };
@@ -122,6 +122,57 @@ function splitOverlapRulesMerge(aRules, bRules) {
122
122
  return result;
123
123
  }
124
124
 
125
+ /**
126
+ * Creates a customizer function for unique plugins.
127
+ *
128
+ * @param {string} key - The key to check for uniqueness
129
+ * @param {string[]} pluginNames - Array of plugin constructor names to make unique
130
+ * @param {Function} getter - Function to get the identifier from the plugin
131
+ * @returns {Function} Customizer function
132
+ */
133
+ export function unique(key, pluginNames = [], getter = item => item.constructor && item.constructor.name) {
134
+ return (a, b, k) => {
135
+ if (k !== key) return undefined;
136
+
137
+ const aItems = Array.isArray(a) ? a : [];
138
+ const bItems = Array.isArray(b) ? b : [];
139
+
140
+ // If not dealing with plugins, return undefined to use default merging
141
+ if (key !== 'plugins') return undefined;
142
+
143
+ // Create a map to track plugins by their identifier
144
+ const uniquePlugins = new Map();
145
+
146
+ // Process all plugins from both arrays
147
+ [...aItems, ...bItems].forEach(plugin => {
148
+ const id = getter(plugin);
149
+
150
+ // If this is a plugin we want to make unique and we can identify it
151
+ if (id && pluginNames.includes(id)) {
152
+ uniquePlugins.set(id, plugin); // Keep only the last instance
153
+ }
154
+ });
155
+
156
+ // Create the result array with all non-unique plugins from a
157
+ const result = aItems.filter(plugin => {
158
+ const id = getter(plugin);
159
+ return !id || !pluginNames.includes(id) || uniquePlugins.get(id) === plugin;
160
+ });
161
+
162
+ // Add unique plugins from b that weren't already in the result
163
+ bItems.forEach(plugin => {
164
+ const id = getter(plugin);
165
+ if (!id || !pluginNames.includes(id)) {
166
+ result.push(plugin);
167
+ } else if (uniquePlugins.get(id) === plugin) {
168
+ result.push(plugin);
169
+ }
170
+ });
171
+
172
+ return result;
173
+ };
174
+ }
175
+
125
176
  /**
126
177
  * Merges webpack/rspack configs with smart handling of overlapping rules.
127
178
  *
@@ -136,6 +187,16 @@ export function mergeSplitOverlap(...configs) {
136
187
  const bRules = Array.isArray(b) ? b : [];
137
188
  return splitOverlapRulesMerge(aRules, bRules);
138
189
  }
190
+
191
+ // Handle plugins uniqueness
192
+ if (key === 'plugins') {
193
+ return unique(
194
+ 'plugins',
195
+ ['HtmlRspackPlugin'],
196
+ (plugin) => plugin.constructor && plugin.constructor.name
197
+ )(a, b, key);
198
+ }
199
+
139
200
  // fall through to default merging
140
201
  return undefined;
141
202
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meteorjs/rspack",
3
- "version": "0.0.19",
3
+ "version": "0.0.21",
4
4
  "description": "Configuration logic for using Rspack in Meteor projects",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -0,0 +1,28 @@
1
+ import RspackMeteorHtmlPlugin, { loadHtmlRspackPluginFromHost } from './RspackMeteorHtmlPlugin.js';
2
+
3
+ /**
4
+ * A plugin that composes the original HtmlRspackPlugin from @rspack/core
5
+ * and RspackMeteorHtmlPlugin, in that order.
6
+ */
7
+ export default class HtmlRspackPlugin {
8
+ constructor(options = {}) {
9
+ this.options = options;
10
+ }
11
+
12
+ apply(compiler) {
13
+ // Load the original HtmlRspackPlugin from the host project
14
+ const OriginalHtmlRspackPlugin = loadHtmlRspackPluginFromHost(compiler);
15
+
16
+ if (!OriginalHtmlRspackPlugin) {
17
+ throw new Error('Could not load HtmlRspackPlugin from host project.');
18
+ }
19
+
20
+ // Apply the original HtmlRspackPlugin
21
+ const originalPlugin = new OriginalHtmlRspackPlugin(this.options);
22
+ originalPlugin.apply(compiler);
23
+
24
+ // Apply the RspackMeteorHtmlPlugin
25
+ const meteorPlugin = new RspackMeteorHtmlPlugin();
26
+ meteorPlugin.apply(compiler);
27
+ }
28
+ }
@@ -1,7 +1,7 @@
1
1
  import path from 'node:path';
2
2
  import { createRequire } from 'node:module';
3
3
 
4
- function loadHtmlRspackPluginFromHost(compiler) {
4
+ export function loadHtmlRspackPluginFromHost(compiler) {
5
5
  // Prefer the compiler's context; fall back to process.cwd()
6
6
  const ctx = compiler.options?.context || compiler.context || process.cwd();
7
7
  const requireFromHost = createRequire(path.join(ctx, 'package.json'));
package/rspack.config.js CHANGED
@@ -1,4 +1,4 @@
1
- import { DefinePlugin, BannerPlugin, HtmlRspackPlugin } from '@rspack/core';
1
+ import { DefinePlugin, BannerPlugin } from '@rspack/core';
2
2
  import fs from 'fs';
3
3
  import { createRequire } from 'module';
4
4
  import path from 'path';
@@ -9,7 +9,7 @@ import { RequireExternalsPlugin } from './plugins/RequireExtenalsPlugin.js';
9
9
  import { getMeteorAppSwcConfig } from "./lib/swc.js";
10
10
  import { mergeSplitOverlap } from './lib/mergeRulesSplitOverlap.js';
11
11
  import CleanBuildAssetsPlugin from "./plugins/CleanBuildAssetsPlugin.js";
12
- import RspackMeteorHtmlPlugin from "./plugins/RspackMeteorHtmlPlugin.js";
12
+ import HtmlRspackPlugin from './plugins/HtmlRspackPlugin.js';
13
13
 
14
14
  const require = createRequire(import.meta.url);
15
15
 
@@ -139,6 +139,7 @@ export default function (inMeteor = {}, argv = {}) {
139
139
  // Determine output points
140
140
  const outputPath = Meteor.outputPath;
141
141
  const outputDir = path.dirname(Meteor.outputPath || '');
142
+
142
143
  const outputFilename = Meteor.outputFilename;
143
144
 
144
145
  // Determine run point
@@ -156,6 +157,10 @@ export default function (inMeteor = {}, argv = {}) {
156
157
  const bundlesContext = Meteor.bundlesContext || 'bundles';
157
158
  const assetsContext = Meteor.assetsContext || 'assets';
158
159
 
160
+ // Determine build output and pass to Meteor
161
+ const buildOutputDir = path.resolve(process.cwd(), buildContext, outputDir);
162
+ Meteor.buildOutputDir = buildOutputDir;
163
+
159
164
  // Set watch options
160
165
  const watchOptions = {
161
166
  ...defaultWatchOptions,
@@ -303,7 +308,6 @@ export default function (inMeteor = {}, argv = {}) {
303
308
  </body>
304
309
  `,
305
310
  }),
306
- new RspackMeteorHtmlPlugin(),
307
311
  ],
308
312
  watchOptions,
309
313
  devtool: isDevEnvironment || isTest ? 'source-map' : 'hidden-source-map',