@openmrs/rspack-config 10.0.1-pre.5322 → 10.0.1-pre.5364

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/dist/index.js CHANGED
@@ -32,6 +32,9 @@ var __importStar = (this && this.__importStar) || (function () {
32
32
  return result;
33
33
  };
34
34
  })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
35
38
  Object.defineProperty(exports, "__esModule", { value: true });
36
39
  exports.optimizationConfig = exports.watchConfig = exports.assetRuleConfig = exports.scssRuleConfig = exports.cssRuleConfig = exports.scriptRuleConfig = exports.additionalConfig = exports.overrides = void 0;
37
40
  /**
@@ -74,6 +77,9 @@ exports.optimizationConfig = exports.watchConfig = exports.assetRuleConfig = exp
74
77
  */
75
78
  const fs_1 = require("fs");
76
79
  const path_1 = require("path");
80
+ const browserslist_1 = __importDefault(require("browserslist"));
81
+ const node_1 = require("browserslist/node");
82
+ const browserslist_config_openmrs_1 = __importDefault(require("browserslist-config-openmrs"));
77
83
  const clean_webpack_plugin_1 = require("clean-webpack-plugin");
78
84
  const ts_checker_rspack_plugin_1 = require("ts-checker-rspack-plugin");
79
85
  // eslint-disable-next-line no-restricted-imports
@@ -127,6 +133,79 @@ function getFrameworkVersion() {
127
133
  return '5.x';
128
134
  }
129
135
  }
