@bleedingdev/modern-js-app-tools 3.2.0-ultramodern.62 → 3.2.0-ultramodern.64

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.
@@ -51,9 +51,19 @@ const JS_OR_TS_EXTS = [
51
51
  '.mjs',
52
52
  '.cjs'
53
53
  ];
54
+ const CLOUDFLARE_WORKER_COMPAT_TEMPLATE_DIR = external_node_path_default().resolve(__dirname, '../../plugins/deploy/platforms/templates');
54
55
  function findExistingFile(candidates) {
55
56
  return candidates.find((candidate)=>external_node_fs_default().existsSync(candidate));
56
57
  }
58
+ function resolvePackageEntry(packageName, paths) {
59
+ try {
60
+ return external_node_fs_default().realpathSync(require.resolve(packageName, {
61
+ paths
62
+ }));
63
+ } catch {
64
+ return;
65
+ }
66
+ }
57
67
  function resolvePackageFile(packageName, filePath, paths) {
58
68
  try {
59
69
  const packageJsonPath = require.resolve(`${packageName}/package.json`, {
@@ -68,12 +78,18 @@ function resolvePackageFile(packageName, filePath, paths) {
68
78
  function setAliasIfPresent(alias, name, value) {
69
79
  if (value) alias.set(name, value);
70
80
  }
81
+ function getCloudflareWorkerCompatFile(file) {
82
+ return external_node_path_default().join(CLOUDFLARE_WORKER_COMPAT_TEMPLATE_DIR, file);
83
+ }
71
84
  function getEffectBffEntry(normalizedConfig, appContext) {
72
85
  if (!normalizedConfig.bff || 'hono' === normalizedConfig.bff.runtimeFramework) return;
73
86
  const configuredEntry = normalizedConfig.bff.effect?.entry;
74
87
  const entryWithoutExtension = configuredEntry ? external_node_path_default().isAbsolute(configuredEntry) ? configuredEntry : external_node_path_default().resolve(appContext.appDirectory, configuredEntry) : external_node_path_default().resolve(appContext.apiDirectory, 'effect', 'index');
75
88
  return findExistingFile(JS_OR_TS_EXTS.map((extension)=>`${entryWithoutExtension}${extension}`));
76
89
  }
90
+ function isCloudflareWorkerDeploy(normalizedConfig) {
91
+ return normalizedConfig.deploy?.target === 'cloudflare' || 'cloudflare' === process.env.MODERNJS_DEPLOY;
92
+ }
77
93
  function getBuilderEnvironments(normalizedConfig, appContext, tempBuilderConfig) {
78
94
  const entries = {};
79
95
  const { entrypoints = [], checkedEntries } = appContext;
@@ -120,7 +136,7 @@ function getBuilderEnvironments(normalizedConfig, appContext, tempBuilderConfig)
120
136
  };
121
137
  const useWorkerTarget = (0, utils_namespaceObject.isServiceWorker)(normalizedConfig);
122
138
  if (useWorkerTarget) {
123
- const useCloudflareModuleWorker = normalizedConfig.deploy?.target === 'cloudflare';
139
+ const useCloudflareModuleWorker = isCloudflareWorkerDeploy(normalizedConfig);
124
140
  const effectBffEntry = useCloudflareModuleWorker ? getEffectBffEntry(normalizedConfig, appContext) : void 0;
125
141
  const tanstackRouterSsrServerFile = useCloudflareModuleWorker ? resolvePackageFile('@tanstack/router-core', 'dist/esm/ssr/ssr-server.js', [
126
142
  appContext.appDirectory,
@@ -154,6 +170,14 @@ function getBuilderEnvironments(normalizedConfig, appContext, tempBuilderConfig)
154
170
  appContext.appDirectory,
155
171
  process.cwd()
156
172
  ]) : void 0;
173
+ const loadableComponentFile = useCloudflareModuleWorker ? resolvePackageEntry('@loadable/component', [
174
+ appContext.appDirectory,
175
+ process.cwd(),
176
+ CLOUDFLARE_WORKER_COMPAT_TEMPLATE_DIR
177
+ ]) : void 0;
178
+ const loadableServerWorkerFile = useCloudflareModuleWorker ? getCloudflareWorkerCompatFile('cloudflare-worker-loadable-server.mjs') : void 0;
179
+ const fsPromisesWorkerFile = useCloudflareModuleWorker ? getCloudflareWorkerCompatFile('cloudflare-worker-fs-promises.mjs') : void 0;
180
+ const pathWorkerFile = useCloudflareModuleWorker ? getCloudflareWorkerCompatFile('cloudflare-worker-path.mjs') : void 0;
157
181
  const baseWorkerEntries = useCloudflareModuleWorker ? cloudflareWorkerServerEntries : serverEntries;
158
182
  const workerEntries = effectBffEntry ? {
159
183
  ...baseWorkerEntries,
@@ -200,12 +224,20 @@ function getBuilderEnvironments(normalizedConfig, appContext, tempBuilderConfig)
200
224
  setAliasIfPresent(chain.resolve.alias, 'react/jsx-dev-runtime$', reactJsxDevRuntimeFile);
201
225
  setAliasIfPresent(chain.resolve.alias, 'react-dom$', reactDomFile);
202
226
  setAliasIfPresent(chain.resolve.alias, 'react-dom/server.edge$', reactDomServerEdgeFile);
227
+ setAliasIfPresent(chain.resolve.alias, '@loadable/component$', loadableComponentFile);
228
+ setAliasIfPresent(chain.resolve.alias, '@loadable/server$', loadableServerWorkerFile);
229
+ setAliasIfPresent(chain.resolve.alias, 'fs/promises$', fsPromisesWorkerFile);
230
+ setAliasIfPresent(chain.resolve.alias, 'node:fs/promises$', fsPromisesWorkerFile);
231
+ setAliasIfPresent(chain.resolve.alias, 'path$', pathWorkerFile);
232
+ setAliasIfPresent(chain.resolve.alias, 'node:path$', pathWorkerFile);
203
233
  chain.resolve.alias.set('react-server-dom-rspack/server.node$', 'react-server-dom-rspack/server.edge');
204
234
  chain.resolve.alias.set('react-server-dom-rspack/server.node', 'react-server-dom-rspack/server.edge');
205
235
  chain.resolve.alias.set('react-server-dom-rspack/client.node$', 'react-server-dom-rspack/client.edge');
206
236
  chain.resolve.alias.set('react-server-dom-rspack/client.node', 'react-server-dom-rspack/client.edge');
207
237
  chain.resolve.fallback.set('async_hooks', false);
208
238
  chain.resolve.fallback.set('node:async_hooks', false);
239
+ chain.resolve.fallback.set('fs', false);
240
+ chain.resolve.fallback.set('node:fs', false);
209
241
  }
210
242
  } : {}
211
243
  }
@@ -0,0 +1,7 @@
1
+ const unavailable = (method)=>async ()=>{
2
+ throw new Error(`node:fs/promises.${method} is unavailable in Cloudflare Worker SSR`);
3
+ };
4
+ export const readFile = unavailable('readFile');
5
+ export default {
6
+ readFile
7
+ };
@@ -0,0 +1,185 @@
1
+ import loadableComponent from '@loadable/component';
2
+ import React from 'react';
3
+ const internals = loadableComponent?.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED || {};
4
+ const LoadableContext = internals.Context || React.createContext(null);
5
+ const getRequiredChunkKey = internals.getRequiredChunkKey || ((namespace)=>`${namespace}__LOADABLE_REQUIRED_CHUNKS__`);
6
+ const scriptExtensions = new Set([
7
+ '.js',
8
+ '.mjs'
9
+ ]);
10
+ const styleExtensions = new Set([
11
+ '.css'
12
+ ]);
13
+ function uniqByUrl(assets) {
14
+ const seen = new Set();
15
+ return assets.filter((asset)=>{
16
+ if (seen.has(asset.url)) return false;
17
+ seen.add(asset.url);
18
+ return true;
19
+ });
20
+ }
21
+ function extname(filePath) {
22
+ const basename = String(filePath).split('/').pop() || '';
23
+ const index = basename.lastIndexOf('.');
24
+ return index > 0 ? basename.slice(index) : '';
25
+ }
26
+ function joinUrl(publicPath, filename) {
27
+ const base = publicPath || '/';
28
+ return `${base.replace(/\/+$/u, '')}/${String(filename).replace(/^\/+/u, '')}`;
29
+ }
30
+ function extraPropsToString(extraProps = {}) {
31
+ return Object.entries(extraProps).filter(([, value])=>void 0 !== value && false !== value).map(([key, value])=>true === value ? ` ${key}` : ` ${key}="${value}"`).join('');
32
+ }
33
+ function assetScriptType(filename) {
34
+ const extension = extname(filename);
35
+ if (scriptExtensions.has(extension)) return "script";
36
+ if (styleExtensions.has(extension)) return 'style';
37
+ }
38
+ function getAssetName(asset) {
39
+ return 'object' == typeof asset && asset?.name ? asset.name : asset;
40
+ }
41
+ function getAssetIntegrity(asset) {
42
+ return 'object' == typeof asset && asset?.integrity ? asset.integrity : null;
43
+ }
44
+ function getChunkGroupAssets(chunkGroup) {
45
+ const assets = chunkGroup?.assets;
46
+ if (Array.isArray(assets)) return assets;
47
+ if (assets && 'object' == typeof assets) return [
48
+ ...assets.js || [],
49
+ ...assets.css || []
50
+ ];
51
+ return [];
52
+ }
53
+ function getChunkGroupChildAssets(chunkGroup, type) {
54
+ const childAssets = chunkGroup?.childAssets?.[type];
55
+ return Array.isArray(childAssets) ? childAssets : [];
56
+ }
57
+ function chunkIncludesJs(chunkInfo) {
58
+ return (chunkInfo?.files || []).some((file)=>scriptExtensions.has(extname(file)));
59
+ }
60
+ export function ChunkExtractorManager({ extractor, children }) {
61
+ return React.createElement(LoadableContext.Provider, {
62
+ value: extractor
63
+ }, children);
64
+ }
65
+ export class ChunkExtractor {
66
+ constructor({ stats, entrypoints = [
67
+ 'main'
68
+ ], namespace = '', outputPath = '/', publicPath } = {}){
69
+ this.namespace = namespace;
70
+ this.stats = stats || {};
71
+ this.publicPath = publicPath || this.stats.publicPath || '/';
72
+ this.outputPath = outputPath || this.stats.outputPath || '/';
73
+ this.entrypoints = Array.isArray(entrypoints) ? entrypoints : [
74
+ entrypoints
75
+ ];
76
+ this.chunks = [];
77
+ }
78
+ addChunk(chunk) {
79
+ if (!this.chunks.includes(chunk)) this.chunks.push(chunk);
80
+ }
81
+ collectChunks(app) {
82
+ return React.createElement(ChunkExtractorManager, {
83
+ extractor: this
84
+ }, app);
85
+ }
86
+ getChunkGroup(chunk) {
87
+ return this.stats.namedChunkGroups?.[chunk] || {
88
+ assets: [],
89
+ childAssets: {},
90
+ chunks: []
91
+ };
92
+ }
93
+ getChunkInfo(chunkId) {
94
+ return (this.stats.chunks || []).find((chunk)=>chunk.id === chunkId);
95
+ }
96
+ resolvePublicUrl(filename) {
97
+ return joinUrl(this.publicPath, filename);
98
+ }
99
+ createChunkAsset({ filename, chunk, type, linkType }) {
100
+ const resolvedFilename = getAssetName(filename);
101
+ const scriptType = assetScriptType(resolvedFilename);
102
+ if (!scriptType) return;
103
+ return {
104
+ filename: resolvedFilename,
105
+ integrity: getAssetIntegrity(filename),
106
+ scriptType,
107
+ chunk,
108
+ url: this.resolvePublicUrl(resolvedFilename),
109
+ path: String(resolvedFilename).replace(/^\/+/u, ''),
110
+ type,
111
+ linkType
112
+ };
113
+ }
114
+ getChunkAssets(chunks) {
115
+ const one = (chunk)=>getChunkGroupAssets(this.getChunkGroup(chunk)).map((filename)=>this.createChunkAsset({
116
+ filename,
117
+ chunk,
118
+ type: 'mainAsset',
119
+ linkType: 'preload'
120
+ })).filter(Boolean);
121
+ return Array.isArray(chunks) ? uniqByUrl(chunks.flatMap(one)) : one(chunks);
122
+ }
123
+ getChunkChildAssets(chunks, type) {
124
+ const one = (chunk)=>getChunkGroupChildAssets(this.getChunkGroup(chunk), type).map((filename)=>this.createChunkAsset({
125
+ filename,
126
+ chunk,
127
+ type: 'childAsset',
128
+ linkType: type
129
+ })).filter(Boolean);
130
+ return Array.isArray(chunks) ? uniqByUrl(chunks.flatMap(one)) : one(chunks);
131
+ }
132
+ getChunkDependencies(chunks) {
133
+ const one = (chunk)=>(this.getChunkGroup(chunk).chunks || []).filter((chunkId)=>chunkIncludesJs(this.getChunkInfo(chunkId)));
134
+ return Array.isArray(chunks) ? [
135
+ ...new Set(chunks.flatMap(one))
136
+ ] : one(chunks);
137
+ }
138
+ getRequiredChunksScriptContent() {
139
+ return JSON.stringify(this.getChunkDependencies(this.chunks));
140
+ }
141
+ getRequiredChunksNamesScriptContent() {
142
+ return JSON.stringify({
143
+ namedChunks: this.chunks
144
+ });
145
+ }
146
+ getRequiredChunksScriptTag(extraProps = {}) {
147
+ const id = getRequiredChunkKey(this.namespace);
148
+ const props = `type="application/json"${extraPropsToString(extraProps)}`;
149
+ return [
150
+ `<script id="${id}" ${props}>${this.getRequiredChunksScriptContent()}</script>`,
151
+ `<script id="${id}_ext" ${props}>${this.getRequiredChunksNamesScriptContent()}</script>`
152
+ ].join('');
153
+ }
154
+ getMainAssets(scriptType) {
155
+ const assets = this.getChunkAssets([
156
+ ...this.entrypoints,
157
+ ...this.chunks
158
+ ]);
159
+ return scriptType ? assets.filter((asset)=>asset.scriptType === scriptType) : assets;
160
+ }
161
+ getScriptTags(extraProps = {}) {
162
+ const scripts = this.getMainAssets("script").map((asset)=>`<script async data-chunk="${asset.chunk}" src="${asset.url}"${extraPropsToString(extraProps)}></script>`);
163
+ return [
164
+ this.getRequiredChunksScriptTag(extraProps),
165
+ ...scripts
166
+ ].join('');
167
+ }
168
+ getStyleTags(extraProps = {}) {
169
+ return this.getMainAssets('style').map((asset)=>`<link data-chunk="${asset.chunk}" rel="stylesheet" href="${asset.url}"${extraPropsToString(extraProps)}>`).join('');
170
+ }
171
+ getLinkTags(extraProps = {}) {
172
+ const assets = [
173
+ ...this.getMainAssets(),
174
+ ...this.getChunkChildAssets([
175
+ ...this.entrypoints,
176
+ ...this.chunks
177
+ ], 'preload'),
178
+ ...this.getChunkChildAssets([
179
+ ...this.entrypoints,
180
+ ...this.chunks
181
+ ], 'prefetch')
182
+ ];
183
+ return uniqByUrl(assets).map((asset)=>`<link data-chunk="${asset.chunk}" rel="${asset.linkType}" as="${asset.scriptType}" href="${asset.url}"${extraPropsToString(extraProps)}>`).join('');
184
+ }
185
+ }
@@ -0,0 +1,59 @@
1
+ const trimSlashes = (value)=>String(value).replace(/^\/+|\/+$/gu, '');
2
+ const normalizeSeparators = (value)=>String(value).replace(/\\+/gu, '/');
3
+ export const sep = '/';
4
+ export const delimiter = ':';
5
+ export function isAbsolute(filePath) {
6
+ return normalizeSeparators(filePath).startsWith('/');
7
+ }
8
+ export function normalize(filePath) {
9
+ const normalized = normalizeSeparators(filePath);
10
+ const absolute = isAbsolute(normalized);
11
+ const parts = [];
12
+ for (const part of normalized.split('/'))if (part && '.' !== part) {
13
+ if ('..' === part) {
14
+ if (parts.length > 0 && '..' !== parts[parts.length - 1]) parts.pop();
15
+ else if (!absolute) parts.push(part);
16
+ continue;
17
+ }
18
+ parts.push(part);
19
+ }
20
+ const joined = parts.join('/');
21
+ if (absolute) return joined ? `/${joined}` : '/';
22
+ return joined || '.';
23
+ }
24
+ export function join(...segments) {
25
+ const joined = segments.map(normalizeSeparators).filter(Boolean).map((segment, index)=>0 === index ? segment : trimSlashes(segment)).filter(Boolean).join('/');
26
+ return joined ? normalize(joined) : '.';
27
+ }
28
+ export function resolve(...segments) {
29
+ const joined = join(...segments);
30
+ return joined.startsWith('/') ? joined : `/${joined}`;
31
+ }
32
+ export function dirname(filePath) {
33
+ const normalized = normalizeSeparators(filePath).replace(/\/+$/u, '');
34
+ const index = normalized.lastIndexOf('/');
35
+ if (index <= 0) return '/';
36
+ return normalized.slice(0, index);
37
+ }
38
+ export function basename(filePath, suffix = '') {
39
+ const normalized = normalizeSeparators(filePath).replace(/\/+$/u, '');
40
+ const base = normalized.slice(normalized.lastIndexOf('/') + 1);
41
+ return suffix && base.endsWith(suffix) ? base.slice(0, -suffix.length) : base;
42
+ }
43
+ export function extname(filePath) {
44
+ const base = basename(filePath);
45
+ const index = base.lastIndexOf('.');
46
+ if (index <= 0) return '';
47
+ return base.slice(index);
48
+ }
49
+ export default {
50
+ basename,
51
+ delimiter,
52
+ dirname,
53
+ extname,
54
+ isAbsolute,
55
+ join,
56
+ normalize,
57
+ resolve,
58
+ sep
59
+ };
@@ -12,9 +12,19 @@ const JS_OR_TS_EXTS = [
12
12
  '.mjs',
13
13
  '.cjs'
14
14
  ];
15
+ const CLOUDFLARE_WORKER_COMPAT_TEMPLATE_DIR = node_path.resolve(__dirname, '../../plugins/deploy/platforms/templates');
15
16
  function findExistingFile(candidates) {
16
17
  return candidates.find((candidate)=>node_fs.existsSync(candidate));
17
18
  }
19
+ function resolvePackageEntry(packageName, paths) {
20
+ try {
21
+ return node_fs.realpathSync(require.resolve(packageName, {
22
+ paths
23
+ }));
24
+ } catch {
25
+ return;
26
+ }
27
+ }
18
28
  function resolvePackageFile(packageName, filePath, paths) {
19
29
  try {
20
30
  const packageJsonPath = require.resolve(`${packageName}/package.json`, {
@@ -29,12 +39,18 @@ function resolvePackageFile(packageName, filePath, paths) {
29
39
  function setAliasIfPresent(alias, name, value) {
30
40
  if (value) alias.set(name, value);
31
41
  }
42
+ function getCloudflareWorkerCompatFile(file) {
43
+ return node_path.join(CLOUDFLARE_WORKER_COMPAT_TEMPLATE_DIR, file);
44
+ }
32
45
  function getEffectBffEntry(normalizedConfig, appContext) {
33
46
  if (!normalizedConfig.bff || 'hono' === normalizedConfig.bff.runtimeFramework) return;
34
47
  const configuredEntry = normalizedConfig.bff.effect?.entry;
35
48
  const entryWithoutExtension = configuredEntry ? node_path.isAbsolute(configuredEntry) ? configuredEntry : node_path.resolve(appContext.appDirectory, configuredEntry) : node_path.resolve(appContext.apiDirectory, 'effect', 'index');
36
49
  return findExistingFile(JS_OR_TS_EXTS.map((extension)=>`${entryWithoutExtension}${extension}`));
37
50
  }
51
+ function isCloudflareWorkerDeploy(normalizedConfig) {
52
+ return normalizedConfig.deploy?.target === 'cloudflare' || 'cloudflare' === process.env.MODERNJS_DEPLOY;
53
+ }
38
54
  function getBuilderEnvironments(normalizedConfig, appContext, tempBuilderConfig) {
39
55
  const entries = {};
40
56
  const { entrypoints = [], checkedEntries } = appContext;
@@ -81,7 +97,7 @@ function getBuilderEnvironments(normalizedConfig, appContext, tempBuilderConfig)
81
97
  };
82
98
  const useWorkerTarget = isServiceWorker(normalizedConfig);
83
99
  if (useWorkerTarget) {
84
- const useCloudflareModuleWorker = normalizedConfig.deploy?.target === 'cloudflare';
100
+ const useCloudflareModuleWorker = isCloudflareWorkerDeploy(normalizedConfig);
85
101
  const effectBffEntry = useCloudflareModuleWorker ? getEffectBffEntry(normalizedConfig, appContext) : void 0;
86
102
  const tanstackRouterSsrServerFile = useCloudflareModuleWorker ? resolvePackageFile('@tanstack/router-core', 'dist/esm/ssr/ssr-server.js', [
87
103
  appContext.appDirectory,
@@ -115,6 +131,14 @@ function getBuilderEnvironments(normalizedConfig, appContext, tempBuilderConfig)
115
131
  appContext.appDirectory,
116
132
  process.cwd()
117
133
  ]) : void 0;
134
+ const loadableComponentFile = useCloudflareModuleWorker ? resolvePackageEntry('@loadable/component', [
135
+ appContext.appDirectory,
136
+ process.cwd(),
137
+ CLOUDFLARE_WORKER_COMPAT_TEMPLATE_DIR
138
+ ]) : void 0;
139
+ const loadableServerWorkerFile = useCloudflareModuleWorker ? getCloudflareWorkerCompatFile('cloudflare-worker-loadable-server.mjs') : void 0;
140
+ const fsPromisesWorkerFile = useCloudflareModuleWorker ? getCloudflareWorkerCompatFile('cloudflare-worker-fs-promises.mjs') : void 0;
141
+ const pathWorkerFile = useCloudflareModuleWorker ? getCloudflareWorkerCompatFile('cloudflare-worker-path.mjs') : void 0;
118
142
  const baseWorkerEntries = useCloudflareModuleWorker ? cloudflareWorkerServerEntries : serverEntries;
119
143
  const workerEntries = effectBffEntry ? {
120
144
  ...baseWorkerEntries,
@@ -161,12 +185,20 @@ function getBuilderEnvironments(normalizedConfig, appContext, tempBuilderConfig)
161
185
  setAliasIfPresent(chain.resolve.alias, 'react/jsx-dev-runtime$', reactJsxDevRuntimeFile);
162
186
  setAliasIfPresent(chain.resolve.alias, 'react-dom$', reactDomFile);
163
187
  setAliasIfPresent(chain.resolve.alias, 'react-dom/server.edge$', reactDomServerEdgeFile);
188
+ setAliasIfPresent(chain.resolve.alias, '@loadable/component$', loadableComponentFile);
189
+ setAliasIfPresent(chain.resolve.alias, '@loadable/server$', loadableServerWorkerFile);
190
+ setAliasIfPresent(chain.resolve.alias, 'fs/promises$', fsPromisesWorkerFile);
191
+ setAliasIfPresent(chain.resolve.alias, 'node:fs/promises$', fsPromisesWorkerFile);
192
+ setAliasIfPresent(chain.resolve.alias, 'path$', pathWorkerFile);
193
+ setAliasIfPresent(chain.resolve.alias, 'node:path$', pathWorkerFile);
164
194
  chain.resolve.alias.set('react-server-dom-rspack/server.node$', 'react-server-dom-rspack/server.edge');
165
195
  chain.resolve.alias.set('react-server-dom-rspack/server.node', 'react-server-dom-rspack/server.edge');
166
196
  chain.resolve.alias.set('react-server-dom-rspack/client.node$', 'react-server-dom-rspack/client.edge');
167
197
  chain.resolve.alias.set('react-server-dom-rspack/client.node', 'react-server-dom-rspack/client.edge');
168
198
  chain.resolve.fallback.set('async_hooks', false);
169
199
  chain.resolve.fallback.set('node:async_hooks', false);
200
+ chain.resolve.fallback.set('fs', false);
201
+ chain.resolve.fallback.set('node:fs', false);
170
202
  }
171
203
  } : {}
172
204
  }
@@ -0,0 +1,7 @@
1
+ const unavailable = (method)=>async ()=>{
2
+ throw new Error(`node:fs/promises.${method} is unavailable in Cloudflare Worker SSR`);
3
+ };
4
+ export const readFile = unavailable('readFile');
5
+ export default {
6
+ readFile
7
+ };
@@ -0,0 +1,185 @@
1
+ import loadableComponent from '@loadable/component';
2
+ import React from 'react';
3
+ const internals = loadableComponent?.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED || {};
4
+ const LoadableContext = internals.Context || React.createContext(null);
5
+ const getRequiredChunkKey = internals.getRequiredChunkKey || ((namespace)=>`${namespace}__LOADABLE_REQUIRED_CHUNKS__`);
6
+ const scriptExtensions = new Set([
7
+ '.js',
8
+ '.mjs'
9
+ ]);
10
+ const styleExtensions = new Set([
11
+ '.css'
12
+ ]);
13
+ function uniqByUrl(assets) {
14
+ const seen = new Set();
15
+ return assets.filter((asset)=>{
16
+ if (seen.has(asset.url)) return false;
17
+ seen.add(asset.url);
18
+ return true;
19
+ });
20
+ }
21
+ function extname(filePath) {
22
+ const basename = String(filePath).split('/').pop() || '';
23
+ const index = basename.lastIndexOf('.');
24
+ return index > 0 ? basename.slice(index) : '';
25
+ }
26
+ function joinUrl(publicPath, filename) {
27
+ const base = publicPath || '/';
28
+ return `${base.replace(/\/+$/u, '')}/${String(filename).replace(/^\/+/u, '')}`;
29
+ }
30
+ function extraPropsToString(extraProps = {}) {
31
+ return Object.entries(extraProps).filter(([, value])=>void 0 !== value && false !== value).map(([key, value])=>true === value ? ` ${key}` : ` ${key}="${value}"`).join('');
32
+ }
33
+ function assetScriptType(filename) {
34
+ const extension = extname(filename);
35
+ if (scriptExtensions.has(extension)) return "script";
36
+ if (styleExtensions.has(extension)) return 'style';
37
+ }
38
+ function getAssetName(asset) {
39
+ return 'object' == typeof asset && asset?.name ? asset.name : asset;
40
+ }
41
+ function getAssetIntegrity(asset) {
42
+ return 'object' == typeof asset && asset?.integrity ? asset.integrity : null;
43
+ }
44
+ function getChunkGroupAssets(chunkGroup) {
45
+ const assets = chunkGroup?.assets;
46
+ if (Array.isArray(assets)) return assets;
47
+ if (assets && 'object' == typeof assets) return [
48
+ ...assets.js || [],
49
+ ...assets.css || []
50
+ ];
51
+ return [];
52
+ }
53
+ function getChunkGroupChildAssets(chunkGroup, type) {
54
+ const childAssets = chunkGroup?.childAssets?.[type];
55
+ return Array.isArray(childAssets) ? childAssets : [];
56
+ }
57
+ function chunkIncludesJs(chunkInfo) {
58
+ return (chunkInfo?.files || []).some((file)=>scriptExtensions.has(extname(file)));
59
+ }
60
+ export function ChunkExtractorManager({ extractor, children }) {
61
+ return React.createElement(LoadableContext.Provider, {
62
+ value: extractor
63
+ }, children);
64
+ }
65
+ export class ChunkExtractor {
66
+ constructor({ stats, entrypoints = [
67
+ 'main'
68
+ ], namespace = '', outputPath = '/', publicPath } = {}){
69
+ this.namespace = namespace;
70
+ this.stats = stats || {};
71
+ this.publicPath = publicPath || this.stats.publicPath || '/';
72
+ this.outputPath = outputPath || this.stats.outputPath || '/';
73
+ this.entrypoints = Array.isArray(entrypoints) ? entrypoints : [
74
+ entrypoints
75
+ ];
76
+ this.chunks = [];
77
+ }
78
+ addChunk(chunk) {
79
+ if (!this.chunks.includes(chunk)) this.chunks.push(chunk);
80
+ }
81
+ collectChunks(app) {
82
+ return React.createElement(ChunkExtractorManager, {
83
+ extractor: this
84
+ }, app);
85
+ }
86
+ getChunkGroup(chunk) {
87
+ return this.stats.namedChunkGroups?.[chunk] || {
88
+ assets: [],
89
+ childAssets: {},
90
+ chunks: []
91
+ };
92
+ }
93
+ getChunkInfo(chunkId) {
94
+ return (this.stats.chunks || []).find((chunk)=>chunk.id === chunkId);
95
+ }
96
+ resolvePublicUrl(filename) {
97
+ return joinUrl(this.publicPath, filename);
98
+ }
99
+ createChunkAsset({ filename, chunk, type, linkType }) {
100
+ const resolvedFilename = getAssetName(filename);
101
+ const scriptType = assetScriptType(resolvedFilename);
102
+ if (!scriptType) return;
103
+ return {
104
+ filename: resolvedFilename,
105
+ integrity: getAssetIntegrity(filename),
106
+ scriptType,
107
+ chunk,
108
+ url: this.resolvePublicUrl(resolvedFilename),
109
+ path: String(resolvedFilename).replace(/^\/+/u, ''),
110
+ type,
111
+ linkType
112
+ };
113
+ }
114
+ getChunkAssets(chunks) {
115
+ const one = (chunk)=>getChunkGroupAssets(this.getChunkGroup(chunk)).map((filename)=>this.createChunkAsset({
116
+ filename,
117
+ chunk,
118
+ type: 'mainAsset',
119
+ linkType: 'preload'
120
+ })).filter(Boolean);
121
+ return Array.isArray(chunks) ? uniqByUrl(chunks.flatMap(one)) : one(chunks);
122
+ }
123
+ getChunkChildAssets(chunks, type) {
124
+ const one = (chunk)=>getChunkGroupChildAssets(this.getChunkGroup(chunk), type).map((filename)=>this.createChunkAsset({
125
+ filename,
126
+ chunk,
127
+ type: 'childAsset',
128
+ linkType: type
129
+ })).filter(Boolean);
130
+ return Array.isArray(chunks) ? uniqByUrl(chunks.flatMap(one)) : one(chunks);
131
+ }
132
+ getChunkDependencies(chunks) {
133
+ const one = (chunk)=>(this.getChunkGroup(chunk).chunks || []).filter((chunkId)=>chunkIncludesJs(this.getChunkInfo(chunkId)));
134
+ return Array.isArray(chunks) ? [
135
+ ...new Set(chunks.flatMap(one))
136
+ ] : one(chunks);
137
+ }
138
+ getRequiredChunksScriptContent() {
139
+ return JSON.stringify(this.getChunkDependencies(this.chunks));
140
+ }
141
+ getRequiredChunksNamesScriptContent() {
142
+ return JSON.stringify({
143
+ namedChunks: this.chunks
144
+ });
145
+ }
146
+ getRequiredChunksScriptTag(extraProps = {}) {
147
+ const id = getRequiredChunkKey(this.namespace);
148
+ const props = `type="application/json"${extraPropsToString(extraProps)}`;
149
+ return [
150
+ `<script id="${id}" ${props}>${this.getRequiredChunksScriptContent()}</script>`,
151
+ `<script id="${id}_ext" ${props}>${this.getRequiredChunksNamesScriptContent()}</script>`
152
+ ].join('');
153
+ }
154
+ getMainAssets(scriptType) {
155
+ const assets = this.getChunkAssets([
156
+ ...this.entrypoints,
157
+ ...this.chunks
158
+ ]);
159
+ return scriptType ? assets.filter((asset)=>asset.scriptType === scriptType) : assets;
160
+ }
161
+ getScriptTags(extraProps = {}) {
162
+ const scripts = this.getMainAssets("script").map((asset)=>`<script async data-chunk="${asset.chunk}" src="${asset.url}"${extraPropsToString(extraProps)}></script>`);
163
+ return [
164
+ this.getRequiredChunksScriptTag(extraProps),
165
+ ...scripts
166
+ ].join('');
167
+ }
168
+ getStyleTags(extraProps = {}) {
169
+ return this.getMainAssets('style').map((asset)=>`<link data-chunk="${asset.chunk}" rel="stylesheet" href="${asset.url}"${extraPropsToString(extraProps)}>`).join('');
170
+ }
171
+ getLinkTags(extraProps = {}) {
172
+ const assets = [
173
+ ...this.getMainAssets(),
174
+ ...this.getChunkChildAssets([
175
+ ...this.entrypoints,
176
+ ...this.chunks
177
+ ], 'preload'),
178
+ ...this.getChunkChildAssets([
179
+ ...this.entrypoints,
180
+ ...this.chunks
181
+ ], 'prefetch')
182
+ ];
183
+ return uniqByUrl(assets).map((asset)=>`<link data-chunk="${asset.chunk}" rel="${asset.linkType}" as="${asset.scriptType}" href="${asset.url}"${extraPropsToString(extraProps)}>`).join('');
184
+ }
185
+ }
@@ -0,0 +1,59 @@
1
+ const trimSlashes = (value)=>String(value).replace(/^\/+|\/+$/gu, '');
2
+ const normalizeSeparators = (value)=>String(value).replace(/\\+/gu, '/');
3
+ export const sep = '/';
4
+ export const delimiter = ':';
5
+ export function isAbsolute(filePath) {
6
+ return normalizeSeparators(filePath).startsWith('/');
7
+ }
8
+ export function normalize(filePath) {
9
+ const normalized = normalizeSeparators(filePath);
10
+ const absolute = isAbsolute(normalized);
11
+ const parts = [];
12
+ for (const part of normalized.split('/'))if (part && '.' !== part) {
13
+ if ('..' === part) {
14
+ if (parts.length > 0 && '..' !== parts[parts.length - 1]) parts.pop();
15
+ else if (!absolute) parts.push(part);
16
+ continue;
17
+ }
18
+ parts.push(part);
19
+ }
20
+ const joined = parts.join('/');
21
+ if (absolute) return joined ? `/${joined}` : '/';
22
+ return joined || '.';
23
+ }
24
+ export function join(...segments) {
25
+ const joined = segments.map(normalizeSeparators).filter(Boolean).map((segment, index)=>0 === index ? segment : trimSlashes(segment)).filter(Boolean).join('/');
26
+ return joined ? normalize(joined) : '.';
27
+ }
28
+ export function resolve(...segments) {
29
+ const joined = join(...segments);
30
+ return joined.startsWith('/') ? joined : `/${joined}`;
31
+ }
32
+ export function dirname(filePath) {
33
+ const normalized = normalizeSeparators(filePath).replace(/\/+$/u, '');
34
+ const index = normalized.lastIndexOf('/');
35
+ if (index <= 0) return '/';
36
+ return normalized.slice(0, index);
37
+ }
38
+ export function basename(filePath, suffix = '') {
39
+ const normalized = normalizeSeparators(filePath).replace(/\/+$/u, '');
40
+ const base = normalized.slice(normalized.lastIndexOf('/') + 1);
41
+ return suffix && base.endsWith(suffix) ? base.slice(0, -suffix.length) : base;
42
+ }
43
+ export function extname(filePath) {
44
+ const base = basename(filePath);
45
+ const index = base.lastIndexOf('.');
46
+ if (index <= 0) return '';
47
+ return base.slice(index);
48
+ }
49
+ export default {
50
+ basename,
51
+ delimiter,
52
+ dirname,
53
+ extname,
54
+ isAbsolute,
55
+ join,
56
+ normalize,
57
+ resolve,
58
+ sep
59
+ };
@@ -4,6 +4,9 @@ import node_fs from "node:fs";
4
4
  import node_path from "node:path";
5
5
  import { SERVICE_WORKER_ENVIRONMENT_NAME } from "@modern-js/builder";
6
6
  import { isProd, isSSR, isServiceWorker, isUseRsc, isUseSSRBundle } from "@modern-js/utils";
7
+ import { fileURLToPath as __rspack_fileURLToPath } from "node:url";
8
+ import { dirname as __rspack_dirname } from "node:path";
9
+ var getBuilderEnvironments_dirname = __rspack_dirname(__rspack_fileURLToPath(import.meta.url));
7
10
  const BFF_EFFECT_WORKER_ENTRY_NAME = '__modern_bff_effect';
8
11
  const BFF_EFFECT_WORKER_RUNTIME_QUERY = 'modern-bff-runtime';
9
12
  const JS_OR_TS_EXTS = [
@@ -14,9 +17,19 @@ const JS_OR_TS_EXTS = [
14
17
  '.mjs',
15
18
  '.cjs'
16
19
  ];
20
+ const CLOUDFLARE_WORKER_COMPAT_TEMPLATE_DIR = node_path.resolve(getBuilderEnvironments_dirname, '../../plugins/deploy/platforms/templates');
17
21
  function findExistingFile(candidates) {
18
22
  return candidates.find((candidate)=>node_fs.existsSync(candidate));
19
23
  }
24
+ function resolvePackageEntry(packageName, paths) {
25
+ try {
26
+ return node_fs.realpathSync(require.resolve(packageName, {
27
+ paths
28
+ }));
29
+ } catch {
30
+ return;
31
+ }
32
+ }
20
33
  function resolvePackageFile(packageName, filePath, paths) {
21
34
  try {
22
35
  const packageJsonPath = require.resolve(`${packageName}/package.json`, {
@@ -31,12 +44,18 @@ function resolvePackageFile(packageName, filePath, paths) {
31
44
  function setAliasIfPresent(alias, name, value) {
32
45
  if (value) alias.set(name, value);
33
46
  }
47
+ function getCloudflareWorkerCompatFile(file) {
48
+ return node_path.join(CLOUDFLARE_WORKER_COMPAT_TEMPLATE_DIR, file);
49
+ }
34
50
  function getEffectBffEntry(normalizedConfig, appContext) {
35
51
  if (!normalizedConfig.bff || 'hono' === normalizedConfig.bff.runtimeFramework) return;
36
52
  const configuredEntry = normalizedConfig.bff.effect?.entry;
37
53
  const entryWithoutExtension = configuredEntry ? node_path.isAbsolute(configuredEntry) ? configuredEntry : node_path.resolve(appContext.appDirectory, configuredEntry) : node_path.resolve(appContext.apiDirectory, 'effect', 'index');
38
54
  return findExistingFile(JS_OR_TS_EXTS.map((extension)=>`${entryWithoutExtension}${extension}`));
39
55
  }
56
+ function isCloudflareWorkerDeploy(normalizedConfig) {
57
+ return normalizedConfig.deploy?.target === 'cloudflare' || 'cloudflare' === process.env.MODERNJS_DEPLOY;
58
+ }
40
59
  function getBuilderEnvironments(normalizedConfig, appContext, tempBuilderConfig) {
41
60
  const entries = {};
42
61
  const { entrypoints = [], checkedEntries } = appContext;
@@ -83,7 +102,7 @@ function getBuilderEnvironments(normalizedConfig, appContext, tempBuilderConfig)
83
102
  };
84
103
  const useWorkerTarget = isServiceWorker(normalizedConfig);
85
104
  if (useWorkerTarget) {
86
- const useCloudflareModuleWorker = normalizedConfig.deploy?.target === 'cloudflare';
105
+ const useCloudflareModuleWorker = isCloudflareWorkerDeploy(normalizedConfig);
87
106
  const effectBffEntry = useCloudflareModuleWorker ? getEffectBffEntry(normalizedConfig, appContext) : void 0;
88
107
  const tanstackRouterSsrServerFile = useCloudflareModuleWorker ? resolvePackageFile('@tanstack/router-core', 'dist/esm/ssr/ssr-server.js', [
89
108
  appContext.appDirectory,
@@ -117,6 +136,14 @@ function getBuilderEnvironments(normalizedConfig, appContext, tempBuilderConfig)
117
136
  appContext.appDirectory,
118
137
  process.cwd()
119
138
  ]) : void 0;
139
+ const loadableComponentFile = useCloudflareModuleWorker ? resolvePackageEntry('@loadable/component', [
140
+ appContext.appDirectory,
141
+ process.cwd(),
142
+ CLOUDFLARE_WORKER_COMPAT_TEMPLATE_DIR
143
+ ]) : void 0;
144
+ const loadableServerWorkerFile = useCloudflareModuleWorker ? getCloudflareWorkerCompatFile('cloudflare-worker-loadable-server.mjs') : void 0;
145
+ const fsPromisesWorkerFile = useCloudflareModuleWorker ? getCloudflareWorkerCompatFile('cloudflare-worker-fs-promises.mjs') : void 0;
146
+ const pathWorkerFile = useCloudflareModuleWorker ? getCloudflareWorkerCompatFile('cloudflare-worker-path.mjs') : void 0;
120
147
  const baseWorkerEntries = useCloudflareModuleWorker ? cloudflareWorkerServerEntries : serverEntries;
121
148
  const workerEntries = effectBffEntry ? {
122
149
  ...baseWorkerEntries,
@@ -163,12 +190,20 @@ function getBuilderEnvironments(normalizedConfig, appContext, tempBuilderConfig)
163
190
  setAliasIfPresent(chain.resolve.alias, 'react/jsx-dev-runtime$', reactJsxDevRuntimeFile);
164
191
  setAliasIfPresent(chain.resolve.alias, 'react-dom$', reactDomFile);
165
192
  setAliasIfPresent(chain.resolve.alias, 'react-dom/server.edge$', reactDomServerEdgeFile);
193
+ setAliasIfPresent(chain.resolve.alias, '@loadable/component$', loadableComponentFile);
194
+ setAliasIfPresent(chain.resolve.alias, '@loadable/server$', loadableServerWorkerFile);
195
+ setAliasIfPresent(chain.resolve.alias, 'fs/promises$', fsPromisesWorkerFile);
196
+ setAliasIfPresent(chain.resolve.alias, 'node:fs/promises$', fsPromisesWorkerFile);
197
+ setAliasIfPresent(chain.resolve.alias, 'path$', pathWorkerFile);
198
+ setAliasIfPresent(chain.resolve.alias, 'node:path$', pathWorkerFile);
166
199
  chain.resolve.alias.set('react-server-dom-rspack/server.node$', 'react-server-dom-rspack/server.edge');
167
200
  chain.resolve.alias.set('react-server-dom-rspack/server.node', 'react-server-dom-rspack/server.edge');
168
201
  chain.resolve.alias.set('react-server-dom-rspack/client.node$', 'react-server-dom-rspack/client.edge');
169
202
  chain.resolve.alias.set('react-server-dom-rspack/client.node', 'react-server-dom-rspack/client.edge');
170
203
  chain.resolve.fallback.set('async_hooks', false);
171
204
  chain.resolve.fallback.set('node:async_hooks', false);
205
+ chain.resolve.fallback.set('fs', false);
206
+ chain.resolve.fallback.set('node:fs', false);
172
207
  }
173
208
  } : {}
174
209
  }
@@ -0,0 +1,7 @@
1
+ const unavailable = (method)=>async ()=>{
2
+ throw new Error(`node:fs/promises.${method} is unavailable in Cloudflare Worker SSR`);
3
+ };
4
+ export const readFile = unavailable('readFile');
5
+ export default {
6
+ readFile
7
+ };
@@ -0,0 +1,185 @@
1
+ import loadableComponent from '@loadable/component';
2
+ import React from 'react';
3
+ const internals = loadableComponent?.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED || {};
4
+ const LoadableContext = internals.Context || React.createContext(null);
5
+ const getRequiredChunkKey = internals.getRequiredChunkKey || ((namespace)=>`${namespace}__LOADABLE_REQUIRED_CHUNKS__`);
6
+ const scriptExtensions = new Set([
7
+ '.js',
8
+ '.mjs'
9
+ ]);
10
+ const styleExtensions = new Set([
11
+ '.css'
12
+ ]);
13
+ function uniqByUrl(assets) {
14
+ const seen = new Set();
15
+ return assets.filter((asset)=>{
16
+ if (seen.has(asset.url)) return false;
17
+ seen.add(asset.url);
18
+ return true;
19
+ });
20
+ }
21
+ function extname(filePath) {
22
+ const basename = String(filePath).split('/').pop() || '';
23
+ const index = basename.lastIndexOf('.');
24
+ return index > 0 ? basename.slice(index) : '';
25
+ }
26
+ function joinUrl(publicPath, filename) {
27
+ const base = publicPath || '/';
28
+ return `${base.replace(/\/+$/u, '')}/${String(filename).replace(/^\/+/u, '')}`;
29
+ }
30
+ function extraPropsToString(extraProps = {}) {
31
+ return Object.entries(extraProps).filter(([, value])=>void 0 !== value && false !== value).map(([key, value])=>true === value ? ` ${key}` : ` ${key}="${value}"`).join('');
32
+ }
33
+ function assetScriptType(filename) {
34
+ const extension = extname(filename);
35
+ if (scriptExtensions.has(extension)) return "script";
36
+ if (styleExtensions.has(extension)) return 'style';
37
+ }
38
+ function getAssetName(asset) {
39
+ return 'object' == typeof asset && asset?.name ? asset.name : asset;
40
+ }
41
+ function getAssetIntegrity(asset) {
42
+ return 'object' == typeof asset && asset?.integrity ? asset.integrity : null;
43
+ }
44
+ function getChunkGroupAssets(chunkGroup) {
45
+ const assets = chunkGroup?.assets;
46
+ if (Array.isArray(assets)) return assets;
47
+ if (assets && 'object' == typeof assets) return [
48
+ ...assets.js || [],
49
+ ...assets.css || []
50
+ ];
51
+ return [];
52
+ }
53
+ function getChunkGroupChildAssets(chunkGroup, type) {
54
+ const childAssets = chunkGroup?.childAssets?.[type];
55
+ return Array.isArray(childAssets) ? childAssets : [];
56
+ }
57
+ function chunkIncludesJs(chunkInfo) {
58
+ return (chunkInfo?.files || []).some((file)=>scriptExtensions.has(extname(file)));
59
+ }
60
+ export function ChunkExtractorManager({ extractor, children }) {
61
+ return React.createElement(LoadableContext.Provider, {
62
+ value: extractor
63
+ }, children);
64
+ }
65
+ export class ChunkExtractor {
66
+ constructor({ stats, entrypoints = [
67
+ 'main'
68
+ ], namespace = '', outputPath = '/', publicPath } = {}){
69
+ this.namespace = namespace;
70
+ this.stats = stats || {};
71
+ this.publicPath = publicPath || this.stats.publicPath || '/';
72
+ this.outputPath = outputPath || this.stats.outputPath || '/';
73
+ this.entrypoints = Array.isArray(entrypoints) ? entrypoints : [
74
+ entrypoints
75
+ ];
76
+ this.chunks = [];
77
+ }
78
+ addChunk(chunk) {
79
+ if (!this.chunks.includes(chunk)) this.chunks.push(chunk);
80
+ }
81
+ collectChunks(app) {
82
+ return React.createElement(ChunkExtractorManager, {
83
+ extractor: this
84
+ }, app);
85
+ }
86
+ getChunkGroup(chunk) {
87
+ return this.stats.namedChunkGroups?.[chunk] || {
88
+ assets: [],
89
+ childAssets: {},
90
+ chunks: []
91
+ };
92
+ }
93
+ getChunkInfo(chunkId) {
94
+ return (this.stats.chunks || []).find((chunk)=>chunk.id === chunkId);
95
+ }
96
+ resolvePublicUrl(filename) {
97
+ return joinUrl(this.publicPath, filename);
98
+ }
99
+ createChunkAsset({ filename, chunk, type, linkType }) {
100
+ const resolvedFilename = getAssetName(filename);
101
+ const scriptType = assetScriptType(resolvedFilename);
102
+ if (!scriptType) return;
103
+ return {
104
+ filename: resolvedFilename,
105
+ integrity: getAssetIntegrity(filename),
106
+ scriptType,
107
+ chunk,
108
+ url: this.resolvePublicUrl(resolvedFilename),
109
+ path: String(resolvedFilename).replace(/^\/+/u, ''),
110
+ type,
111
+ linkType
112
+ };
113
+ }
114
+ getChunkAssets(chunks) {
115
+ const one = (chunk)=>getChunkGroupAssets(this.getChunkGroup(chunk)).map((filename)=>this.createChunkAsset({
116
+ filename,
117
+ chunk,
118
+ type: 'mainAsset',
119
+ linkType: 'preload'
120
+ })).filter(Boolean);
121
+ return Array.isArray(chunks) ? uniqByUrl(chunks.flatMap(one)) : one(chunks);
122
+ }
123
+ getChunkChildAssets(chunks, type) {
124
+ const one = (chunk)=>getChunkGroupChildAssets(this.getChunkGroup(chunk), type).map((filename)=>this.createChunkAsset({
125
+ filename,
126
+ chunk,
127
+ type: 'childAsset',
128
+ linkType: type
129
+ })).filter(Boolean);
130
+ return Array.isArray(chunks) ? uniqByUrl(chunks.flatMap(one)) : one(chunks);
131
+ }
132
+ getChunkDependencies(chunks) {
133
+ const one = (chunk)=>(this.getChunkGroup(chunk).chunks || []).filter((chunkId)=>chunkIncludesJs(this.getChunkInfo(chunkId)));
134
+ return Array.isArray(chunks) ? [
135
+ ...new Set(chunks.flatMap(one))
136
+ ] : one(chunks);
137
+ }
138
+ getRequiredChunksScriptContent() {
139
+ return JSON.stringify(this.getChunkDependencies(this.chunks));
140
+ }
141
+ getRequiredChunksNamesScriptContent() {
142
+ return JSON.stringify({
143
+ namedChunks: this.chunks
144
+ });
145
+ }
146
+ getRequiredChunksScriptTag(extraProps = {}) {
147
+ const id = getRequiredChunkKey(this.namespace);
148
+ const props = `type="application/json"${extraPropsToString(extraProps)}`;
149
+ return [
150
+ `<script id="${id}" ${props}>${this.getRequiredChunksScriptContent()}</script>`,
151
+ `<script id="${id}_ext" ${props}>${this.getRequiredChunksNamesScriptContent()}</script>`
152
+ ].join('');
153
+ }
154
+ getMainAssets(scriptType) {
155
+ const assets = this.getChunkAssets([
156
+ ...this.entrypoints,
157
+ ...this.chunks
158
+ ]);
159
+ return scriptType ? assets.filter((asset)=>asset.scriptType === scriptType) : assets;
160
+ }
161
+ getScriptTags(extraProps = {}) {
162
+ const scripts = this.getMainAssets("script").map((asset)=>`<script async data-chunk="${asset.chunk}" src="${asset.url}"${extraPropsToString(extraProps)}></script>`);
163
+ return [
164
+ this.getRequiredChunksScriptTag(extraProps),
165
+ ...scripts
166
+ ].join('');
167
+ }
168
+ getStyleTags(extraProps = {}) {
169
+ return this.getMainAssets('style').map((asset)=>`<link data-chunk="${asset.chunk}" rel="stylesheet" href="${asset.url}"${extraPropsToString(extraProps)}>`).join('');
170
+ }
171
+ getLinkTags(extraProps = {}) {
172
+ const assets = [
173
+ ...this.getMainAssets(),
174
+ ...this.getChunkChildAssets([
175
+ ...this.entrypoints,
176
+ ...this.chunks
177
+ ], 'preload'),
178
+ ...this.getChunkChildAssets([
179
+ ...this.entrypoints,
180
+ ...this.chunks
181
+ ], 'prefetch')
182
+ ];
183
+ return uniqByUrl(assets).map((asset)=>`<link data-chunk="${asset.chunk}" rel="${asset.linkType}" as="${asset.scriptType}" href="${asset.url}"${extraPropsToString(extraProps)}>`).join('');
184
+ }
185
+ }
@@ -0,0 +1,59 @@
1
+ const trimSlashes = (value)=>String(value).replace(/^\/+|\/+$/gu, '');
2
+ const normalizeSeparators = (value)=>String(value).replace(/\\+/gu, '/');
3
+ export const sep = '/';
4
+ export const delimiter = ':';
5
+ export function isAbsolute(filePath) {
6
+ return normalizeSeparators(filePath).startsWith('/');
7
+ }
8
+ export function normalize(filePath) {
9
+ const normalized = normalizeSeparators(filePath);
10
+ const absolute = isAbsolute(normalized);
11
+ const parts = [];
12
+ for (const part of normalized.split('/'))if (part && '.' !== part) {
13
+ if ('..' === part) {
14
+ if (parts.length > 0 && '..' !== parts[parts.length - 1]) parts.pop();
15
+ else if (!absolute) parts.push(part);
16
+ continue;
17
+ }
18
+ parts.push(part);
19
+ }
20
+ const joined = parts.join('/');
21
+ if (absolute) return joined ? `/${joined}` : '/';
22
+ return joined || '.';
23
+ }
24
+ export function join(...segments) {
25
+ const joined = segments.map(normalizeSeparators).filter(Boolean).map((segment, index)=>0 === index ? segment : trimSlashes(segment)).filter(Boolean).join('/');
26
+ return joined ? normalize(joined) : '.';
27
+ }
28
+ export function resolve(...segments) {
29
+ const joined = join(...segments);
30
+ return joined.startsWith('/') ? joined : `/${joined}`;
31
+ }
32
+ export function dirname(filePath) {
33
+ const normalized = normalizeSeparators(filePath).replace(/\/+$/u, '');
34
+ const index = normalized.lastIndexOf('/');
35
+ if (index <= 0) return '/';
36
+ return normalized.slice(0, index);
37
+ }
38
+ export function basename(filePath, suffix = '') {
39
+ const normalized = normalizeSeparators(filePath).replace(/\/+$/u, '');
40
+ const base = normalized.slice(normalized.lastIndexOf('/') + 1);
41
+ return suffix && base.endsWith(suffix) ? base.slice(0, -suffix.length) : base;
42
+ }
43
+ export function extname(filePath) {
44
+ const base = basename(filePath);
45
+ const index = base.lastIndexOf('.');
46
+ if (index <= 0) return '';
47
+ return base.slice(index);
48
+ }
49
+ export default {
50
+ basename,
51
+ delimiter,
52
+ dirname,
53
+ extname,
54
+ isAbsolute,
55
+ join,
56
+ normalize,
57
+ resolve,
58
+ sep
59
+ };
@@ -0,0 +1,5 @@
1
+ export declare const readFile: () => Promise<never>;
2
+ declare const _default: {
3
+ readFile: () => Promise<never>;
4
+ };
5
+ export default _default;
@@ -0,0 +1,48 @@
1
+ import React from 'react';
2
+ export declare function ChunkExtractorManager({ extractor, children }: {
3
+ children: any;
4
+ extractor: any;
5
+ }): React.DetailedReactHTMLElement<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>;
6
+ export declare class ChunkExtractor {
7
+ namespace: string;
8
+ stats: any;
9
+ publicPath: any;
10
+ outputPath: any;
11
+ entrypoints: string[];
12
+ chunks: any[];
13
+ constructor({ stats, entrypoints, namespace, outputPath, publicPath, }?: {
14
+ entrypoints?: string[] | undefined;
15
+ namespace?: string | undefined;
16
+ outputPath?: string | undefined;
17
+ });
18
+ addChunk(chunk: any): void;
19
+ collectChunks(app: any): React.DetailedReactHTMLElement<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>;
20
+ getChunkGroup(chunk: any): any;
21
+ getChunkInfo(chunkId: any): any;
22
+ resolvePublicUrl(filename: any): string;
23
+ createChunkAsset({ filename, chunk, type, linkType }: {
24
+ chunk: any;
25
+ filename: any;
26
+ linkType: any;
27
+ type: any;
28
+ }): {
29
+ filename: any;
30
+ integrity: any;
31
+ scriptType: string;
32
+ chunk: any;
33
+ url: string;
34
+ path: string;
35
+ type: any;
36
+ linkType: any;
37
+ } | undefined;
38
+ getChunkAssets(chunks: any): any;
39
+ getChunkChildAssets(chunks: any, type: any): any;
40
+ getChunkDependencies(chunks: any): any;
41
+ getRequiredChunksScriptContent(): string;
42
+ getRequiredChunksNamesScriptContent(): string;
43
+ getRequiredChunksScriptTag(extraProps?: {}): string;
44
+ getMainAssets(scriptType: any): any;
45
+ getScriptTags(extraProps?: {}): string;
46
+ getStyleTags(extraProps?: {}): any;
47
+ getLinkTags(extraProps?: {}): any;
48
+ }
@@ -0,0 +1,21 @@
1
+ export declare const sep = "/";
2
+ export declare const delimiter = ":";
3
+ export declare function isAbsolute(filePath: any): boolean;
4
+ export declare function normalize(filePath: any): string;
5
+ export declare function join(...segments: any[]): string;
6
+ export declare function resolve(...segments: any[]): string;
7
+ export declare function dirname(filePath: any): string;
8
+ export declare function basename(filePath: any, suffix?: string): string;
9
+ export declare function extname(filePath: any): string;
10
+ declare const _default: {
11
+ basename: typeof basename;
12
+ delimiter: string;
13
+ dirname: typeof dirname;
14
+ extname: typeof extname;
15
+ isAbsolute: typeof isAbsolute;
16
+ join: typeof join;
17
+ normalize: typeof normalize;
18
+ resolve: typeof resolve;
19
+ sep: string;
20
+ };
21
+ export default _default;
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "modern",
18
18
  "modern.js"
19
19
  ],
20
- "version": "3.2.0-ultramodern.62",
20
+ "version": "3.2.0-ultramodern.64",
21
21
  "types": "./dist/types/index.d.ts",
22
22
  "main": "./dist/cjs/index.js",
23
23
  "exports": {
@@ -85,6 +85,7 @@
85
85
  "@babel/parser": "^7.29.3",
86
86
  "@babel/traverse": "^7.29.0",
87
87
  "@babel/types": "^7.29.0",
88
+ "@loadable/component": "5.16.7",
88
89
  "@rsbuild/core": "2.0.7",
89
90
  "@swc/core": "1.15.40",
90
91
  "@swc/helpers": "^0.5.21",
@@ -98,16 +99,16 @@
98
99
  "ndepe": "^0.1.13",
99
100
  "pkg-types": "^2.3.1",
100
101
  "std-env": "4.1.0",
101
- "@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.2.0-ultramodern.62",
102
- "@modern-js/plugin-data-loader": "npm:@bleedingdev/modern-js-plugin-data-loader@3.2.0-ultramodern.62",
103
- "@modern-js/i18n-utils": "npm:@bleedingdev/modern-js-i18n-utils@3.2.0-ultramodern.62",
104
- "@modern-js/prod-server": "npm:@bleedingdev/modern-js-prod-server@3.2.0-ultramodern.62",
105
- "@modern-js/server": "npm:@bleedingdev/modern-js-server@3.2.0-ultramodern.62",
106
- "@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.2.0-ultramodern.62",
107
- "@modern-js/server-utils": "npm:@bleedingdev/modern-js-server-utils@3.2.0-ultramodern.62",
108
- "@modern-js/builder": "npm:@bleedingdev/modern-js-builder@3.2.0-ultramodern.62",
109
- "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.2.0-ultramodern.62",
110
- "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.2.0-ultramodern.62"
102
+ "@modern-js/i18n-utils": "npm:@bleedingdev/modern-js-i18n-utils@3.2.0-ultramodern.64",
103
+ "@modern-js/builder": "npm:@bleedingdev/modern-js-builder@3.2.0-ultramodern.64",
104
+ "@modern-js/plugin-data-loader": "npm:@bleedingdev/modern-js-plugin-data-loader@3.2.0-ultramodern.64",
105
+ "@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.2.0-ultramodern.64",
106
+ "@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.2.0-ultramodern.64",
107
+ "@modern-js/prod-server": "npm:@bleedingdev/modern-js-prod-server@3.2.0-ultramodern.64",
108
+ "@modern-js/server-utils": "npm:@bleedingdev/modern-js-server-utils@3.2.0-ultramodern.64",
109
+ "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.2.0-ultramodern.64",
110
+ "@modern-js/server": "npm:@bleedingdev/modern-js-server@3.2.0-ultramodern.64",
111
+ "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.2.0-ultramodern.64"
111
112
  },
112
113
  "devDependencies": {
113
114
  "@rslib/core": "0.21.5",