@openmrs/webpack-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 +133 -8
- package/package.json +3 -1
- package/src/index.ts +168 -2
package/dist/index.js
CHANGED
|
@@ -44,16 +44,21 @@ exports.optimizationConfig = exports.watchConfig = exports.assetRuleConfig = exp
|
|
|
44
44
|
*/
|
|
45
45
|
const fs_1 = require("fs");
|
|
46
46
|
const path_1 = require("path");
|
|
47
|
+
const browserslist_1 = __importDefault(require("browserslist"));
|
|
48
|
+
const node_1 = require("browserslist/node");
|
|
49
|
+
const browserslist_config_openmrs_1 = __importDefault(require("browserslist-config-openmrs"));
|
|
47
50
|
const clean_webpack_plugin_1 = require("clean-webpack-plugin");
|
|
48
51
|
const copy_webpack_plugin_1 = __importDefault(require("copy-webpack-plugin"));
|
|
49
52
|
const fork_ts_checker_webpack_plugin_1 = __importDefault(require("fork-ts-checker-webpack-plugin"));
|
|
50
53
|
// eslint-disable-next-line no-restricted-imports
|
|
51
54
|
const lodash_1 = require("lodash");
|
|
52
55
|
const semver_1 = require("semver");
|
|
53
|
-
const webpack_1 = require("
|
|
54
|
-
|
|
56
|
+
const webpack_1 = require("webpack");
|
|
57
|
+
// webpack's own browsers-to-features mapping
|
|
58
|
+
const browserslistTargetHandler_1 = __importDefault(require("webpack/lib/config/browserslistTargetHandler"));
|
|
55
59
|
const webpack_bundle_analyzer_1 = require("webpack-bundle-analyzer");
|
|
56
60
|
const webpack_stats_plugin_1 = require("webpack-stats-plugin");
|
|
61
|
+
const webpack_2 = require("@module-federation/enhanced/webpack");
|
|
57
62
|
const production = 'production';
|
|
58
63
|
// Read from our own pin rather than `@module-federation/enhanced/package.json`, which its `exports` map
|
|
59
64
|
// makes unreadable. `parse` rather than `coerce`, so that loosening the pin to a range disables the skew
|
|
@@ -61,6 +66,25 @@ const production = 'production';
|
|
|
61
66
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
62
67
|
const moduleFederationPin = require('../package.json').dependencies['@module-federation/enhanced'];
|
|
63
68
|
const moduleFederationVersion = (0, semver_1.parse)(moduleFederationPin);
|
|
69
|
+
// The subset of what `browserslistTargetHandler.resolve` reports that `output.environment` accepts;
|
|
70
|
+
// the rest describe the platform and available APIs, and webpack's schema rejects them here.
|
|
71
|
+
const environmentFlags = [
|
|
72
|
+
'arrowFunction',
|
|
73
|
+
'asyncFunction',
|
|
74
|
+
'bigIntLiteral',
|
|
75
|
+
'const',
|
|
76
|
+
'destructuring',
|
|
77
|
+
'document',
|
|
78
|
+
'dynamicImport',
|
|
79
|
+
'dynamicImportInWorker',
|
|
80
|
+
'forOf',
|
|
81
|
+
'globalThis',
|
|
82
|
+
'importMetaDirnameAndFilename',
|
|
83
|
+
'methodShorthand',
|
|
84
|
+
'module',
|
|
85
|
+
'optionalChaining',
|
|
86
|
+
'templateLiteral',
|
|
87
|
+
];
|
|
64
88
|
/**
|
|
65
89
|
* Prepended to this app's entry chunks. Without it, an app running under an app shell too old to
|
|
66
90
|
* publish the runtime globals fails with a `TypeError` from inside minified runtime code. All three
|
|
@@ -98,6 +122,95 @@ function getFrameworkVersion() {
|
|
|
98
122
|
return '5.x';
|
|
99
123
|
}
|
|
100
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* The browserslist queries swc compiles this module against, falling back to OpenMRS's shared config
|
|
127
|
+
* when the module declares none, so that frontend RFC 0003 stays the single source of truth. Given no
|
|
128
|
+
* target at all swc down-levels to ES5, and every supported browser pays for transform helpers it
|
|
129
|
+
* doesn't need.
|
|
130
|
+
*
|
|
131
|
+
* `@openmrs/rspack-config` has a copy of this; keep them in step. `browser-targets.test.ts` compares
|
|
132
|
+
* what the two hand their loaders and fails if they drift.
|
|
133
|
+
*
|
|
134
|
+
* @param root The directory of the module being built
|
|
135
|
+
*/
|
|
136
|
+
function browserslistQueries(root) {
|
|
137
|
+
var _a, _b;
|
|
138
|
+
const warnings = [];
|
|
139
|
+
// deliberately unguarded
|
|
140
|
+
const loaded = browserslist_1.default.loadConfig({ path: root });
|
|
141
|
+
const configured = loaded === undefined ? [] : Array.isArray(loaded) ? loaded : [loaded];
|
|
142
|
+
if (loaded !== undefined && configured.length === 0) {
|
|
143
|
+
// warn when a browserlist config is empty
|
|
144
|
+
warnings.push(`This module declares a browserslist config, but it resolves to no queries for the ` +
|
|
145
|
+
`${(_b = (_a = process.env.BROWSERSLIST_ENV) !== null && _a !== void 0 ? _a : process.env.NODE_ENV) !== null && _b !== void 0 ? _b : production} environment. ` +
|
|
146
|
+
`Targeting ${browserslist_config_openmrs_1.default.join(', ')} instead.`);
|
|
147
|
+
}
|
|
148
|
+
const expanded = expandBrowserslistExtends(configured.length > 0 ? configured : browserslist_config_openmrs_1.default, root, warnings);
|
|
149
|
+
return { queries: expanded.length > 0 ? expanded : browserslist_config_openmrs_1.default, warnings };
|
|
150
|
+
}
|
|
151
|
+
function expandBrowserslistExtends(queries, root, warnings, seen = new Set()) {
|
|
152
|
+
// Split on commas because a browserslist config may be a single string of them
|
|
153
|
+
return queries.flatMap((query) => query
|
|
154
|
+
.split(',')
|
|
155
|
+
.flatMap((part) => {
|
|
156
|
+
const extended = /^extends\s+(.+)$/i.exec(part.trim());
|
|
157
|
+
if (!extended) {
|
|
158
|
+
return [part.trim()];
|
|
159
|
+
}
|
|
160
|
+
const name = extended[1].trim();
|
|
161
|
+
if (seen.has(name)) {
|
|
162
|
+
return [];
|
|
163
|
+
}
|
|
164
|
+
seen.add(name);
|
|
165
|
+
try {
|
|
166
|
+
// browserslist's own loader, rather than a bare `require` so we handle the same syntax
|
|
167
|
+
const resolved = (0, node_1.loadQueries)({ path: root }, name);
|
|
168
|
+
return expandBrowserslistExtends(Array.isArray(resolved) ? resolved : [resolved], root, warnings, seen);
|
|
169
|
+
}
|
|
170
|
+
catch (err) {
|
|
171
|
+
// Only browserslist's own verdict on a named config is survivable: not installed, or refused
|
|
172
|
+
// for its name.
|
|
173
|
+
const notInstalled = (err === null || err === void 0 ? void 0 : err.code) === 'MODULE_NOT_FOUND';
|
|
174
|
+
const refused = (err === null || err === void 0 ? void 0 : err.browserslist) === true;
|
|
175
|
+
if (!notInstalled && !refused) {
|
|
176
|
+
throw err;
|
|
177
|
+
}
|
|
178
|
+
warnings.push(`Could not load the browserslist config "${name}" (${err.message}). ` +
|
|
179
|
+
`Targeting ${browserslist_config_openmrs_1.default.join(', ')} instead.`);
|
|
180
|
+
return browserslist_config_openmrs_1.default;
|
|
181
|
+
}
|
|
182
|
+
})
|
|
183
|
+
.filter((part) => part.length > 0));
|
|
184
|
+
}
|
|
185
|
+
/** Reports how a module's browsers were worked out, where a developer will actually see it. */
|
|
186
|
+
class BrowserslistWarningsPlugin {
|
|
187
|
+
constructor(messages) {
|
|
188
|
+
this.messages = messages;
|
|
189
|
+
}
|
|
190
|
+
apply(compiler) {
|
|
191
|
+
compiler.hooks.thisCompilation.tap('OpenmrsBrowserslistWarnings', (compilation) => {
|
|
192
|
+
for (const message of this.messages) {
|
|
193
|
+
compilation.warnings.push(new webpack_1.WebpackError(message));
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* The `output.environment` flags for a set of browserslist queries: which JavaScript features webpack
|
|
200
|
+
* may use in the runtime it generates.
|
|
201
|
+
*
|
|
202
|
+
* Derived with webpack's own browserslist target handler, so the browsers-to-features mapping is the
|
|
203
|
+
* caniuse-backed one webpack uses for `target: 'browserslist'` rather than a table maintained here.
|
|
204
|
+
* `resolve` also reports platform and API properties that `output.environment` rejects, hence the
|
|
205
|
+
* filter to the flags webpack's schema accepts.
|
|
206
|
+
*
|
|
207
|
+
* @param queries Browserslist queries, already `extends`-expanded
|
|
208
|
+
* @param root The directory of the module being built, for resolving relative queries
|
|
209
|
+
*/
|
|
210
|
+
function browserEnvironment(queries, root) {
|
|
211
|
+
const supported = browserslistTargetHandler_1.default.resolve((0, browserslist_1.default)(queries, { path: root }));
|
|
212
|
+
return Object.fromEntries(environmentFlags.filter((flag) => typeof supported[flag] === 'boolean').map((flag) => [flag, supported[flag]]));
|
|
213
|
+
}
|
|
101
214
|
function makeIdent(name) {
|
|
102
215
|
if (name.includes('/')) {
|
|
103
216
|
name = name.slice(name.indexOf('/'));
|
|
@@ -176,6 +289,7 @@ exports.default = (env, argv = {}) => {
|
|
|
176
289
|
const outDir = (0, path_1.dirname)(browser || main);
|
|
177
290
|
const srcFile = (0, path_1.resolve)(root, browser ? main : types);
|
|
178
291
|
const ident = makeIdent(name);
|
|
292
|
+
const { queries: browserTargets, warnings: browserslistWarnings } = browserslistQueries(root);
|
|
179
293
|
const frameworkVersion = getFrameworkVersion();
|
|
180
294
|
const routes = (0, path_1.resolve)(root, 'src', 'routes.json');
|
|
181
295
|
const hasRoutesDefined = fileExistsSync(routes);
|
|
@@ -202,12 +316,22 @@ exports.default = (env, argv = {}) => {
|
|
|
202
316
|
publicPath: 'auto',
|
|
203
317
|
path: (0, path_1.resolve)(root, outDir),
|
|
204
318
|
hashFunction: 'xxhash64',
|
|
319
|
+
environment: browserEnvironment(browserTargets, root),
|
|
205
320
|
}, module: {
|
|
206
321
|
rules: [
|
|
207
322
|
(0, lodash_1.merge)({
|
|
208
323
|
test: /\.m?(js|ts|tsx)$/,
|
|
209
324
|
exclude: /node_modules/,
|
|
210
|
-
use:
|
|
325
|
+
use: {
|
|
326
|
+
loader: require.resolve('swc-loader'),
|
|
327
|
+
options: {
|
|
328
|
+
env: {
|
|
329
|
+
targets: browserTargets,
|
|
330
|
+
},
|
|
331
|
+
// ignore a project .swcrc to match rspack behavior
|
|
332
|
+
swcrc: false,
|
|
333
|
+
},
|
|
334
|
+
},
|
|
211
335
|
}, exports.scriptRuleConfig),
|
|
212
336
|
(0, lodash_1.merge)({
|
|
213
337
|
test: /\.css$/,
|
|
@@ -237,7 +361,7 @@ exports.default = (env, argv = {}) => {
|
|
|
237
361
|
type: 'asset/source',
|
|
238
362
|
}),
|
|
239
363
|
],
|
|
240
|
-
}, mode, devtool: mode === production ? 'hidden-nosources-source-map' : 'source-map', devServer: {
|
|
364
|
+
}, mode, target: 'web', devtool: mode === production ? 'hidden-nosources-source-map' : 'source-map', devServer: {
|
|
241
365
|
headers: {
|
|
242
366
|
'Access-Control-Allow-Origin': '*',
|
|
243
367
|
},
|
|
@@ -257,6 +381,7 @@ exports.default = (env, argv = {}) => {
|
|
|
257
381
|
maxInitialRequests: 1,
|
|
258
382
|
},
|
|
259
383
|
}, exports.optimizationConfig), plugins: [
|
|
384
|
+
browserslistWarnings.length > 0 && new BrowserslistWarningsPlugin(browserslistWarnings),
|
|
260
385
|
new fork_ts_checker_webpack_plugin_1.default({
|
|
261
386
|
issue: {
|
|
262
387
|
exclude: [
|
|
@@ -271,10 +396,10 @@ exports.default = (env, argv = {}) => {
|
|
|
271
396
|
new webpack_bundle_analyzer_1.BundleAnalyzerPlugin({
|
|
272
397
|
analyzerMode: env && env.analyze ? 'server' : 'disabled',
|
|
273
398
|
}),
|
|
274
|
-
new
|
|
399
|
+
new webpack_1.DefinePlugin({
|
|
275
400
|
'process.env.FRAMEWORK_VERSION': JSON.stringify(frameworkVersion),
|
|
276
401
|
}),
|
|
277
|
-
new
|
|
402
|
+
new webpack_2.ModuleFederationPlugin({
|
|
278
403
|
// Look in the `esm-dynamic-loading` framework package for an explanation of how modules
|
|
279
404
|
// get loaded into the application.
|
|
280
405
|
name,
|
|
@@ -336,11 +461,11 @@ exports.default = (env, argv = {}) => {
|
|
|
336
461
|
// The two runtime packages a remote can safely borrow from the app shell; see the
|
|
337
462
|
// `ExternalsPlugin` block in `@openmrs/rspack-config` for why only these two are shareable,
|
|
338
463
|
// what still ships per remote, and why this is a plugin rather than an `externals` entry.
|
|
339
|
-
new
|
|
464
|
+
new webpack_1.ExternalsPlugin('global', {
|
|
340
465
|
'@module-federation/sdk': '_OPENMRS_FEDERATION_SDK',
|
|
341
466
|
'@module-federation/error-codes': '_OPENMRS_FEDERATION_ERROR_CODES',
|
|
342
467
|
}),
|
|
343
|
-
new
|
|
468
|
+
new webpack_1.BannerPlugin({
|
|
344
469
|
raw: true,
|
|
345
470
|
entryOnly: true,
|
|
346
471
|
test: /\.[cm]?js$/,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openmrs/webpack-config",
|
|
3
|
-
"version": "10.0.1-pre.
|
|
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",
|
|
@@ -33,6 +33,8 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@module-federation/enhanced": "2.8.1",
|
|
35
35
|
"@swc/core": "1.15.21",
|
|
36
|
+
"browserslist": "4.28.9",
|
|
37
|
+
"browserslist-config-openmrs": "^1.0.1",
|
|
36
38
|
"clean-webpack-plugin": "4.0.0",
|
|
37
39
|
"copy-webpack-plugin": "11.0.0",
|
|
38
40
|
"css-loader": "5.2.7",
|
package/src/index.ts
CHANGED
|
@@ -38,23 +38,30 @@
|
|
|
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 CopyWebpackPlugin from 'copy-webpack-plugin';
|
|
43
46
|
import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
|
|
44
47
|
// eslint-disable-next-line no-restricted-imports
|
|
45
48
|
import { isArray, merge, mergeWith } from 'lodash';
|
|
46
49
|
import { inc, parse } from 'semver';
|
|
47
|
-
import { ModuleFederationPlugin } from '@module-federation/enhanced/webpack';
|
|
48
50
|
import {
|
|
49
51
|
BannerPlugin,
|
|
52
|
+
type Compiler,
|
|
50
53
|
DefinePlugin,
|
|
51
54
|
ExternalsPlugin,
|
|
52
55
|
type ModuleOptions,
|
|
53
56
|
type RuleSetRule,
|
|
57
|
+
WebpackError,
|
|
54
58
|
type WebpackOptionsNormalized as WebpackConfiguration,
|
|
55
59
|
} from 'webpack';
|
|
60
|
+
// webpack's own browsers-to-features mapping
|
|
61
|
+
import browserslistTargetHandler from 'webpack/lib/config/browserslistTargetHandler';
|
|
56
62
|
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
|
|
57
63
|
import { StatsWriterPlugin } from 'webpack-stats-plugin';
|
|
64
|
+
import { ModuleFederationPlugin } from '@module-federation/enhanced/webpack';
|
|
58
65
|
|
|
59
66
|
type OpenmrsWebpackConfig = Omit<Partial<WebpackConfiguration>, 'module' | 'output'> & {
|
|
60
67
|
module: ModuleOptions;
|
|
@@ -70,6 +77,26 @@ const production = 'production';
|
|
|
70
77
|
const moduleFederationPin: string = require('../package.json').dependencies['@module-federation/enhanced'];
|
|
71
78
|
const moduleFederationVersion = parse(moduleFederationPin);
|
|
72
79
|
|
|
80
|
+
// The subset of what `browserslistTargetHandler.resolve` reports that `output.environment` accepts;
|
|
81
|
+
// the rest describe the platform and available APIs, and webpack's schema rejects them here.
|
|
82
|
+
const environmentFlags = [
|
|
83
|
+
'arrowFunction',
|
|
84
|
+
'asyncFunction',
|
|
85
|
+
'bigIntLiteral',
|
|
86
|
+
'const',
|
|
87
|
+
'destructuring',
|
|
88
|
+
'document',
|
|
89
|
+
'dynamicImport',
|
|
90
|
+
'dynamicImportInWorker',
|
|
91
|
+
'forOf',
|
|
92
|
+
'globalThis',
|
|
93
|
+
'importMetaDirnameAndFilename',
|
|
94
|
+
'methodShorthand',
|
|
95
|
+
'module',
|
|
96
|
+
'optionalChaining',
|
|
97
|
+
'templateLiteral',
|
|
98
|
+
] as const;
|
|
99
|
+
|
|
73
100
|
/**
|
|
74
101
|
* Prepended to this app's entry chunks. Without it, an app running under an app shell too old to
|
|
75
102
|
* publish the runtime globals fails with a `TypeError` from inside minified runtime code. All three
|
|
@@ -111,6 +138,132 @@ function getFrameworkVersion() {
|
|
|
111
138
|
}
|
|
112
139
|
}
|
|
113
140
|
|
|
141
|
+
/** What a module's browsers resolved to, plus anything worth telling the developer about getting there. */
|
|
142
|
+
type BrowserPolicy = { queries: Array<string>; warnings: Array<string> };
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* The browserslist queries swc compiles this module against, falling back to OpenMRS's shared config
|
|
146
|
+
* when the module declares none, so that frontend RFC 0003 stays the single source of truth. Given no
|
|
147
|
+
* target at all swc down-levels to ES5, and every supported browser pays for transform helpers it
|
|
148
|
+
* doesn't need.
|
|
149
|
+
*
|
|
150
|
+
* `@openmrs/rspack-config` has a copy of this; keep them in step. `browser-targets.test.ts` compares
|
|
151
|
+
* what the two hand their loaders and fails if they drift.
|
|
152
|
+
*
|
|
153
|
+
* @param root The directory of the module being built
|
|
154
|
+
*/
|
|
155
|
+
function browserslistQueries(root: string): BrowserPolicy {
|
|
156
|
+
const warnings: Array<string> = [];
|
|
157
|
+
// deliberately unguarded
|
|
158
|
+
const loaded = browserslist.loadConfig({ path: root });
|
|
159
|
+
const configured = loaded === undefined ? [] : Array.isArray(loaded) ? loaded : [loaded];
|
|
160
|
+
|
|
161
|
+
if (loaded !== undefined && configured.length === 0) {
|
|
162
|
+
// warn when a browserlist config is empty
|
|
163
|
+
warnings.push(
|
|
164
|
+
`This module declares a browserslist config, but it resolves to no queries for the ` +
|
|
165
|
+
`${process.env.BROWSERSLIST_ENV ?? process.env.NODE_ENV ?? production} environment. ` +
|
|
166
|
+
`Targeting ${defaultBrowserslistQueries.join(', ')} instead.`,
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const expanded = expandBrowserslistExtends(
|
|
171
|
+
configured.length > 0 ? configured : defaultBrowserslistQueries,
|
|
172
|
+
root,
|
|
173
|
+
warnings,
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
return { queries: expanded.length > 0 ? expanded : defaultBrowserslistQueries, warnings };
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function expandBrowserslistExtends(
|
|
180
|
+
queries: Array<string>,
|
|
181
|
+
root: string,
|
|
182
|
+
warnings: Array<string>,
|
|
183
|
+
seen = new Set<string>(),
|
|
184
|
+
): Array<string> {
|
|
185
|
+
// Split on commas because a browserslist config may be a single string of them
|
|
186
|
+
return queries.flatMap((query) =>
|
|
187
|
+
query
|
|
188
|
+
.split(',')
|
|
189
|
+
.flatMap((part) => {
|
|
190
|
+
const extended = /^extends\s+(.+)$/i.exec(part.trim());
|
|
191
|
+
|
|
192
|
+
if (!extended) {
|
|
193
|
+
return [part.trim()];
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const name = extended[1].trim();
|
|
197
|
+
|
|
198
|
+
if (seen.has(name)) {
|
|
199
|
+
return [];
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
seen.add(name);
|
|
203
|
+
|
|
204
|
+
try {
|
|
205
|
+
// browserslist's own loader, rather than a bare `require` so we handle the same syntax
|
|
206
|
+
const resolved = loadQueries({ path: root }, name);
|
|
207
|
+
|
|
208
|
+
return expandBrowserslistExtends(Array.isArray(resolved) ? resolved : [resolved], root, warnings, seen);
|
|
209
|
+
} catch (err) {
|
|
210
|
+
// Only browserslist's own verdict on a named config is survivable: not installed, or refused
|
|
211
|
+
// for its name.
|
|
212
|
+
const notInstalled = (err as { code?: string })?.code === 'MODULE_NOT_FOUND';
|
|
213
|
+
const refused = (err as { browserslist?: boolean })?.browserslist === true;
|
|
214
|
+
|
|
215
|
+
if (!notInstalled && !refused) {
|
|
216
|
+
throw err;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
warnings.push(
|
|
220
|
+
`Could not load the browserslist config "${name}" (${(err as Error).message}). ` +
|
|
221
|
+
`Targeting ${defaultBrowserslistQueries.join(', ')} instead.`,
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
return defaultBrowserslistQueries;
|
|
225
|
+
}
|
|
226
|
+
})
|
|
227
|
+
.filter((part) => part.length > 0),
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** Reports how a module's browsers were worked out, where a developer will actually see it. */
|
|
232
|
+
class BrowserslistWarningsPlugin {
|
|
233
|
+
constructor(private readonly messages: Array<string>) {}
|
|
234
|
+
|
|
235
|
+
apply(compiler: Compiler) {
|
|
236
|
+
compiler.hooks.thisCompilation.tap('OpenmrsBrowserslistWarnings', (compilation) => {
|
|
237
|
+
for (const message of this.messages) {
|
|
238
|
+
compilation.warnings.push(new WebpackError(message));
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* The `output.environment` flags for a set of browserslist queries: which JavaScript features webpack
|
|
246
|
+
* may use in the runtime it generates.
|
|
247
|
+
*
|
|
248
|
+
* Derived with webpack's own browserslist target handler, so the browsers-to-features mapping is the
|
|
249
|
+
* caniuse-backed one webpack uses for `target: 'browserslist'` rather than a table maintained here.
|
|
250
|
+
* `resolve` also reports platform and API properties that `output.environment` rejects, hence the
|
|
251
|
+
* filter to the flags webpack's schema accepts.
|
|
252
|
+
*
|
|
253
|
+
* @param queries Browserslist queries, already `extends`-expanded
|
|
254
|
+
* @param root The directory of the module being built, for resolving relative queries
|
|
255
|
+
*/
|
|
256
|
+
function browserEnvironment(queries: Array<string>, root: string): WebpackConfiguration['output']['environment'] {
|
|
257
|
+
const supported = browserslistTargetHandler.resolve(browserslist(queries, { path: root })) as Record<
|
|
258
|
+
string,
|
|
259
|
+
boolean | null | undefined
|
|
260
|
+
>;
|
|
261
|
+
|
|
262
|
+
return Object.fromEntries(
|
|
263
|
+
environmentFlags.filter((flag) => typeof supported[flag] === 'boolean').map((flag) => [flag, supported[flag]]),
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
|
|
114
267
|
function makeIdent(name: string): string {
|
|
115
268
|
if (name.includes('/')) {
|
|
116
269
|
name = name.slice(name.indexOf('/'));
|
|
@@ -201,6 +354,7 @@ export default (env: Record<string, string>, argv: Record<string, string> = {})
|
|
|
201
354
|
const outDir = dirname(browser || main);
|
|
202
355
|
const srcFile = resolve(root, browser ? main : types);
|
|
203
356
|
const ident = makeIdent(name);
|
|
357
|
+
const { queries: browserTargets, warnings: browserslistWarnings } = browserslistQueries(root);
|
|
204
358
|
const frameworkVersion = getFrameworkVersion();
|
|
205
359
|
const routes = resolve(root, 'src', 'routes.json');
|
|
206
360
|
const hasRoutesDefined = fileExistsSync(routes);
|
|
@@ -232,6 +386,7 @@ export default (env: Record<string, string>, argv: Record<string, string> = {})
|
|
|
232
386
|
publicPath: 'auto',
|
|
233
387
|
path: resolve(root, outDir),
|
|
234
388
|
hashFunction: 'xxhash64',
|
|
389
|
+
environment: browserEnvironment(browserTargets, root),
|
|
235
390
|
},
|
|
236
391
|
module: {
|
|
237
392
|
rules: [
|
|
@@ -239,7 +394,16 @@ export default (env: Record<string, string>, argv: Record<string, string> = {})
|
|
|
239
394
|
{
|
|
240
395
|
test: /\.m?(js|ts|tsx)$/,
|
|
241
396
|
exclude: /node_modules/,
|
|
242
|
-
use:
|
|
397
|
+
use: {
|
|
398
|
+
loader: require.resolve('swc-loader'),
|
|
399
|
+
options: {
|
|
400
|
+
env: {
|
|
401
|
+
targets: browserTargets,
|
|
402
|
+
},
|
|
403
|
+
// ignore a project .swcrc to match rspack behavior
|
|
404
|
+
swcrc: false,
|
|
405
|
+
},
|
|
406
|
+
},
|
|
243
407
|
},
|
|
244
408
|
scriptRuleConfig,
|
|
245
409
|
),
|
|
@@ -282,6 +446,7 @@ export default (env: Record<string, string>, argv: Record<string, string> = {})
|
|
|
282
446
|
],
|
|
283
447
|
},
|
|
284
448
|
mode,
|
|
449
|
+
target: 'web',
|
|
285
450
|
devtool: mode === production ? 'hidden-nosources-source-map' : 'source-map',
|
|
286
451
|
devServer: {
|
|
287
452
|
headers: {
|
|
@@ -313,6 +478,7 @@ export default (env: Record<string, string>, argv: Record<string, string> = {})
|
|
|
313
478
|
optimizationConfig,
|
|
314
479
|
),
|
|
315
480
|
plugins: [
|
|
481
|
+
browserslistWarnings.length > 0 && new BrowserslistWarningsPlugin(browserslistWarnings),
|
|
316
482
|
new ForkTsCheckerWebpackPlugin({
|
|
317
483
|
issue: {
|
|
318
484
|
exclude: [
|