@bleedingdev/modern-js-app-tools 3.2.0-ultramodern.120 → 3.2.0-ultramodern.121

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.
Files changed (44) hide show
  1. package/dist/cjs/baseline.js +3 -87
  2. package/dist/cjs/commands/index.js +3 -6
  3. package/dist/cjs/commands/runtime.js +35 -2
  4. package/dist/cjs/index.js +1 -1
  5. package/dist/cjs/plugins/deploy/platforms/cloudflare.js +20 -4
  6. package/dist/cjs/plugins/deploy/platforms/templates/cloudflare-entry.mjs +74 -13
  7. package/dist/cjs/plugins/deploy/utils/index.js +10 -35
  8. package/dist/cjs/presetUltramodern.js +87 -3
  9. package/dist/cjs/rsbuild.js +46 -62
  10. package/dist/cjs/types/config/cloudflareDeploy.js +18 -0
  11. package/dist/cjs/types/config/precompress.js +18 -0
  12. package/dist/esm/baseline.mjs +3 -77
  13. package/dist/esm/commands/index.mjs +2 -5
  14. package/dist/esm/commands/runtime.mjs +33 -3
  15. package/dist/esm/index.mjs +2 -2
  16. package/dist/esm/plugins/deploy/platforms/cloudflare.mjs +20 -4
  17. package/dist/esm/plugins/deploy/platforms/templates/cloudflare-entry.mjs +74 -13
  18. package/dist/esm/plugins/deploy/utils/index.mjs +11 -36
  19. package/dist/esm/presetUltramodern.mjs +77 -3
  20. package/dist/esm/rsbuild.mjs +1 -8
  21. package/dist/esm/types/config/cloudflareDeploy.mjs +0 -0
  22. package/dist/esm/types/config/precompress.mjs +0 -0
  23. package/dist/esm-node/baseline.mjs +3 -77
  24. package/dist/esm-node/commands/index.mjs +2 -5
  25. package/dist/esm-node/commands/runtime.mjs +33 -3
  26. package/dist/esm-node/index.mjs +2 -2
  27. package/dist/esm-node/plugins/deploy/platforms/cloudflare.mjs +20 -4
  28. package/dist/esm-node/plugins/deploy/platforms/templates/cloudflare-entry.mjs +74 -13
  29. package/dist/esm-node/plugins/deploy/utils/index.mjs +12 -36
  30. package/dist/esm-node/presetUltramodern.mjs +77 -3
  31. package/dist/esm-node/rsbuild.mjs +1 -8
  32. package/dist/esm-node/types/config/cloudflareDeploy.mjs +1 -0
  33. package/dist/esm-node/types/config/precompress.mjs +1 -0
  34. package/dist/types/baseline.d.ts +16 -46
  35. package/dist/types/commands/index.d.ts +1 -1
  36. package/dist/types/commands/runtime.d.ts +1 -0
  37. package/dist/types/presetUltramodern.d.ts +52 -2
  38. package/dist/types/types/config/cloudflareDeploy.d.ts +79 -0
  39. package/dist/types/types/config/deploy.d.ts +2 -56
  40. package/dist/types/types/config/output.d.ts +4 -20
  41. package/dist/types/types/config/precompress.d.ts +20 -0
  42. package/package.json +11 -13
  43. package/dist/esm/rslib-runtime.mjs +0 -18
  44. package/dist/esm-node/rslib-runtime.mjs +0 -19
@@ -1,19 +1,5 @@
1
1
  "use strict";