136
+ /**
137
+ * The browserslist queries swc compiles this module against, falling back to OpenMRS's shared config
138
+ * when the module declares none, so that frontend RFC 0003 stays the single source of truth. Given no
139
+ * target at all swc down-levels to ES5, and every supported browser pays for transform helpers it
140
+ * doesn't need.
141
+ *
142
+ * `@openmrs/webpack-config` has a copy of this; keep them in step. `browser-targets.test.ts` compares
143
+ * what the two hand their loaders and fails if they drift.
144
+ *
145
+ * @param root The directory of the module being built
146
+ */
147
+ function browserslistQueries(root) {
148
+ var _a, _b;
149
+ const warnings = [];
150
+ // deliberately unguarded
151
+ const loaded = browserslist_1.default.loadConfig({ path: root });
152
+ const configured = loaded === undefined ? [] : Array.isArray(loaded) ? loaded : [loaded];
153
+ if (loaded !== undefined && configured.length === 0) {
154
+ // warn when a browserlist config is empty
155
+ warnings.push(`This module declares a browserslist config, but it resolves to no queries for the ` +
156
+ `${(_b = (_a = process.env.BROWSERSLIST_ENV) !== null && _a !== void 0 ? _a : process.env.NODE_ENV) !== null && _b !== void 0 ? _b : production} environment. ` +
157
+ `Targeting ${browserslist_config_openmrs_1.default.join(', ')} instead.`);
158
+ }
159
+ const expanded = expandBrowserslistExtends(configured.length > 0 ? configured : browserslist_config_openmrs_1.default, root, warnings);
160
+ return { queries: expanded.length > 0 ? expanded : browserslist_config_openmrs_1.default, warnings };
161
+ }
162
+ function expandBrowserslistExtends(queries, root, warnings, seen = new Set()) {
163
+ // Split on commas because a browserslist config may be a single string of them
164
+ return queries.flatMap((query) => query
165
+ .split(',')
166
+ .flatMap((part) => {
167
+ const extended = /^extends\s+(.+)$/i.exec(part.trim());
168
+ if (!extended) {
169
+ return [part.trim()];
170
+ }
171
+ const name = extended[1].trim();
172
+ if (seen.has(name)) {
173
+ return [];
174
+ }
175
+ seen.add(name);
176
+ try {
177
+ // browserslist's own loader, rather than a bare `require` so we handle the same syntax
178
+ const resolved = (0, node_1.loadQueries)({ path: root }, name);
179
+ return expandBrowserslistExtends(Array.isArray(resolved) ? resolved : [resolved], root, warnings, seen);
180
+ }
181
+ catch (err) {
182
+ // Only browserslist's own verdict on a named config is survivable: not installed, or refused
183
+ // for its name.
184
+ const notInstalled = (err === null || err === void 0 ? void 0 : err.code) === 'MODULE_NOT_FOUND';
185
+ const refused = (err === null || err === void 0 ? void 0 : err.browserslist) === true;
186
+ if (!notInstalled && !refused) {
187
+ throw err;
188
+ }
189
+ warnings.push(`Could not load the browserslist config "${name}" (${err.message}). ` +
190
+ `Targeting ${browserslist_config_openmrs_1.default.join(', ')} instead.`);
191
+ return browserslist_config_openmrs_1.default;
192
+ }
193
+ })
194
+ .filter((part) => part.length > 0));
195
+ }
196
+ /** Reports how a module's browsers were worked out, where a developer will actually see it. */
197
+ class BrowserslistWarningsPlugin {
198
+ constructor(messages) {
199
+ this.messages = messages;
200
+ }
201
+ apply(compiler) {
202
+ compiler.hooks.thisCompilation.tap('OpenmrsBrowserslistWarnings', (compilation) => {
203
+ for (const message of this.messages) {
204
+ compilation.warnings.push(new core_1.default.WebpackError(message));
205
+ }
206
+ });
207
+ }
208
+ }
130
209
  function makeIdent(name) {
131
210
  if (name.includes('/')) {
132
211
  name = name.slice(name.indexOf('/'));
@@ -207,6 +286,7 @@ exports.default = (env, argv = {}) => {
207
286
  const outDir = (0, path_1.dirname)(browser || main);
208
287
  const srcFile = (0, path_1.resolve)(root, browser ? main : types);
209
288
  const ident = makeIdent(name);
289
+ const { queries: browserTargets, warnings: browserslistWarnings } = browserslistQueries(root);
210
290
  const frameworkVersion = getFrameworkVersion();
211
291
  const routes = (0, path_1.resolve)(root, 'src', 'routes.json');
212
292
  const hasRoutesDefined = fileExistsSync(routes);
@@ -240,6 +320,9 @@ exports.default = (env, argv = {}) => {
240
320
  exclude: /node_modules/,
241
321
  loader: 'builtin:swc-loader',
242
322
  options: {
323
+ env: {
324
+ targets: browserTargets,
325
+ },
243
326
  jsc: {
244
327
  parser: {
245
328
  syntax: 'typescript',
@@ -276,7 +359,9 @@ exports.default = (env, argv = {}) => {
276
359
  type: 'asset/source',
277
360
  },
278
361
  ],
279
- }, mode, devtool: mode === production ? 'hidden-nosources-source-map' : 'source-map', devServer: {
362
+ }, mode,
363
+ // governs rspack's own runtime and chunk-loading glue
364
+ target: ['web', `browserslist:${browserTargets.join(', ')}`], devtool: mode === production ? 'hidden-nosources-source-map' : 'source-map', devServer: {
280
365
  headers: {
281
366
  'Access-Control-Allow-Origin': '*',
282
367
  },
@@ -294,6 +379,7 @@ exports.default = (env, argv = {}) => {
294
379
  },
295
380
  minimizer: [new core_1.default.SwcJsMinimizerRspackPlugin(), new core_1.default.LightningCssMinimizerRspackPlugin()],
296
381
  }, exports.optimizationConfig), plugins: [
382
+ browserslistWarnings.length > 0 && new BrowserslistWarningsPlugin(browserslistWarnings),
297
383
  new ts_checker_rspack_plugin_1.TsCheckerRspackPlugin(),
298
384
  new clean_webpack_plugin_1.CleanWebpackPlugin(),
299
385
  new webpack_bundle_analyzer_1.BundleAnalyzerPlugin({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openmrs/rspack-config",
3
- "version": "10.0.1-pre.5322",
3
+ "version": "10.0.1-pre.5364",
4
4
  "license": "MPL-2.0",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -35,6 +35,8 @@
35
35
  "@rspack/cli": "1.7.9",
36
36
  "@rspack/core": "1.7.9",
37
37
  "@swc/core": "1.15.21",
38
+ "browserslist": "4.28.9",
39
+ "browserslist-config-openmrs": "^1.0.1",
38
40
  "clean-webpack-plugin": "4.0.0",
39
41
  "copy-webpack-plugin": "11.0.0",
40
42
  "css-loader": "5.2.7",
package/src/index.ts CHANGED
@@ -38,6 +38,9 @@
38
38
  */
39
39
  import { existsSync, statSync } from 'fs';
40
40
  import { basename, dirname, resolve } from 'path';
41
+ import browserslist from 'browserslist';
42
+ import { loadQueries } from 'browserslist/node';
43
+ import defaultBrowserslistQueries from 'browserslist-config-openmrs';
41
44
  import { CleanWebpackPlugin } from 'clean-webpack-plugin';
42
45
  import { TsCheckerRspackPlugin } from 'ts-checker-rspack-plugin';
43
46
  // eslint-disable-next-line no-restricted-imports
@@ -45,6 +48,7 @@ import { isArray, merge, mergeWith } from 'lodash';
45
48
  import { inc, parse } from 'semver';
46
49
  import { ModuleFederationPlugin } from '@module-federation/enhanced/rspack';
47
50
  import rspack, {
51
+ type Compiler,
48
52
  CopyRspackPlugin,
49
53
  DefinePlugin,
50
54
  type ModuleOptions,
@@ -108,6 +112,109 @@ function getFrameworkVersion() {
108
112
  }
109
113
  }
110
114
 
115
+ /** What a module's browsers resolved to, plus anything worth telling the developer about getting there. */
116
+ type BrowserPolicy = { queries: Array<string>; warnings: Array<string> };
117
+
118
+ /**
119
+ * The browserslist queries swc compiles this module against, falling back to OpenMRS's shared config
120
+ * when the module declares none, so that frontend RFC 0003 stays the single source of truth. Given no
121
+ * target at all swc down-levels to ES5, and every supported browser pays for transform helpers it
122
+ * doesn't need.
123
+ *
124
+ * `@openmrs/webpack-config` has a copy of this; keep them in step. `browser-targets.test.ts` compares
125
+ * what the two hand their loaders and fails if they drift.
126
+ *
127
+ * @param root The directory of the module being built
128
+ */
129
+ function browserslistQueries(root: string): BrowserPolicy {
130
+ const warnings: Array<string> = [];
131
+ // deliberately unguarded
132
+ const loaded = browserslist.loadConfig({ path: root });
133
+ const configured = loaded === undefined ? [] : Array.isArray(loaded) ? loaded : [loaded];
134
+
135
+ if (loaded !== undefined && configured.length === 0) {
136
+ // warn when a browserlist config is empty
137
+ warnings.push(
138
+ `This module declares a browserslist config, but it resolves to no queries for the ` +
139
+ `${process.env.BROWSERSLIST_ENV ?? process.env.NODE_ENV ?? production} environment. ` +
140
+ `Targeting ${defaultBrowserslistQueries.join(', ')} instead.`,
141
+ );
142
+ }
143
+
144
+ const expanded = expandBrowserslistExtends(
145
+ configured.length > 0 ? configured : defaultBrowserslistQueries,
146
+ root,
147
+ warnings,
148
+ );
149
+
150
+ return { queries: expanded.length > 0 ? expanded : defaultBrowserslistQueries, warnings };
151
+ }
152
+
153
+ function expandBrowserslistExtends(
154
+ queries: Array<string>,
155
+ root: string,
156
+ warnings: Array<string>,
157
+ seen = new Set<string>(),
158
+ ): Array<string> {
159
+ // Split on commas because a browserslist config may be a single string of them
160
+ return queries.flatMap((query) =>
161
+ query
162
+ .split(',')
163
+ .flatMap((part) => {
164
+ const extended = /^extends\s+(.+)$/i.exec(part.trim());
165
+
166
+ if (!extended) {
167
+ return [part.trim()];
168
+ }
169
+
170
+ const name = extended[1].trim();
171
+
172
+ if (seen.has(name)) {
173
+ return [];
174
+ }
175
+
176
+ seen.add(name);
177
+
178
+ try {
179
+ // browserslist's own loader, rather than a bare `require` so we handle the same syntax
180
+ const resolved = loadQueries({ path: root }, name);
181
+
182
+ return expandBrowserslistExtends(Array.isArray(resolved) ? resolved : [resolved], root, warnings, seen);
183
+ } catch (err) {
184
+ // Only browserslist's own verdict on a named config is survivable: not installed, or refused
185
+ // for its name.
186
+ const notInstalled = (err as { code?: string })?.code === 'MODULE_NOT_FOUND';
187
+ const refused = (err as { browserslist?: boolean })?.browserslist === true;
188
+
189
+ if (!notInstalled && !refused) {
190
+ throw err;
191
+ }
192
+
193
+ warnings.push(
194
+ `Could not load the browserslist config "${name}" (${(err as Error).message}). ` +
195
+ `Targeting ${defaultBrowserslistQueries.join(', ')} instead.`,
196
+ );
197
+
198
+ return defaultBrowserslistQueries;
199
+ }
200
+ })
201
+ .filter((part) => part.length > 0),
202
+ );
203
+ }
204
+
205
+ /** Reports how a module's browsers were worked out, where a developer will actually see it. */
206
+ class BrowserslistWarningsPlugin {
207
+ constructor(private readonly messages: Array<string>) {}
208
+
209
+ apply(compiler: Compiler) {
210
+ compiler.hooks.thisCompilation.tap('OpenmrsBrowserslistWarnings', (compilation) => {
211
+ for (const message of this.messages) {
212
+ compilation.warnings.push(new rspack.WebpackError(message));
213
+ }
214
+ });
215
+ }
216
+ }
217
+
111
218
  function makeIdent(name: string): string {
112
219
  if (name.includes('/')) {
113
220
  name = name.slice(name.indexOf('/'));
@@ -200,6 +307,7 @@ export default (env: Record<string, string>, argv: Record<string, string> = {})
200
307
  const outDir = dirname(browser || main);
201
308
  const srcFile = resolve(root, browser ? main : types);
202
309
  const ident = makeIdent(name);
310
+ const { queries: browserTargets, warnings: browserslistWarnings } = browserslistQueries(root);
203
311
  const frameworkVersion = getFrameworkVersion();
204
312
  const routes = resolve(root, 'src', 'routes.json');
205
313
  const hasRoutesDefined = fileExistsSync(routes);
@@ -240,6 +348,9 @@ export default (env: Record<string, string>, argv: Record<string, string> = {})
240
348
  exclude: /node_modules/,
241
349
  loader: 'builtin:swc-loader',
242
350
  options: {
351
+ env: {
352
+ targets: browserTargets,
353
+ },
243
354
  jsc: {
244
355
  parser: {
245
356
  syntax: 'typescript',
@@ -289,6 +400,8 @@ export default (env: Record<string, string>, argv: Record<string, string> = {})
289
400
  ],
290
401
  },
291
402
  mode,
403
+ // governs rspack's own runtime and chunk-loading glue
404
+ target: ['web', `browserslist:${browserTargets.join(', ')}`],
292
405
  devtool: mode === production ? 'hidden-nosources-source-map' : 'source-map',
293
406
  devServer: {
294
407
  headers: {
@@ -318,6 +431,7 @@ export default (env: Record<string, string>, argv: Record<string, string> = {})
318
431
  optimizationConfig,
319
432
  ),
320
433
  plugins: [
434
+ browserslistWarnings.length > 0 && new BrowserslistWarningsPlugin(browserslistWarnings),
321
435
  new TsCheckerRspackPlugin(),
322
436
  new CleanWebpackPlugin(),
323
437
  new BundleAnalyzerPlugin({