@bleedingdev/modern-js-app-tools 3.2.0-ultramodern.10 → 3.2.0-ultramodern.101
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/bin/modern.js +0 -0
- package/dist/cjs/baseline.js +43 -1
- package/dist/cjs/builder/generator/getBuilderEnvironments.js +191 -8
- package/dist/cjs/builder/shared/builderPlugins/adapterBasic.js +41 -5
- package/dist/cjs/builder/shared/builderPlugins/adapterSSR.js +3 -1
- package/dist/cjs/plugins/deploy/index.js +17 -6
- package/dist/cjs/plugins/deploy/platforms/cloudflare.js +222 -0
- package/dist/cjs/plugins/deploy/platforms/templates/cloudflare-entry.mjs +457 -0
- package/dist/cjs/plugins/deploy/platforms/templates/cloudflare-worker-fs-promises.mjs +7 -0
- package/dist/cjs/plugins/deploy/platforms/templates/cloudflare-worker-loadable-server.mjs +185 -0
- package/dist/cjs/plugins/deploy/platforms/templates/cloudflare-worker-path.mjs +59 -0
- package/dist/cjs/rsbuild.js +3 -0
- package/dist/esm/baseline.mjs +33 -1
- package/dist/esm/builder/generator/getBuilderEnvironments.mjs +180 -8
- package/dist/esm/builder/shared/builderPlugins/adapterBasic.mjs +41 -5
- package/dist/esm/builder/shared/builderPlugins/adapterSSR.mjs +3 -1
- package/dist/esm/plugins/deploy/index.mjs +10 -4
- package/dist/esm/plugins/deploy/platforms/cloudflare.mjs +178 -0
- package/dist/esm/plugins/deploy/platforms/templates/cloudflare-entry.mjs +457 -0
- package/dist/esm/plugins/deploy/platforms/templates/cloudflare-worker-fs-promises.mjs +7 -0
- package/dist/esm/plugins/deploy/platforms/templates/cloudflare-worker-loadable-server.mjs +185 -0
- package/dist/esm/plugins/deploy/platforms/templates/cloudflare-worker-path.mjs +59 -0
- package/dist/esm/rsbuild.mjs +5 -2
- package/dist/esm-node/baseline.mjs +33 -1
- package/dist/esm-node/builder/generator/getBuilderEnvironments.mjs +185 -9
- package/dist/esm-node/builder/shared/builderPlugins/adapterBasic.mjs +41 -5
- package/dist/esm-node/builder/shared/builderPlugins/adapterSSR.mjs +3 -1
- package/dist/esm-node/plugins/deploy/index.mjs +10 -4
- package/dist/esm-node/plugins/deploy/platforms/cloudflare.mjs +179 -0
- package/dist/esm-node/plugins/deploy/platforms/templates/cloudflare-entry.mjs +457 -0
- package/dist/esm-node/plugins/deploy/platforms/templates/cloudflare-worker-fs-promises.mjs +7 -0
- package/dist/esm-node/plugins/deploy/platforms/templates/cloudflare-worker-loadable-server.mjs +185 -0
- package/dist/esm-node/plugins/deploy/platforms/templates/cloudflare-worker-path.mjs +59 -0
- package/dist/esm-node/rsbuild.mjs +5 -2
- package/dist/types/locale/en.d.ts +1 -1
- package/dist/types/locale/zh.d.ts +1 -1
- package/dist/types/plugins/deploy/index.d.ts +4 -1
- package/dist/types/plugins/deploy/platforms/cloudflare.d.ts +2 -0
- package/dist/types/plugins/deploy/platforms/templates/cloudflare-entry.d.mts +4 -0
- package/dist/types/plugins/deploy/platforms/templates/cloudflare-worker-fs-promises.d.mts +5 -0
- package/dist/types/plugins/deploy/platforms/templates/cloudflare-worker-loadable-server.d.mts +48 -0
- package/dist/types/plugins/deploy/platforms/templates/cloudflare-worker-path.d.mts +21 -0
- package/dist/types/types/config/deploy.d.ts +8 -0
- package/package.json +18 -17
|
@@ -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
|
+
};
|
package/dist/cjs/rsbuild.js
CHANGED
|
@@ -42,9 +42,11 @@ var __webpack_exports__ = {};
|
|
|
42
42
|
resolveModernRsbuildConfig: ()=>resolveModernRsbuildConfig
|
|
43
43
|
});
|
|
44
44
|
const builder_namespaceObject = require("@modern-js/builder");
|
|
45
|
+
const utils_namespaceObject = require("@modern-js/utils");
|
|
45
46
|
const index_js_namespaceObject = require("./builder/shared/builderPlugins/index.js");
|
|
46
47
|
const external_constants_js_namespaceObject = require("./constants.js");
|
|
47
48
|
const getConfigFile_js_namespaceObject = require("./utils/getConfigFile.js");
|
|
49
|
+
const loadPlugins_js_namespaceObject = require("./utils/loadPlugins.js");
|
|
48
50
|
const MODERN_META_NAME = 'modern-js';
|
|
49
51
|
const { createConfigOptions } = __webpack_require__("@modern-js/plugin/cli");
|
|
50
52
|
async function resolveModernRsbuildConfig(options) {
|
|
@@ -55,6 +57,7 @@ var __webpack_exports__ = {};
|
|
|
55
57
|
command: options.command,
|
|
56
58
|
cwd,
|
|
57
59
|
configFile,
|
|
60
|
+
internalPlugins: await (0, loadPlugins_js_namespaceObject.loadInternalPlugins)(cwd, utils_namespaceObject.INTERNAL_RUNTIME_PLUGINS),
|
|
58
61
|
metaName,
|
|
59
62
|
modifyModernConfig: options.modifyModernConfig
|
|
60
63
|
});
|
package/dist/esm/baseline.mjs
CHANGED
|
@@ -1,4 +1,33 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import node_path from "node:path";
|
|
1
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
|
+
};
|
|
2
31
|
const createAppBaselineConfig = (options = {})=>{
|
|
3
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;
|
|
4
33
|
const server = {};
|
|
@@ -32,7 +61,10 @@ const createAppBaselineConfig = (options = {})=>{
|
|
|
32
61
|
disableClientServer: true
|
|
33
62
|
}
|
|
34
63
|
},
|
|
35
|
-
server
|
|
64
|
+
server,
|
|
65
|
+
tools: {
|
|
66
|
+
bundlerChain: setReactRouterBridgeSafeAliases
|
|
67
|
+
}
|
|
36
68
|
};
|
|
37
69
|
if (enableBffRequestId) baselineConfig.bff = {
|
|
38
70
|
requestId: appId
|
|
@@ -1,5 +1,69 @@
|
|
|
1
|
+
import node_fs from "node:fs";
|
|
2
|
+
import node_path from "node:path";
|
|
1
3
|
import { SERVICE_WORKER_ENVIRONMENT_NAME } from "@modern-js/builder";
|
|
2
4
|
import { isProd, isSSR, isServiceWorker, isUseRsc, isUseSSRBundle } from "@modern-js/utils";
|
|
5
|
+
const BFF_EFFECT_WORKER_ENTRY_NAME = '__modern_bff_effect';
|
|
6
|
+
const BFF_EFFECT_WORKER_RUNTIME_QUERY = 'modern-bff-runtime';
|
|
7
|
+
const JS_OR_TS_EXTS = [
|
|
8
|
+
'.ts',
|
|
9
|
+
'.tsx',
|
|
10
|
+
'.js',
|
|
11
|
+
'.jsx',
|
|
12
|
+
'.mjs',
|
|
13
|
+
'.cjs'
|
|
14
|
+
];
|
|
15
|
+
const CLOUDFLARE_WORKER_COMPAT_TEMPLATE_DIR = node_path.resolve(__dirname, '../../plugins/deploy/platforms/templates');
|
|
16
|
+
function findExistingFile(candidates) {
|
|
17
|
+
return candidates.find((candidate)=>node_fs.existsSync(candidate));
|
|
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
|
+
}
|
|
28
|
+
function resolvePackageFile(packageName, filePath, paths) {
|
|
29
|
+
try {
|
|
30
|
+
return node_fs.realpathSync(require.resolve(`${packageName}/${filePath}`, {
|
|
31
|
+
paths
|
|
32
|
+
}));
|
|
33
|
+
} catch {
|
|
34
|
+
const packageEntry = resolvePackageEntry(packageName, paths);
|
|
35
|
+
if (!packageEntry) return;
|
|
36
|
+
const packageRoot = findPackageRoot(packageEntry, packageName);
|
|
37
|
+
const packageFile = packageRoot ? node_path.join(packageRoot, filePath) : void 0;
|
|
38
|
+
return packageFile && node_fs.existsSync(packageFile) ? node_fs.realpathSync(packageFile) : void 0;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function findPackageRoot(entryFile, packageName) {
|
|
42
|
+
let directory = node_path.dirname(entryFile);
|
|
43
|
+
while(directory !== node_path.dirname(directory)){
|
|
44
|
+
const packageJsonPath = node_path.join(directory, 'package.json');
|
|
45
|
+
try {
|
|
46
|
+
const packageJson = JSON.parse(node_fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
47
|
+
if (packageJson.name === packageName) return directory;
|
|
48
|
+
} catch {}
|
|
49
|
+
directory = node_path.dirname(directory);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function setAliasIfPresent(alias, name, value) {
|
|
53
|
+
if (value) alias.set(name, value);
|
|
54
|
+
}
|
|
55
|
+
function getCloudflareWorkerCompatFile(file) {
|
|
56
|
+
return node_path.join(CLOUDFLARE_WORKER_COMPAT_TEMPLATE_DIR, file);
|
|
57
|
+
}
|
|
58
|
+
function getEffectBffEntry(normalizedConfig, appContext) {
|
|
59
|
+
if (!normalizedConfig.bff || 'hono' === normalizedConfig.bff.runtimeFramework) return;
|
|
60
|
+
const configuredEntry = normalizedConfig.bff.effect?.entry;
|
|
61
|
+
const entryWithoutExtension = configuredEntry ? node_path.isAbsolute(configuredEntry) ? configuredEntry : node_path.resolve(appContext.appDirectory, configuredEntry) : node_path.resolve(appContext.apiDirectory, 'effect', 'index');
|
|
62
|
+
return findExistingFile(JS_OR_TS_EXTS.map((extension)=>`${entryWithoutExtension}${extension}`));
|
|
63
|
+
}
|
|
64
|
+
function isCloudflareWorkerDeploy(normalizedConfig) {
|
|
65
|
+
return normalizedConfig.deploy?.target === 'cloudflare' || 'cloudflare' === process.env.MODERNJS_DEPLOY;
|
|
66
|
+
}
|
|
3
67
|
function getBuilderEnvironments(normalizedConfig, appContext, tempBuilderConfig) {
|
|
4
68
|
const entries = {};
|
|
5
69
|
const { entrypoints = [], checkedEntries } = appContext;
|
|
@@ -16,6 +80,11 @@ function getBuilderEnvironments(normalizedConfig, appContext, tempBuilderConfig)
|
|
|
16
80
|
const v = entries[entry];
|
|
17
81
|
serverEntries[entry] = v.map((entry)=>entry.replace('index.jsx', 'index.server.jsx')).map((entry)=>entry.replace('bootstrap.jsx', 'bootstrap.server.jsx'));
|
|
18
82
|
}
|
|
83
|
+
const cloudflareWorkerServerEntries = {};
|
|
84
|
+
for(const entry in entries){
|
|
85
|
+
const v = entries[entry];
|
|
86
|
+
cloudflareWorkerServerEntries[entry] = v.map((entry)=>entry.replace('index.jsx', 'index.server.jsx')).map((entry)=>entry.replace('bootstrap.jsx', 'index.server.jsx'));
|
|
87
|
+
}
|
|
19
88
|
const environments = {
|
|
20
89
|
client: {
|
|
21
90
|
output: {
|
|
@@ -40,14 +109,117 @@ function getBuilderEnvironments(normalizedConfig, appContext, tempBuilderConfig)
|
|
|
40
109
|
}
|
|
41
110
|
};
|
|
42
111
|
const useWorkerTarget = isServiceWorker(normalizedConfig);
|
|
43
|
-
if (useWorkerTarget)
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
112
|
+
if (useWorkerTarget) {
|
|
113
|
+
const useCloudflareModuleWorker = isCloudflareWorkerDeploy(normalizedConfig);
|
|
114
|
+
const effectBffEntry = useCloudflareModuleWorker ? getEffectBffEntry(normalizedConfig, appContext) : void 0;
|
|
115
|
+
const tanstackRouterSsrServerFile = useCloudflareModuleWorker ? resolvePackageFile('@tanstack/router-core', 'dist/esm/ssr/ssr-server.js', [
|
|
116
|
+
appContext.appDirectory,
|
|
117
|
+
process.cwd()
|
|
118
|
+
]) : void 0;
|
|
119
|
+
const runtimeRscWorkerFile = useCloudflareModuleWorker ? resolvePackageFile('@modern-js/runtime', 'dist/esm/rsc/server.worker.mjs', [
|
|
120
|
+
appContext.appDirectory,
|
|
121
|
+
process.cwd()
|
|
122
|
+
]) : void 0;
|
|
123
|
+
const renderRscWorkerFile = useCloudflareModuleWorker ? resolvePackageFile('@modern-js/render', 'dist/esm/rscWorker.mjs', [
|
|
124
|
+
appContext.appDirectory,
|
|
125
|
+
process.cwd()
|
|
126
|
+
]) : void 0;
|
|
127
|
+
const reactFile = useCloudflareModuleWorker ? resolvePackageFile('react', 'index.js', [
|
|
128
|
+
appContext.appDirectory,
|
|
129
|
+
process.cwd()
|
|
130
|
+
]) : void 0;
|
|
131
|
+
const reactJsxRuntimeFile = useCloudflareModuleWorker ? resolvePackageFile('react', 'jsx-runtime.js', [
|
|
132
|
+
appContext.appDirectory,
|
|
133
|
+
process.cwd()
|
|
134
|
+
]) : void 0;
|
|
135
|
+
const reactJsxDevRuntimeFile = useCloudflareModuleWorker ? resolvePackageFile('react', 'jsx-dev-runtime.js', [
|
|
136
|
+
appContext.appDirectory,
|
|
137
|
+
process.cwd()
|
|
138
|
+
]) : void 0;
|
|
139
|
+
const reactDomFile = useCloudflareModuleWorker ? resolvePackageFile('react-dom', 'index.js', [
|
|
140
|
+
appContext.appDirectory,
|
|
141
|
+
process.cwd()
|
|
142
|
+
]) : void 0;
|
|
143
|
+
const reactDomServerEdgeFile = useCloudflareModuleWorker ? resolvePackageFile('react-dom', 'server.edge.js', [
|
|
144
|
+
appContext.appDirectory,
|
|
145
|
+
process.cwd()
|
|
146
|
+
]) : void 0;
|
|
147
|
+
const loadableComponentFile = useCloudflareModuleWorker ? resolvePackageFile('@loadable/component', 'dist/esm/loadable.esm.mjs', [
|
|
148
|
+
appContext.appDirectory,
|
|
149
|
+
process.cwd(),
|
|
150
|
+
CLOUDFLARE_WORKER_COMPAT_TEMPLATE_DIR
|
|
151
|
+
]) : void 0;
|
|
152
|
+
const loadableServerWorkerFile = useCloudflareModuleWorker ? getCloudflareWorkerCompatFile('cloudflare-worker-loadable-server.mjs') : void 0;
|
|
153
|
+
const fsPromisesWorkerFile = useCloudflareModuleWorker ? getCloudflareWorkerCompatFile('cloudflare-worker-fs-promises.mjs') : void 0;
|
|
154
|
+
const pathWorkerFile = useCloudflareModuleWorker ? getCloudflareWorkerCompatFile('cloudflare-worker-path.mjs') : void 0;
|
|
155
|
+
const baseWorkerEntries = useCloudflareModuleWorker ? cloudflareWorkerServerEntries : serverEntries;
|
|
156
|
+
const workerEntries = effectBffEntry ? {
|
|
157
|
+
...baseWorkerEntries,
|
|
158
|
+
[BFF_EFFECT_WORKER_ENTRY_NAME]: [
|
|
159
|
+
`${effectBffEntry}?${BFF_EFFECT_WORKER_RUNTIME_QUERY}`
|
|
160
|
+
]
|
|
161
|
+
} : baseWorkerEntries;
|
|
162
|
+
environments[SERVICE_WORKER_ENVIRONMENT_NAME] = {
|
|
163
|
+
output: {
|
|
164
|
+
target: useCloudflareModuleWorker ? 'web' : 'web-worker',
|
|
165
|
+
...useCloudflareModuleWorker ? {
|
|
166
|
+
module: true
|
|
167
|
+
} : {}
|
|
168
|
+
},
|
|
169
|
+
source: {
|
|
170
|
+
entry: workerEntries
|
|
171
|
+
},
|
|
172
|
+
tools: {
|
|
173
|
+
htmlPlugin: false,
|
|
174
|
+
...useCloudflareModuleWorker ? {
|
|
175
|
+
bundlerChain: (chain)=>{
|
|
176
|
+
chain.merge({
|
|
177
|
+
experiments: {
|
|
178
|
+
outputModule: true
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
chain.output.module(true).library({
|
|
182
|
+
type: 'module'
|
|
183
|
+
}).chunkFormat('module').chunkLoading('import').workerChunkLoading('import');
|
|
184
|
+
chain.target('webworker');
|
|
185
|
+
chain.plugins.delete('plugin-module-federation');
|
|
186
|
+
if (tanstackRouterSsrServerFile) {
|
|
187
|
+
chain.resolve.alias.set('@tanstack/router-core/ssr/server$', tanstackRouterSsrServerFile);
|
|
188
|
+
chain.resolve.alias.set('@tanstack/router-core/ssr/server', tanstackRouterSsrServerFile);
|
|
189
|
+
}
|
|
190
|
+
if (runtimeRscWorkerFile) {
|
|
191
|
+
chain.resolve.alias.set('@modern-js/runtime/rsc/server$', runtimeRscWorkerFile);
|
|
192
|
+
chain.resolve.alias.set('@modern-js/runtime/rsc/server', runtimeRscWorkerFile);
|
|
193
|
+
}
|
|
194
|
+
if (renderRscWorkerFile) {
|
|
195
|
+
chain.resolve.alias.set('@modern-js/render/rsc$', renderRscWorkerFile);
|
|
196
|
+
chain.resolve.alias.set('@modern-js/render/rsc', renderRscWorkerFile);
|
|
197
|
+
chain.resolve.alias.set('@modern-js/render/rsc-worker$', renderRscWorkerFile);
|
|
198
|
+
}
|
|
199
|
+
setAliasIfPresent(chain.resolve.alias, 'react$', reactFile);
|
|
200
|
+
setAliasIfPresent(chain.resolve.alias, 'react/jsx-runtime$', reactJsxRuntimeFile);
|
|
201
|
+
setAliasIfPresent(chain.resolve.alias, 'react/jsx-dev-runtime$', reactJsxDevRuntimeFile);
|
|
202
|
+
setAliasIfPresent(chain.resolve.alias, 'react-dom$', reactDomFile);
|
|
203
|
+
setAliasIfPresent(chain.resolve.alias, 'react-dom/server.edge$', reactDomServerEdgeFile);
|
|
204
|
+
setAliasIfPresent(chain.resolve.alias, '@loadable/component$', loadableComponentFile);
|
|
205
|
+
setAliasIfPresent(chain.resolve.alias, '@loadable/server$', loadableServerWorkerFile);
|
|
206
|
+
setAliasIfPresent(chain.resolve.alias, 'fs/promises$', fsPromisesWorkerFile);
|
|
207
|
+
setAliasIfPresent(chain.resolve.alias, 'node:fs/promises$', fsPromisesWorkerFile);
|
|
208
|
+
setAliasIfPresent(chain.resolve.alias, 'path$', pathWorkerFile);
|
|
209
|
+
setAliasIfPresent(chain.resolve.alias, 'node:path$', pathWorkerFile);
|
|
210
|
+
chain.resolve.alias.set('react-server-dom-rspack/server.node$', 'react-server-dom-rspack/server.edge');
|
|
211
|
+
chain.resolve.alias.set('react-server-dom-rspack/server.node', 'react-server-dom-rspack/server.edge');
|
|
212
|
+
chain.resolve.alias.set('react-server-dom-rspack/client.node$', 'react-server-dom-rspack/client.edge');
|
|
213
|
+
chain.resolve.alias.set('react-server-dom-rspack/client.node', 'react-server-dom-rspack/client.edge');
|
|
214
|
+
chain.resolve.fallback.set('async_hooks', false);
|
|
215
|
+
chain.resolve.fallback.set('node:async_hooks', false);
|
|
216
|
+
chain.resolve.fallback.set('fs', false);
|
|
217
|
+
chain.resolve.fallback.set('node:fs', false);
|
|
218
|
+
}
|
|
219
|
+
} : {}
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
}
|
|
51
223
|
return {
|
|
52
224
|
environments,
|
|
53
225
|
builderConfig: tempBuilderConfig
|
|
@@ -5,8 +5,11 @@ const builderPluginAdapterBasic = (options)=>({
|
|
|
5
5
|
setup (api) {
|
|
6
6
|
api.modifyBundlerChain((chain, { target, CHAIN_ID, environment })=>{
|
|
7
7
|
const isServiceWorker = environment.name === SERVICE_WORKER_ENVIRONMENT_NAME;
|
|
8
|
-
|
|
9
|
-
if ('
|
|
8
|
+
const isWebTargetServiceWorker = isServiceWorker && 'web' === target;
|
|
9
|
+
if ('node' === target || isServiceWorker) applyNodeCompat(isServiceWorker, chain, {
|
|
10
|
+
includeNodeExtensions: !isWebTargetServiceWorker
|
|
11
|
+
});
|
|
12
|
+
if ('web' === target && !isServiceWorker) {
|
|
10
13
|
const bareServerModuleReg = /\.(server|node)\.[tj]sx?$/;
|
|
11
14
|
const depExt = 'mjs';
|
|
12
15
|
chain.module.rule(CHAIN_ID.RULE.JS).exclude.add(bareServerModuleReg);
|
|
@@ -22,8 +25,40 @@ const builderPluginAdapterBasic = (options)=>({
|
|
|
22
25
|
});
|
|
23
26
|
api.modifyRspackConfig((config, { target, environment })=>{
|
|
24
27
|
const isServiceWorker = environment.name === SERVICE_WORKER_ENVIRONMENT_NAME;
|
|
28
|
+
const isWebTargetServiceWorker = isServiceWorker && 'web' === target;
|
|
25
29
|
if ('node' === target || isServiceWorker) {
|
|
26
|
-
const extensionAlias = {
|
|
30
|
+
const extensionAlias = isWebTargetServiceWorker ? {
|
|
31
|
+
'.js': [
|
|
32
|
+
'.worker.js',
|
|
33
|
+
'.server.js',
|
|
34
|
+
'.js'
|
|
35
|
+
],
|
|
36
|
+
'.jsx': [
|
|
37
|
+
'.worker.jsx',
|
|
38
|
+
'.server.jsx',
|
|
39
|
+
'.jsx'
|
|
40
|
+
],
|
|
41
|
+
'.ts': [
|
|
42
|
+
'.worker.ts',
|
|
43
|
+
'.server.ts',
|
|
44
|
+
'.ts'
|
|
45
|
+
],
|
|
46
|
+
'.tsx': [
|
|
47
|
+
'.worker.tsx',
|
|
48
|
+
'.server.tsx',
|
|
49
|
+
'.tsx'
|
|
50
|
+
],
|
|
51
|
+
'.mjs': [
|
|
52
|
+
'.worker.mjs',
|
|
53
|
+
'.server.mjs',
|
|
54
|
+
'.mjs'
|
|
55
|
+
],
|
|
56
|
+
'.json': [
|
|
57
|
+
'.worker.json',
|
|
58
|
+
'.server.json',
|
|
59
|
+
'.json'
|
|
60
|
+
]
|
|
61
|
+
} : {
|
|
27
62
|
'.js': [
|
|
28
63
|
'.node.js',
|
|
29
64
|
'.server.js',
|
|
@@ -64,7 +99,8 @@ const builderPluginAdapterBasic = (options)=>({
|
|
|
64
99
|
});
|
|
65
100
|
}
|
|
66
101
|
});
|
|
67
|
-
function applyNodeCompat(isServiceWorker, chain) {
|
|
102
|
+
function applyNodeCompat(isServiceWorker, chain, options = {}) {
|
|
103
|
+
const { includeNodeExtensions = true } = options;
|
|
68
104
|
const nodeExts = [
|
|
69
105
|
'.node.js',
|
|
70
106
|
'.node.jsx',
|
|
@@ -83,7 +119,7 @@ function applyNodeCompat(isServiceWorker, chain) {
|
|
|
83
119
|
'.worker.ts',
|
|
84
120
|
'.worker.tsx'
|
|
85
121
|
];
|
|
86
|
-
for (const ext of nodeExts)chain.resolve.extensions.prepend(ext);
|
|
122
|
+
if (includeNodeExtensions) for (const ext of nodeExts)chain.resolve.extensions.prepend(ext);
|
|
87
123
|
if (isServiceWorker) for (const ext of webWorkerExts)chain.resolve.extensions.prepend(ext);
|
|
88
124
|
}
|
|
89
125
|
export { builderPluginAdapterBasic };
|
|
@@ -94,9 +94,10 @@ function applyFilterEntriesBySSRConfig({ isProd, chain, appNormalizedConfig }) {
|
|
|
94
94
|
});
|
|
95
95
|
}
|
|
96
96
|
async function applySSRLoaderEntry(chain, optinos, isServer) {
|
|
97
|
-
const { appContext } = optinos;
|
|
97
|
+
const { appContext, normalizedConfig } = optinos;
|
|
98
98
|
const { internalDirectory } = appContext;
|
|
99
99
|
const { entrypoints } = appContext;
|
|
100
|
+
const isRsc = isUseRsc(normalizedConfig);
|
|
100
101
|
await Promise.all(entrypoints.map(async (entrypoint)=>{
|
|
101
102
|
const { entryName } = entrypoint;
|
|
102
103
|
const serverLoadersFile = getServerCombinedModuleFile(internalDirectory, entryName);
|
|
@@ -104,6 +105,7 @@ async function applySSRLoaderEntry(chain, optinos, isServer) {
|
|
|
104
105
|
await fs.access(serverLoadersFile, fs.constants.F_OK);
|
|
105
106
|
chain.entry(`${entryName}-server-loaders`).add(serverLoadersFile);
|
|
106
107
|
} catch (err) {}
|
|
108
|
+
else if (isRsc) chain.entry(`${entryName}-server-loaders`).add("data:text/javascript,export%20{};");
|
|
107
109
|
}));
|
|
108
110
|
}
|
|
109
111
|
function applySSRDataLoader(chain, options) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { provider } from "std-env";
|
|
2
|
+
import { createCloudflarePreset } from "./platforms/cloudflare.mjs";
|
|
2
3
|
import { createGhPagesPreset } from "./platforms/gh-pages.mjs";
|
|
3
4
|
import { createNetlifyPreset } from "./platforms/netlify.mjs";
|
|
4
5
|
import { createNodePreset } from "./platforms/node.mjs";
|
|
@@ -8,14 +9,18 @@ const deployPresets = {
|
|
|
8
9
|
node: createNodePreset,
|
|
9
10
|
vercel: createVercelPreset,
|
|
10
11
|
netlify: createNetlifyPreset,
|
|
11
|
-
ghPages: createGhPagesPreset
|
|
12
|
+
ghPages: createGhPagesPreset,
|
|
13
|
+
cloudflare: createCloudflarePreset
|
|
12
14
|
};
|
|
15
|
+
const getSupportedDeployTargets = ()=>Object.keys(deployPresets);
|
|
16
|
+
const isDeployTarget = (target)=>Object.prototype.hasOwnProperty.call(deployPresets, target);
|
|
17
|
+
const resolveDeployTarget = (modernConfig, envDeployTarget = process.env.MODERNJS_DEPLOY, detectedProvider = provider)=>modernConfig.deploy?.target || envDeployTarget || detectedProvider || 'node';
|
|
13
18
|
async function getDeployPreset(appContext, modernConfig, deployTarget, api) {
|
|
14
19
|
const { appDirectory, distDirectory, metaName } = appContext;
|
|
15
20
|
const { useSSR, useAPI, useWebServer } = getProjectUsage(appDirectory, distDirectory, metaName);
|
|
16
21
|
const needModernServer = useSSR || useAPI || useWebServer;
|
|
22
|
+
if (!isDeployTarget(deployTarget)) throw new Error(`Unknown deploy target: '${deployTarget}'. deploy.target or MODERNJS_DEPLOY should be one of: ${getSupportedDeployTargets().join(', ')}.`);
|
|
17
23
|
const createPreset = deployPresets[deployTarget];
|
|
18
|
-
if (!createPreset) throw new Error(`Unknown deploy target: '${deployTarget}'. MODERNJS_DEPLOY should be 'node', 'vercel', or 'netlify'.`);
|
|
19
24
|
return createPreset({
|
|
20
25
|
appContext,
|
|
21
26
|
modernConfig,
|
|
@@ -26,12 +31,12 @@ async function getDeployPreset(appContext, modernConfig, deployTarget, api) {
|
|
|
26
31
|
const deploy = ()=>({
|
|
27
32
|
name: '@modern-js/plugin-deploy',
|
|
28
33
|
setup: (api)=>{
|
|
29
|
-
const deployTarget = process.env.MODERNJS_DEPLOY || provider || 'node';
|
|
30
34
|
api.deploy(async ()=>{
|
|
31
35
|
const appContext = api.getAppContext();
|
|
32
36
|
const { metaName } = appContext;
|
|
33
|
-
if ('modern-js' !== metaName && !process.env.MODERNJS_DEPLOY) return;
|
|
34
37
|
const modernConfig = api.getNormalizedConfig();
|
|
38
|
+
const deployTarget = resolveDeployTarget(modernConfig);
|
|
39
|
+
if ('modern-js' !== metaName && !modernConfig.deploy?.target && !process.env.MODERNJS_DEPLOY) return;
|
|
35
40
|
const deployPreset = await getDeployPreset(appContext, modernConfig, deployTarget, api);
|
|
36
41
|
deployPreset?.prepare && await deployPreset?.prepare();
|
|
37
42
|
deployPreset?.writeOutput && await deployPreset?.writeOutput();
|
|
@@ -41,3 +46,4 @@ const deploy = ()=>({
|
|
|
41
46
|
}
|
|
42
47
|
});
|
|
43
48
|
export default deploy;
|
|
49
|
+
export { getSupportedDeployTargets, resolveDeployTarget };
|