2
- var __webpack_modules__ = {
3
- "@modern-js/plugin/cli" (module) {
4
- module.exports = require("@modern-js/plugin/cli");
5
- }
6
- };
7
- var __webpack_module_cache__ = {};
8
- function __webpack_require__(moduleId) {
9
- var cachedModule = __webpack_module_cache__[moduleId];
10
- if (void 0 !== cachedModule) return cachedModule.exports;
11
- var module = __webpack_module_cache__[moduleId] = {
12
- exports: {}
13
- };
14
- __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
15
- return module.exports;
16
- }
2
+ var __webpack_require__ = {};
17
3
  (()=>{
18
4
  __webpack_require__.d = (exports1, getters, values)=>{
19
5
  var define = (defs, kind)=>{
@@ -40,54 +26,52 @@ function __webpack_require__(moduleId) {
40
26
  };
41
27
  })();
42
28
  var __webpack_exports__ = {};
43
- (()=>{
44
- __webpack_require__.r(__webpack_exports__);
45
- __webpack_require__.d(__webpack_exports__, {
46
- resolveModernRsbuildConfig: ()=>resolveModernRsbuildConfig
29
+ __webpack_require__.r(__webpack_exports__);
30
+ __webpack_require__.d(__webpack_exports__, {
31
+ resolveModernRsbuildConfig: ()=>resolveModernRsbuildConfig
32
+ });
33
+ const builder_namespaceObject = require("@modern-js/builder");
34
+ const cli_namespaceObject = require("@modern-js/plugin/cli");
35
+ const utils_namespaceObject = require("@modern-js/utils");
36
+ const index_js_namespaceObject = require("./builder/shared/builderPlugins/index.js");
37
+ const external_constants_js_namespaceObject = require("./constants.js");
38
+ const getConfigFile_js_namespaceObject = require("./utils/getConfigFile.js");
39
+ const loadPlugins_js_namespaceObject = require("./utils/loadPlugins.js");
40
+ const MODERN_META_NAME = 'modern-js';
41
+ async function resolveModernRsbuildConfig(options) {
42
+ const { cwd = process.cwd(), metaName = MODERN_META_NAME } = options;
43
+ const configFile = options.configPath || (0, getConfigFile_js_namespaceObject.getConfigFile)(void 0, cwd);
44
+ if (!configFile) throw new Error(`Cannot find config file in ${cwd}. Please make sure you have a ${external_constants_js_namespaceObject.DEFAULT_CONFIG_FILE} file in your project.`);
45
+ const { config: modernConfig, getAppContext } = await (0, cli_namespaceObject.createConfigOptions)({
46
+ command: options.command,
47
+ cwd,
48
+ configFile,
49
+ internalPlugins: await (0, loadPlugins_js_namespaceObject.loadInternalPlugins)(cwd, utils_namespaceObject.INTERNAL_RUNTIME_PLUGINS),
50
+ metaName,
51
+ modifyModernConfig: options.modifyModernConfig
47
52
  });
48
- const builder_namespaceObject = require("@modern-js/builder");
49
- const utils_namespaceObject = require("@modern-js/utils");
50
- const index_js_namespaceObject = require("./builder/shared/builderPlugins/index.js");
51
- const external_constants_js_namespaceObject = require("./constants.js");
52
- const getConfigFile_js_namespaceObject = require("./utils/getConfigFile.js");
53
- const loadPlugins_js_namespaceObject = require("./utils/loadPlugins.js");
54
- const MODERN_META_NAME = 'modern-js';
55
- const { createConfigOptions } = __webpack_require__("@modern-js/plugin/cli");
56
- async function resolveModernRsbuildConfig(options) {
57
- const { cwd = process.cwd(), metaName = MODERN_META_NAME } = options;
58
- const configFile = options.configPath || (0, getConfigFile_js_namespaceObject.getConfigFile)(void 0, cwd);
59
- if (!configFile) throw new Error(`Cannot find config file in ${cwd}. Please make sure you have a ${external_constants_js_namespaceObject.DEFAULT_CONFIG_FILE} file in your project.`);
60
- const { config: modernConfig, getAppContext } = await createConfigOptions({
61
- command: options.command,
62
- cwd,
63
- configFile,
64
- internalPlugins: await (0, loadPlugins_js_namespaceObject.loadInternalPlugins)(cwd, utils_namespaceObject.INTERNAL_RUNTIME_PLUGINS),
65
- metaName,
66
- modifyModernConfig: options.modifyModernConfig
67
- });
68
- const nonStandardConfig = {
69
- ...modernConfig,
70
- plugins: modernConfig.builderPlugins
71
- };
72
- const appContext = getAppContext();
73
- const { rsbuildConfig, rsbuildPlugins } = await (0, builder_namespaceObject.parseRspackConfig)(nonStandardConfig, {
74
- cwd
75
- });
76
- const adapterParams = {
77
- appContext,
78
- normalizedConfig: modernConfig
79
- };
80
- rsbuildConfig.plugins = [
81
- ...rsbuildPlugins,
82
- ...rsbuildConfig.plugins || [],
83
- (0, index_js_namespaceObject.builderPluginAdapterBasic)(adapterParams),
84
- (0, index_js_namespaceObject.builderPluginAdapterHooks)(adapterParams)
85
- ];
86
- return {
87
- rsbuildConfig
88
- };
89
- }
90
- })();
53
+ const nonStandardConfig = {
54
+ ...modernConfig,
55
+ plugins: modernConfig.builderPlugins
56
+ };
57
+ const appContext = getAppContext();
58
+ const { rsbuildConfig, rsbuildPlugins } = await (0, builder_namespaceObject.parseRspackConfig)(nonStandardConfig, {
59
+ cwd
60
+ });
61
+ const adapterParams = {
62
+ appContext,
63
+ normalizedConfig: modernConfig
64
+ };
65
+ rsbuildConfig.plugins = [
66
+ ...rsbuildPlugins,
67
+ ...rsbuildConfig.plugins || [],
68
+ (0, index_js_namespaceObject.builderPluginAdapterBasic)(adapterParams),
69
+ (0, index_js_namespaceObject.builderPluginAdapterHooks)(adapterParams)
70
+ ];
71
+ return {
72
+ rsbuildConfig
73
+ };
74
+ }
91
75
  exports.resolveModernRsbuildConfig = __webpack_exports__.resolveModernRsbuildConfig;
92
76
  for(var __rspack_i in __webpack_exports__)if (-1 === [
93
77
  "resolveModernRsbuildConfig"
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __webpack_require__ = {};
3
+ (()=>{
4
+ __webpack_require__.r = (exports1)=>{
5
+ if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
6
+ value: 'Module'
7
+ });
8
+ Object.defineProperty(exports1, '__esModule', {
9
+ value: true
10
+ });
11
+ };
12
+ })();
13
+ var __webpack_exports__ = {};
14
+ __webpack_require__.r(__webpack_exports__);
15
+ for(var __rspack_i in __webpack_exports__)exports[__rspack_i] = __webpack_exports__[__rspack_i];
16
+ Object.defineProperty(exports, '__esModule', {
17
+ value: true
18
+ });
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __webpack_require__ = {};
3
+ (()=>{
4
+ __webpack_require__.r = (exports1)=>{
5
+ if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
6
+ value: 'Module'
7
+ });
8
+ Object.defineProperty(exports1, '__esModule', {
9
+ value: true
10
+ });
11
+ };
12
+ })();
13
+ var __webpack_exports__ = {};
14
+ __webpack_require__.r(__webpack_exports__);
15
+ for(var __rspack_i in __webpack_exports__)exports[__rspack_i] = __webpack_exports__[__rspack_i];
16
+ Object.defineProperty(exports, '__esModule', {
17
+ value: true
18
+ });
@@ -1,78 +1,4 @@
1
- import { createRequire } from "node:module";
2
- import node_path from "node:path";
3
- import { mergeConfig } from "@modern-js/plugin/cli";
4
- const resolveReactRouterPackageDir = ()=>{
5
- const localRequire = createRequire(node_path.join(process.cwd(), 'package.json'));
6
- try {
7
- const reactRouterDomPackageJson = localRequire.resolve('react-router-dom/package.json', {
8
- paths: [
9
- process.cwd()
10
- ]
11
- });
12
- const reactRouterPackageJson = localRequire.resolve('react-router/package.json', {
13
- paths: [
14
- node_path.dirname(reactRouterDomPackageJson)
15
- ]
16
- });
17
- return node_path.dirname(reactRouterPackageJson);
18
- } catch {
19
- return;
20
- }
21
- };
22
- const setReactRouterBridgeSafeAliases = (chain)=>{
23
- const reactRouterPackageDir = resolveReactRouterPackageDir();
24
- if (!reactRouterPackageDir) return;
25
- const productionEntry = node_path.join(reactRouterPackageDir, 'dist/production/index.mjs');
26
- const developmentEntry = node_path.join(reactRouterPackageDir, 'dist/development/index.mjs');
27
- chain.resolve.alias.set('react-router$', productionEntry);
28
- chain.resolve.alias.set('react-router/dist/production/index.js', productionEntry);
29
- chain.resolve.alias.set('react-router/dist/development/index.js', developmentEntry);
30
- };
31
- const createAppBaselineConfig = (options = {})=>{
32
- const { appId = 'app', enableBffRequestId = true, enableTelemetry = true, enableTelemetryExporters = true, otlpEndpoint = process.env.MODERN_TELEMETRY_OTLP_ENDPOINT || 'http://127.0.0.1:4318/v1/logs', victoriaMetricsEndpoint = process.env.MODERN_TELEMETRY_VICTORIA_ENDPOINT || 'http://127.0.0.1:8428/api/v1/import/prometheus', telemetryFailLoudStartup = true, enableModuleFederationSSR = true } = options;
33
- const server = {};
34
- if (enableTelemetry) {
35
- server.telemetry = {
36
- enabled: true,
37
- failLoudStartup: telemetryFailLoudStartup
38
- };
39
- if (enableTelemetryExporters) server.telemetry.exporters = {
40
- otlp: {
41
- enabled: true,
42
- endpoint: otlpEndpoint
43
- },
44
- victoriaMetrics: {
45
- enabled: true,
46
- endpoint: victoriaMetricsEndpoint
47
- }
48
- };
49
- }
50
- if (enableModuleFederationSSR) server.ssr = {
51
- mode: 'stream',
52
- moduleFederationAppSSR: true
53
- };
54
- const baselineConfig = {
55
- output: {
56
- precompress: true
57
- },
58
- performance: {
59
- rsdoctor: {
60
- enabled: 'production' === process.env.NODE_ENV,
61
- disableClientServer: true
62
- }
63
- },
64
- server,
65
- tools: {
66
- bundlerChain: setReactRouterBridgeSafeAliases
67
- }
68
- };
69
- if (enableBffRequestId) baselineConfig.bff = {
70
- requestId: appId
71
- };
72
- return baselineConfig;
73
- };
74
- const withAppBaseline = (config, options = {})=>mergeConfig([
75
- createAppBaselineConfig(options),
76
- config
77
- ]);
1
+ import { createPresetUltramodernConfig, presetUltramodern } from "./presetUltramodern.mjs";
2
+ const createAppBaselineConfig = createPresetUltramodernConfig;
3
+ const withAppBaseline = presetUltramodern;
78
4
  export { createAppBaselineConfig, withAppBaseline };
@@ -1,5 +1,4 @@
1
1
  import { i18n, localeKeys } from "../locale/index.mjs";
2
- import { runtimeCommand } from "./runtime.mjs";
3
2
  const devCommand = async (program, api)=>{
4
3
  program.command('dev').alias('start').usage('[options]').description(i18n.t(localeKeys.command.dev.describe)).option('-c --config <config>', i18n.t(localeKeys.command.shared.config)).option('-e --entry [entry...]', i18n.t(localeKeys.command.dev.entry)).option('--analyze', i18n.t(localeKeys.command.shared.analyze)).option('--api-only', i18n.t(localeKeys.command.dev.apiOnly)).option('--web-only', i18n.t(localeKeys.command.dev.webOnly)).action(async (options)=>{
5
4
  const { dev } = await import("./dev.mjs");
@@ -41,7 +40,5 @@ const infoCommand = (program, api)=>{
41
40
  await info(api, options);
42
41
  });
43
42
  };
44
- const runtimeOperationsCommand = async (program, api)=>{
45
- await runtimeCommand(program, api);
46
- };
47
- export { buildCommand, deployCommand, devCommand, infoCommand, inspectCommand, runtimeOperationsCommand, serverCommand };
43
+ export { runtimeCommand } from "./runtime.mjs";
44
+ export { buildCommand, deployCommand, devCommand, infoCommand, inspectCommand, serverCommand };
@@ -54,9 +54,39 @@ const parseResponseBody = async (response)=>{
54
54
  };
55
55
  }
56
56
  };
57
+ const INDENT_STEP = ' ';
58
+ const formatScalar = (value)=>'string' == typeof value ? value : JSON.stringify(value) ?? 'undefined';
59
+ const formatHumanReadableLines = (value, indent)=>{
60
+ if (Array.isArray(value)) {
61
+ if (0 === value.length) return [
62
+ `${indent}(empty)`
63
+ ];
64
+ return value.flatMap((entry)=>null !== entry && 'object' == typeof entry ? [
65
+ `${indent}-`,
66
+ ...formatHumanReadableLines(entry, indent + INDENT_STEP)
67
+ ] : [
68
+ `${indent}- ${formatScalar(entry)}`
69
+ ]);
70
+ }
71
+ if (null !== value && 'object' == typeof value) {
72
+ const entries = Object.entries(value);
73
+ if (0 === entries.length) return [
74
+ `${indent}(empty)`
75
+ ];
76
+ return entries.flatMap(([key, entry])=>null !== entry && 'object' == typeof entry ? [
77
+ `${indent}${key}:`,
78
+ ...formatHumanReadableLines(entry, indent + INDENT_STEP)
79
+ ] : [
80
+ `${indent}${key}: ${formatScalar(entry)}`
81
+ ]);
82
+ }
83
+ return [
84
+ `${indent}${formatScalar(value)}`
85
+ ];
86
+ };
87
+ const formatRuntimeOutput = (payload, jsonOnly)=>jsonOnly ? JSON.stringify(payload, null, 2) : formatHumanReadableLines(payload, '').join('\n');
57
88
  const printOutput = (payload, jsonOnly)=>{
58
- if (jsonOnly) return void console.log(JSON.stringify(payload, null, 2));
59
- console.log(JSON.stringify(payload, null, 2));
89
+ console.log(formatRuntimeOutput(payload, jsonOnly));
60
90
  };
61
91
  const createRuntimeFallbackSignalPayload = (options)=>{
62
92
  const payload = {
@@ -113,4 +143,4 @@ const runtimeCommand = async (program, _api)=>{
113
143
  printOutput(responsePayload, options.json);
114
144
  });
115
145
  };
116
- export { createRuntimeFallbackSignalPayload, resolveRuntimeEndpoint, resolveToken, runtimeCommand };
146
+ export { createRuntimeFallbackSignalPayload, formatRuntimeOutput, resolveRuntimeEndpoint, resolveToken, runtimeCommand };
@@ -3,7 +3,7 @@ import { getLocaleLanguage } from "@modern-js/i18n-utils/language-detector";
3
3
  import { createAsyncHook } from "@modern-js/plugin";
4
4
  import { cleanRequireCache, deprecatedCommands, emptyDir, getArgv, getCommand } from "@modern-js/utils";
5
5
  import path from "path";
6
- import { buildCommand, deployCommand, devCommand, infoCommand, inspectCommand, runtimeOperationsCommand, serverCommand } from "./commands/index.mjs";
6
+ import { buildCommand, deployCommand, devCommand, infoCommand, inspectCommand, runtimeCommand, serverCommand } from "./commands/index.mjs";
7
7
  import { compatPlugin } from "./compat/index.mjs";
8
8
  import { DEFAULT_RUNTIME_CONFIG_FILE } from "./constants.mjs";
9
9
  import { i18n } from "./locale/index.mjs";
@@ -71,7 +71,7 @@ const appTools = ()=>({
71
71
  deployCommand(program, api);
72
72
  inspectCommand(program, api);
73
73
  infoCommand(program, api);
74
- await runtimeOperationsCommand(program, api);
74
+ await runtimeCommand(program, api);
75
75
  deprecatedCommands(program);
76
76
  });
77
77
  api.onPrepare(async ()=>{
@@ -19,6 +19,15 @@ const DEFAULT_SECURITY_HEADERS = {
19
19
  contentTypeOptions: 'nosniff',
20
20
  permissionsPolicy: 'camera=(), geolocation=(), microphone=(), payment=(), usb=()'
21
21
  };
22
+ const DEFAULT_CORS_ALLOWED_METHODS = [
23
+ 'GET',
24
+ 'HEAD',
25
+ 'POST',
26
+ 'PUT',
27
+ 'PATCH',
28
+ 'DELETE',
29
+ 'OPTIONS'
30
+ ];
22
31
  const DEFAULT_CSP_DIRECTIVES = {
23
32
  'base-uri': [
24
33
  "'self'"
@@ -156,10 +165,20 @@ const createNoindexPolicy = (noindex)=>{
156
165
  reason: noindex.reason
157
166
  };
158
167
  };
168
+ const createCloudflareWorkerCorsPolicy = (cors)=>({
169
+ assets: cors?.assets ?? true,
170
+ allowedOrigins: normalizeDirectiveValues(cors?.allowedOrigins ?? []),
171
+ allowedMethods: cors?.allowedMethods?.length ? normalizeDirectiveValues(cors.allowedMethods.map((method)=>method.toUpperCase())) : DEFAULT_CORS_ALLOWED_METHODS,
172
+ allowedHeaders: cors?.allowedHeaders?.length ? normalizeDirectiveValues(cors.allowedHeaders) : [
173
+ '*'
174
+ ],
175
+ reason: cors?.reason
176
+ });
159
177
  const createCloudflareWorkerSecurityPolicy = (modernConfig)=>{
160
178
  const security = modernConfig.deploy?.worker?.security;
161
179
  if (security?.enabled === false) return {
162
180
  enabled: false,
181
+ cors: createCloudflareWorkerCorsPolicy(security.cors),
163
182
  reason: security.reason
164
183
  };
165
184
  return {
@@ -171,10 +190,7 @@ const createCloudflareWorkerSecurityPolicy = (modernConfig)=>{
171
190
  },
172
191
  contentSecurityPolicy: createContentSecurityPolicy(security?.contentSecurityPolicy),
173
192
  noindex: createNoindexPolicy(security?.noindex),
174
- cookies: {
175
- mutateSetCookie: false,
176
- reason: security?.cookies?.reason ?? 'Cloudflare worker does not own application Set-Cookie headers.'
177
- },
193
+ cors: createCloudflareWorkerCorsPolicy(security?.cors),
178
194
  reason: security?.reason
179
195
  };
180
196
  };
@@ -3,16 +3,57 @@ const MODERN_WORKER_MANIFEST = p_workerManifest;
3
3
  const WORKER_MODULE_LOADERS = p_workerModuleLoaders;
4
4
  const workerModulePromises = new Map();
5
5
  const remoteJsonPromises = new Map();
6
- const CORS_HEADERS = {
6
+ const CORS_POLICY = MODERN_WORKER_MANIFEST.security?.cors || {};
7
+ const ASSET_CORS_ENABLED = false !== CORS_POLICY.assets;
8
+ const APP_CORS_ALLOWED_ORIGINS = (CORS_POLICY.allowedOrigins || []).map((origin)=>String(origin).toLowerCase());
9
+ const APP_CORS_ALLOWED_METHODS = (CORS_POLICY.allowedMethods?.length ? CORS_POLICY.allowedMethods : [
10
+ 'GET',
11
+ 'HEAD',
12
+ 'POST',
13
+ 'PUT',
14
+ 'PATCH',
15
+ 'DELETE',
16
+ 'OPTIONS'
17
+ ]).join(', ');
18
+ const APP_CORS_ALLOWED_HEADERS = (CORS_POLICY.allowedHeaders?.length ? CORS_POLICY.allowedHeaders : [
19
+ '*'
20
+ ]).join(', ');
21
+ const ASSET_CORS_HEADERS = {
7
22
  'access-control-allow-headers': '*',
8
23
  'access-control-allow-methods': 'GET, HEAD, OPTIONS',
9
24
  'access-control-allow-origin': '*'
10
25
  };
11
26
  globalThis.__dirname ??= '/';
12
27
  globalThis.__filename ??= '/index.js';
13
- function withCorsHeaders(response) {
28
+ function getAllowedAppCorsOrigin(request) {
29
+ if (0 === APP_CORS_ALLOWED_ORIGINS.length) return null;
30
+ const origin = request.headers.get('origin');
31
+ if (!origin) return null;
32
+ if (APP_CORS_ALLOWED_ORIGINS.includes('*')) return '*';
33
+ return APP_CORS_ALLOWED_ORIGINS.includes(origin.toLowerCase()) ? origin : null;
34
+ }
35
+ function appendVaryOrigin(headers) {
36
+ const vary = headers.get('vary');
37
+ if (!vary) return void headers.set('vary', 'origin');
38
+ const varyValues = vary.split(',').map((value)=>value.trim().toLowerCase());
39
+ if (!varyValues.includes('origin')) headers.set('vary', `${vary}, origin`);
40
+ }
41
+ function withAppCorsHeaders(response, request) {
42
+ const allowedOrigin = getAllowedAppCorsOrigin(request);
43
+ if (!allowedOrigin) return response;
14
44
  const headers = new Headers(response.headers);
15
- for (const [name, value] of Object.entries(CORS_HEADERS))if (!headers.has(name)) headers.set(name, value);
45
+ if (!headers.has('access-control-allow-origin')) headers.set('access-control-allow-origin', allowedOrigin);
46
+ if ('*' !== allowedOrigin) appendVaryOrigin(headers);
47
+ return new Response(response.body, {
48
+ headers,
49
+ status: response.status,
50
+ statusText: response.statusText
51
+ });
52
+ }
53
+ function withAssetCorsHeaders(response) {
54
+ if (!ASSET_CORS_ENABLED) return response;
55
+ const headers = new Headers(response.headers);
56
+ for (const [name, value] of Object.entries(ASSET_CORS_HEADERS))if (!headers.has(name)) headers.set(name, value);
16
57
  return new Response(response.body, {
17
58
  headers,
18
59
  status: response.status,
@@ -84,7 +125,7 @@ function isFingerprintedAssetPathname(pathname) {
84
125
  return /(?:^|\/)[^/]+\.[a-f0-9]{8,}\.(?:css|js|mjs|json|svg|png|jpe?g|webp|avif|gif|woff2?|ttf)$/iu.test(pathname);
85
126
  }
86
127
  function withAssetHeaders(response, request) {
87
- const corsResponse = withCorsHeaders(response);
128
+ const corsResponse = withAssetCorsHeaders(response);
88
129
  const headers = new Headers(corsResponse.headers);
89
130
  const { pathname } = new URL(request.url);
90
131
  if (isFingerprintedAssetPathname(pathname)) headers.set('cache-control', 'public, max-age=31536000, immutable');
@@ -94,10 +135,30 @@ function withAssetHeaders(response, request) {
94
135
  statusText: corsResponse.statusText
95
136
  });
96
137
  }
97
- function createCorsPreflightResponse(request) {
138
+ async function createCorsPreflightResponse(request, env) {
98
139
  if ('OPTIONS' !== request.method) return null;
140
+ const allowedOrigin = getAllowedAppCorsOrigin(request);
141
+ if (allowedOrigin) {
142
+ const headers = new Headers({
143
+ 'access-control-allow-headers': APP_CORS_ALLOWED_HEADERS,
144
+ 'access-control-allow-methods': APP_CORS_ALLOWED_METHODS,
145
+ 'access-control-allow-origin': allowedOrigin
146
+ });
147
+ if ('*' !== allowedOrigin) headers.set('vary', 'origin');
148
+ return new Response(null, {
149
+ headers,
150
+ status: 204
151
+ });
152
+ }
153
+ if (!ASSET_CORS_ENABLED) return null;
154
+ const assets = env?.[ASSETS_BINDING];
155
+ if (!assets || 'function' != typeof assets.fetch) return null;
156
+ const assetResponse = await assets.fetch(new Request(request.url, {
157
+ method: 'HEAD'
158
+ }));
159
+ if (!assetResponse || 404 === assetResponse.status) return null;
99
160
  return new Response(null, {
100
- headers: CORS_HEADERS,
161
+ headers: ASSET_CORS_HEADERS,
101
162
  status: 204
102
163
  });
103
164
  }
@@ -478,25 +539,25 @@ async function dispatchBffRequest(request, env) {
478
539
  }
479
540
  export default {
480
541
  async fetch (request, env, ctx) {
481
- const corsPreflightResponse = createCorsPreflightResponse(request);
542
+ const corsPreflightResponse = await createCorsPreflightResponse(request, env);
482
543
  if (corsPreflightResponse) return finalizeResponseForRequest(corsPreflightResponse, request);
483
544
  const assetResponse = await fetchAsset(request, env);
484
545
  if (assetResponse) return finalizeResponseForRequest(assetResponse, request);
485
546
  const bffResponse = await dispatchBffRequest(request, env);
486
- if (bffResponse) return finalizeResponseForRequest(withCorsHeaders(bffResponse), request);
547
+ if (bffResponse) return finalizeResponseForRequest(withAppCorsHeaders(bffResponse, request), request);
487
548
  const route = findRoute(request);
488
549
  const { pathname } = new URL(request.url);
489
- if (isAssetLikePathname(pathname) && !routeMatchesExactly(route, pathname)) return finalizeResponseForRequest(withCorsHeaders(new Response('Not found', {
550
+ if (isAssetLikePathname(pathname) && !routeMatchesExactly(route, pathname)) return finalizeResponseForRequest(withAppCorsHeaders(new Response('Not found', {
490
551
  status: 404
491
- })), request);
552
+ }), request), request);
492
553
  if (route?.worker) {
493
554
  const renderableRequest = createRenderableRequest(request);
494
- return finalizeResponseForRequest(withCorsHeaders(await dispatchRouteWorker(route, renderableRequest, env, ctx)), request);
555
+ return finalizeResponseForRequest(withAppCorsHeaders(await dispatchRouteWorker(route, renderableRequest, env, ctx), request), request);
495
556
  }
496
557
  const htmlResponse = await fetchRouteHtml(route, request, env);
497
558
  if (htmlResponse) return finalizeResponseForRequest(htmlResponse, request);
498
- return finalizeResponseForRequest(withCorsHeaders(new Response('Not found', {
559
+ return finalizeResponseForRequest(withAppCorsHeaders(new Response('Not found', {
499
560
  status: 404
500
- })), request);
561
+ }), request), request);
501
562
  }
502
563
  };
@@ -1,5 +1,6 @@
1
1
  import { createRequire } from "node:module";
2
- import { ROUTE_SPEC_FILE, SERVER_DIR, fs, getMeta } from "@modern-js/utils";
2
+ import { pathToFileURL } from "node:url";
3
+ import { ROUTE_SPEC_FILE, SERVER_DIR, dynamicImport, fs, getMeta } from "@modern-js/utils";
3
4
  import path from "path";
4
5
  const normalizePath = (filePath)=>filePath.replace(/\\/g, '/');
5
6
  const getProjectUsage = (appDirectory, distDirectory, metaName)=>{
@@ -25,43 +26,17 @@ const getProjectUsage = (appDirectory, distDirectory, metaName)=>{
25
26
  };
26
27
  const getTemplatePath = (file)=>path.join(__dirname, '../platforms/templates', file);
27
28
  const readTemplate = async (file)=>(await fs.readFile(getTemplatePath(file))).toString();
28
- const localRequire = createRequire(path.join(__dirname, 'package.json'));
29
- const findNearestPackageJson = (resolvedEntry)=>{
30
- let currentDir = path.dirname(resolvedEntry);
31
- while(currentDir !== path.dirname(currentDir)){
32
- const manifestPath = path.join(currentDir, 'package.json');
33
- if (fs.existsSync(manifestPath)) return manifestPath;
34
- currentDir = path.dirname(currentDir);
35
- }
36
- };
37
- const splitPackageSpecifier = (entry)=>{
38
- const segments = entry.split('/');
39
- if (entry.startsWith('@')) {
40
- const [scope, name, ...rest] = segments;
41
- return {
42
- packageName: `${scope}/${name}`,
43
- exportKey: rest.length > 0 ? `./${rest.join('/')}` : '.'
44
- };
45
- }
46
- const [name, ...rest] = segments;
47
- return {
48
- packageName: name,
49
- exportKey: rest.length > 0 ? `./${rest.join('/')}` : '.'
50
- };
51
- };
52
29
  const resolveESMDependency = async (entry)=>{
30
+ const conditions = new Set([
31
+ 'node',
32
+ 'import',
33
+ 'module',
34
+ 'default'
35
+ ]);
53
36
  try {
54
- const { packageName, exportKey } = splitPackageSpecifier(entry);
55
- const resolvedEntry = localRequire.resolve(entry);
56
- const packageJsonPath = findNearestPackageJson(localRequire.resolve(packageName));
57
- if (!packageJsonPath) return normalizePath(resolvedEntry);
58
- const packageDir = path.dirname(packageJsonPath);
59
- const packageJson = fs.readJSONSync(packageJsonPath);
60
- const exportConfig = packageJson.exports?.[exportKey];
61
- if ('string' == typeof exportConfig) return normalizePath(path.join(packageDir, exportConfig));
62
- const esmExportPath = exportConfig?.node?.import || exportConfig?.import || exportConfig?.default;
63
- if ('string' == typeof esmExportPath) return normalizePath(path.join(packageDir, esmExportPath));
64
- return normalizePath(resolvedEntry);
37
+ const resolverPath = pathToFileURL(createRequire(__filename).resolve('import-meta-resolve')).href;
38
+ const { moduleResolve } = await dynamicImport(resolverPath);
39
+ return normalizePath(moduleResolve(entry, pathToFileURL(`${__dirname}/`), conditions, false).pathname.replace(/^\/(\w):/, '$1:'));
65
40
  } catch (err) {}
66
41
  };
67
42
  export { getProjectUsage, getTemplatePath, normalizePath, readTemplate, resolveESMDependency };
@@ -1,4 +1,78 @@
1
- import { createAppBaselineConfig, withAppBaseline } from "./baseline.mjs";
2
- const createPresetUltramodernConfig = (options = {})=>createAppBaselineConfig(options);
3
- const presetUltramodern = (config, options = {})=>withAppBaseline(config, options);
1
+ import { createRequire } from "node:module";
2
+ import node_path from "node:path";
3
+ import { mergeConfig } from "@modern-js/plugin/cli";
4
+ const DEFAULT_OTLP_ENDPOINT = 'http://127.0.0.1:4318/v1/logs';
5
+ const DEFAULT_VICTORIA_METRICS_ENDPOINT = 'http://127.0.0.1:8428/api/v1/import/prometheus';
6
+ const resolveReactRouterPackageDir = (appDirectory)=>{
7
+ const localRequire = createRequire(node_path.join(appDirectory, 'package.json'));
8
+ try {
9
+ const reactRouterDomPackageJson = localRequire.resolve('react-router-dom/package.json', {
10
+ paths: [
11
+ appDirectory
12
+ ]
13
+ });
14
+ const reactRouterPackageJson = localRequire.resolve('react-router/package.json', {
15
+ paths: [
16
+ node_path.dirname(reactRouterDomPackageJson)
17
+ ]
18
+ });
19
+ return node_path.dirname(reactRouterPackageJson);
20
+ } catch {
21
+ return;
22
+ }
23
+ };
24
+ const setReactRouterBridgeSafeAliases = (chain, { isProd })=>{
25
+ const chainContext = chain.get('context');
26
+ const appDirectory = 'string' == typeof chainContext && chainContext.length > 0 ? chainContext : process.cwd();
27
+ const reactRouterPackageDir = resolveReactRouterPackageDir(appDirectory);
28
+ if (!reactRouterPackageDir) return;
29
+ const productionEntry = node_path.join(reactRouterPackageDir, 'dist/production/index.mjs');
30
+ const developmentEntry = node_path.join(reactRouterPackageDir, 'dist/development/index.mjs');
31
+ chain.resolve.alias.set('react-router$', isProd ? productionEntry : developmentEntry);
32
+ chain.resolve.alias.set('react-router/dist/production/index.js', productionEntry);
33
+ chain.resolve.alias.set('react-router/dist/development/index.js', developmentEntry);
34
+ };
35
+ const createPresetUltramodernConfig = (options = {})=>{
36
+ const { appId = 'app', enableBffRequestId = true, enableTelemetry = true, enableTelemetryExporters, otlpEndpoint = process.env.MODERN_TELEMETRY_OTLP_ENDPOINT, victoriaMetricsEndpoint = process.env.MODERN_TELEMETRY_VICTORIA_ENDPOINT, telemetryFailLoudStartup = true, enableModuleFederationSSR = true } = options;
37
+ const server = {};
38
+ if (enableTelemetry) {
39
+ server.telemetry = {
40
+ enabled: true,
41
+ failLoudStartup: telemetryFailLoudStartup
42
+ };
43
+ if (false !== enableTelemetryExporters) {
44
+ const exporters = {};
45
+ if (true === enableTelemetryExporters || otlpEndpoint) exporters.otlp = {
46
+ enabled: true,
47
+ endpoint: otlpEndpoint || DEFAULT_OTLP_ENDPOINT
48
+ };
49
+ if (true === enableTelemetryExporters || victoriaMetricsEndpoint) exporters.victoriaMetrics = {
50
+ enabled: true,
51
+ endpoint: victoriaMetricsEndpoint || DEFAULT_VICTORIA_METRICS_ENDPOINT
52
+ };
53
+ if (Object.keys(exporters).length > 0) server.telemetry.exporters = exporters;
54
+ }
55
+ }
56
+ if (enableModuleFederationSSR) server.ssr = {
57
+ mode: 'stream',
58
+ moduleFederationAppSSR: true
59
+ };
60
+ const presetConfig = {
61
+ output: {
62
+ precompress: true
63
+ },
64
+ server,
65
+ tools: {
66
+ bundlerChain: setReactRouterBridgeSafeAliases
67
+ }
68
+ };
69
+ if (enableBffRequestId) presetConfig.bff = {
70
+ requestId: appId
71
+ };
72
+ return presetConfig;
73
+ };
74
+ const presetUltramodern = (config, options = {})=>mergeConfig([
75
+ createPresetUltramodernConfig(options),
76
+ config
77
+ ]);
4
78
  export { createPresetUltramodernConfig, presetUltramodern };