@bleedingdev/modern-js-app-tools-extensions 3.9.0-ultramodern.8 → 3.9.0-ultramodern.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/native-type-checker.js +37 -8
- package/dist/cjs/policy-defaults.js +101 -0
- package/dist/cjs/runtime-package-resolution.js +118 -0
- package/dist/esm/native-type-checker.mjs +38 -9
- package/dist/esm/policy-defaults.mjs +45 -0
- package/dist/esm/runtime-package-resolution.mjs +60 -0
- package/dist/esm-node/native-type-checker.mjs +38 -9
- package/dist/esm-node/policy-defaults.mjs +46 -0
- package/dist/esm-node/runtime-package-resolution.mjs +61 -0
- package/dist/types/policy-defaults.d.ts +46 -0
- package/dist/types/runtime-package-resolution.d.ts +28 -0
- package/package.json +21 -10
- package/src/native-type-checker.ts +54 -12
- package/src/policy-defaults.ts +127 -0
- package/src/runtime-package-resolution.ts +115 -0
|
@@ -45,9 +45,17 @@ const external_node_fs_namespaceObject = require("node:fs");
|
|
|
45
45
|
const external_node_path_namespaceObject = require("node:path");
|
|
46
46
|
var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_namespaceObject);
|
|
47
47
|
const external_node_util_namespaceObject = require("node:util");
|
|
48
|
+
const builder_namespaceObject = require("@modern-js/builder");
|
|
48
49
|
const execute = (0, external_node_util_namespaceObject.promisify)(external_node_child_process_namespaceObject.execFile);
|
|
49
50
|
const native_type_checker_name = 'UltramodernNativeTypeChecker';
|
|
50
|
-
const watchDependencyPath = (file)=>
|
|
51
|
+
const watchDependencyPath = (file)=>{
|
|
52
|
+
if ('win32' !== process.platform) return file;
|
|
53
|
+
try {
|
|
54
|
+
return external_node_fs_namespaceObject.realpathSync.native(file);
|
|
55
|
+
} catch {
|
|
56
|
+
return file;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
51
59
|
class UltramodernNativeTypeChecker {
|
|
52
60
|
async check() {
|
|
53
61
|
const { configFile, build } = this.options;
|
|
@@ -83,6 +91,7 @@ class UltramodernNativeTypeChecker {
|
|
|
83
91
|
}
|
|
84
92
|
async watchInputs() {
|
|
85
93
|
const inputs = new Set();
|
|
94
|
+
const missing = new Set();
|
|
86
95
|
const projects = [
|
|
87
96
|
this.options.configFile
|
|
88
97
|
];
|
|
@@ -91,11 +100,20 @@ class UltramodernNativeTypeChecker {
|
|
|
91
100
|
if (visited.has(configFile)) continue;
|
|
92
101
|
visited.add(configFile);
|
|
93
102
|
inputs.add(configFile);
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
103
|
+
if (!(0, external_node_fs_namespaceObject.existsSync)(configFile)) {
|
|
104
|
+
missing.add(configFile);
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
let config;
|
|
108
|
+
try {
|
|
109
|
+
config = JSON.parse(await this.run([
|
|
110
|
+
'--showConfig',
|
|
111
|
+
'--project',
|
|
112
|
+
configFile
|
|
113
|
+
]));
|
|
114
|
+
} catch {
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
99
117
|
const directory = external_node_path_default().dirname(configFile);
|
|
100
118
|
for (const file of config.files ?? [])inputs.add(external_node_path_default().resolve(directory, file));
|
|
101
119
|
for (const reference of config.references ?? []){
|
|
@@ -103,14 +121,25 @@ class UltramodernNativeTypeChecker {
|
|
|
103
121
|
projects.push('.json' === external_node_path_default().extname(target) ? target : external_node_path_default().join(target, 'tsconfig.json'));
|
|
104
122
|
}
|
|
105
123
|
}
|
|
106
|
-
return
|
|
124
|
+
return {
|
|
125
|
+
inputs,
|
|
126
|
+
missing
|
|
127
|
+
};
|
|
107
128
|
}
|
|
108
129
|
apply(compiler) {
|
|
109
130
|
compiler.hooks.thisCompilation.tap(native_type_checker_name, (compilation)=>{
|
|
110
131
|
compilation.hooks.processAssets.tapPromise(native_type_checker_name, async ()=>{
|
|
111
132
|
try {
|
|
112
133
|
compilation.fileDependencies.add(watchDependencyPath(this.options.configFile));
|
|
113
|
-
|
|
134
|
+
const projectConfigFile = (0, builder_namespaceObject.refreshTsgoCheckerConfig)(this.options.configFile);
|
|
135
|
+
if (projectConfigFile) {
|
|
136
|
+
const watched = watchDependencyPath(projectConfigFile);
|
|
137
|
+
compilation.fileDependencies.add(watched);
|
|
138
|
+
if (!(0, external_node_fs_namespaceObject.existsSync)(projectConfigFile)) compilation.missingDependencies.add(watched);
|
|
139
|
+
}
|
|
140
|
+
const { inputs, missing } = await this.watchInputs();
|
|
141
|
+
for (const file of inputs)compilation.fileDependencies.add(watchDependencyPath(file));
|
|
142
|
+
for (const file of missing)compilation.missingDependencies.add(watchDependencyPath(file));
|
|
114
143
|
await this.check();
|
|
115
144
|
} catch (cause) {
|
|
116
145
|
compilation.errors.push(new Error(cause instanceof Error ? cause.message : String(cause), {
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const __rslib_import_meta_url__ = /*#__PURE__*/ function() {
|
|
3
|
+
return "u" < typeof document ? new (require('url'.replace('', ''))).URL('file:' + __filename).href : document.currentScript && document.currentScript.src || new URL('main.js', document.baseURI).href;
|
|
4
|
+
}();
|
|
5
|
+
var __webpack_require__ = {};
|
|
6
|
+
(()=>{
|
|
7
|
+
__webpack_require__.d = (exports1, getters, values)=>{
|
|
8
|
+
var define = (defs, kind)=>{
|
|
9
|
+
for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
10
|
+
enumerable: true,
|
|
11
|
+
[kind]: defs[key]
|
|
12
|
+
});
|
|
13
|
+
};
|
|
14
|
+
define(getters, "get");
|
|
15
|
+
define(values, "value");
|
|
16
|
+
};
|
|
17
|
+
})();
|
|
18
|
+
(()=>{
|
|
19
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
20
|
+
})();
|
|
21
|
+
(()=>{
|
|
22
|
+
__webpack_require__.r = (exports1)=>{
|
|
23
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
24
|
+
value: 'Module'
|
|
25
|
+
});
|
|
26
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
27
|
+
value: true
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
})();
|
|
31
|
+
var __webpack_exports__ = {};
|
|
32
|
+
__webpack_require__.r(__webpack_exports__);
|
|
33
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
34
|
+
POLICY_DEFAULTS_PLUGIN_NAME: ()=>POLICY_DEFAULTS_PLUGIN_NAME,
|
|
35
|
+
RENDERER_EXTENSIONS_PACKAGE: ()=>RENDERER_EXTENSIONS_PACKAGE,
|
|
36
|
+
RENDERER_EXTENSIONS_PLUGIN_NAME: ()=>RENDERER_EXTENSIONS_PLUGIN_NAME,
|
|
37
|
+
SERVER_EXTENSIONS_PLUGIN_NAME: ()=>SERVER_EXTENSIONS_PLUGIN_NAME,
|
|
38
|
+
applyPolicyDefaults: ()=>applyPolicyDefaults,
|
|
39
|
+
createPolicyDefaultsPlugin: ()=>createPolicyDefaultsPlugin
|
|
40
|
+
});
|
|
41
|
+
const external_runtime_package_resolution_js_namespaceObject = require("./runtime-package-resolution.js");
|
|
42
|
+
const RENDERER_EXTENSIONS_PACKAGE = '@modern-js/runtime-renderer-extensions';
|
|
43
|
+
const RENDERER_EXTENSIONS_PLUGIN_NAME = 'rendererHead';
|
|
44
|
+
const SERVER_EXTENSIONS_PLUGIN_NAME = '@modern-js/app-tools/server-plugin';
|
|
45
|
+
const POLICY_DEFAULTS_PLUGIN_NAME = '@modern-js/ultramodern-policy-defaults';
|
|
46
|
+
const applyPolicyDefaults = (api, options = {})=>{
|
|
47
|
+
if (false !== options.rendererExtensions) {
|
|
48
|
+
api._internalRuntimePlugins(({ entrypoint, plugins })=>{
|
|
49
|
+
if (!plugins.some((plugin)=>plugin.path === RENDERER_EXTENSIONS_PACKAGE)) plugins.push({
|
|
50
|
+
name: RENDERER_EXTENSIONS_PLUGIN_NAME,
|
|
51
|
+
path: RENDERER_EXTENSIONS_PACKAGE,
|
|
52
|
+
config: {}
|
|
53
|
+
});
|
|
54
|
+
return {
|
|
55
|
+
entrypoint,
|
|
56
|
+
plugins
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
const moduleDirectories = (0, external_runtime_package_resolution_js_namespaceObject.collectRuntimePackageModuleDirectories)([
|
|
60
|
+
RENDERER_EXTENSIONS_PACKAGE
|
|
61
|
+
], __rslib_import_meta_url__);
|
|
62
|
+
if (moduleDirectories.length > 0) api.modifyResolvedConfig((config)=>({
|
|
63
|
+
...config,
|
|
64
|
+
builderPlugins: [
|
|
65
|
+
...config.builderPlugins ?? [],
|
|
66
|
+
(0, external_runtime_package_resolution_js_namespaceObject.createRuntimePackageResolutionPlugin)(moduleDirectories)
|
|
67
|
+
]
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
70
|
+
if (false !== options.serverExtensions) api._internalServerPlugins(({ plugins })=>{
|
|
71
|
+
if (!plugins.some((plugin)=>plugin.name === SERVER_EXTENSIONS_PLUGIN_NAME)) plugins.push({
|
|
72
|
+
name: SERVER_EXTENSIONS_PLUGIN_NAME
|
|
73
|
+
});
|
|
74
|
+
return {
|
|
75
|
+
plugins
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
const createPolicyDefaultsPlugin = (options = {})=>({
|
|
80
|
+
name: POLICY_DEFAULTS_PLUGIN_NAME,
|
|
81
|
+
setup (api) {
|
|
82
|
+
applyPolicyDefaults(api, options);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
exports.POLICY_DEFAULTS_PLUGIN_NAME = __webpack_exports__.POLICY_DEFAULTS_PLUGIN_NAME;
|
|
86
|
+
exports.RENDERER_EXTENSIONS_PACKAGE = __webpack_exports__.RENDERER_EXTENSIONS_PACKAGE;
|
|
87
|
+
exports.RENDERER_EXTENSIONS_PLUGIN_NAME = __webpack_exports__.RENDERER_EXTENSIONS_PLUGIN_NAME;
|
|
88
|
+
exports.SERVER_EXTENSIONS_PLUGIN_NAME = __webpack_exports__.SERVER_EXTENSIONS_PLUGIN_NAME;
|
|
89
|
+
exports.applyPolicyDefaults = __webpack_exports__.applyPolicyDefaults;
|
|
90
|
+
exports.createPolicyDefaultsPlugin = __webpack_exports__.createPolicyDefaultsPlugin;
|
|
91
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
92
|
+
"POLICY_DEFAULTS_PLUGIN_NAME",
|
|
93
|
+
"RENDERER_EXTENSIONS_PACKAGE",
|
|
94
|
+
"RENDERER_EXTENSIONS_PLUGIN_NAME",
|
|
95
|
+
"SERVER_EXTENSIONS_PLUGIN_NAME",
|
|
96
|
+
"applyPolicyDefaults",
|
|
97
|
+
"createPolicyDefaultsPlugin"
|
|
98
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
99
|
+
Object.defineProperty(exports, '__esModule', {
|
|
100
|
+
value: true
|
|
101
|
+
});
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.n = (module)=>{
|
|
5
|
+
var getter = module && module.__esModule ? ()=>module['default'] : ()=>module;
|
|
6
|
+
__webpack_require__.d(getter, {
|
|
7
|
+
a: getter
|
|
8
|
+
});
|
|
9
|
+
return getter;
|
|
10
|
+
};
|
|
11
|
+
})();
|
|
12
|
+
(()=>{
|
|
13
|
+
__webpack_require__.d = (exports1, getters, values)=>{
|
|
14
|
+
var define = (defs, kind)=>{
|
|
15
|
+
for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
[kind]: defs[key]
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
define(getters, "get");
|
|
21
|
+
define(values, "value");
|
|
22
|
+
};
|
|
23
|
+
})();
|
|
24
|
+
(()=>{
|
|
25
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
26
|
+
})();
|
|
27
|
+
(()=>{
|
|
28
|
+
__webpack_require__.r = (exports1)=>{
|
|
29
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
30
|
+
value: 'Module'
|
|
31
|
+
});
|
|
32
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
33
|
+
value: true
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
})();
|
|
37
|
+
var __webpack_exports__ = {};
|
|
38
|
+
__webpack_require__.r(__webpack_exports__);
|
|
39
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
40
|
+
canResolveRuntimePackage: ()=>canResolveRuntimePackage,
|
|
41
|
+
collectRuntimePackageModuleDirectories: ()=>collectRuntimePackageModuleDirectories,
|
|
42
|
+
createRuntimePackageResolutionPlugin: ()=>createRuntimePackageResolutionPlugin,
|
|
43
|
+
findHostingModuleDirectory: ()=>findHostingModuleDirectory
|
|
44
|
+
});
|
|
45
|
+
const external_node_fs_namespaceObject = require("node:fs");
|
|
46
|
+
var external_node_fs_default = /*#__PURE__*/ __webpack_require__.n(external_node_fs_namespaceObject);
|
|
47
|
+
const external_node_module_namespaceObject = require("node:module");
|
|
48
|
+
const external_node_path_namespaceObject = require("node:path");
|
|
49
|
+
var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_namespaceObject);
|
|
50
|
+
const external_node_url_namespaceObject = require("node:url");
|
|
51
|
+
const findHostingModuleDirectory = (packageName, fromDirectory)=>{
|
|
52
|
+
let directory = external_node_path_default().resolve(fromDirectory);
|
|
53
|
+
for(;;){
|
|
54
|
+
const candidate = external_node_path_default().join(directory, 'node_modules');
|
|
55
|
+
if (external_node_fs_default().existsSync(external_node_path_default().join(candidate, packageName))) return candidate;
|
|
56
|
+
const parent = external_node_path_default().dirname(directory);
|
|
57
|
+
if (parent === directory) return;
|
|
58
|
+
directory = parent;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
const collectRuntimePackageModuleDirectories = (packageNames, registrarUrl)=>{
|
|
62
|
+
const registrarDirectory = external_node_path_default().dirname((0, external_node_url_namespaceObject.fileURLToPath)(registrarUrl));
|
|
63
|
+
const directories = [];
|
|
64
|
+
for (const packageName of packageNames){
|
|
65
|
+
const directory = findHostingModuleDirectory(packageName, registrarDirectory);
|
|
66
|
+
if (directory && !directories.includes(directory)) directories.push(directory);
|
|
67
|
+
}
|
|
68
|
+
return directories;
|
|
69
|
+
};
|
|
70
|
+
const appendModuleDirectories = (config, directories)=>{
|
|
71
|
+
if (0 === directories.length) return;
|
|
72
|
+
config.resolve ??= {};
|
|
73
|
+
const existing = config.resolve.modules ?? [
|
|
74
|
+
'node_modules'
|
|
75
|
+
];
|
|
76
|
+
config.resolve.modules = [
|
|
77
|
+
...existing,
|
|
78
|
+
...directories.filter((directory)=>!existing.includes(directory))
|
|
79
|
+
];
|
|
80
|
+
};
|
|
81
|
+
const createRuntimePackageResolutionPlugin = (directories)=>({
|
|
82
|
+
name: 'ultramodern:runtime-package-resolution',
|
|
83
|
+
setup (api) {
|
|
84
|
+
api.modifyRspackConfig({
|
|
85
|
+
order: 'post',
|
|
86
|
+
handler (config) {
|
|
87
|
+
appendModuleDirectories(config, directories);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
api.onBeforeCreateCompiler({
|
|
91
|
+
order: 'post',
|
|
92
|
+
handler ({ bundlerConfigs }) {
|
|
93
|
+
for (const config of bundlerConfigs)appendModuleDirectories(config, directories);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
const canResolveRuntimePackage = (packageName, registrarUrl)=>{
|
|
99
|
+
try {
|
|
100
|
+
(0, external_node_module_namespaceObject.createRequire)(registrarUrl).resolve(packageName);
|
|
101
|
+
return true;
|
|
102
|
+
} catch {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
exports.canResolveRuntimePackage = __webpack_exports__.canResolveRuntimePackage;
|
|
107
|
+
exports.collectRuntimePackageModuleDirectories = __webpack_exports__.collectRuntimePackageModuleDirectories;
|
|
108
|
+
exports.createRuntimePackageResolutionPlugin = __webpack_exports__.createRuntimePackageResolutionPlugin;
|
|
109
|
+
exports.findHostingModuleDirectory = __webpack_exports__.findHostingModuleDirectory;
|
|
110
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
111
|
+
"canResolveRuntimePackage",
|
|
112
|
+
"collectRuntimePackageModuleDirectories",
|
|
113
|
+
"createRuntimePackageResolutionPlugin",
|
|
114
|
+
"findHostingModuleDirectory"
|
|
115
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
116
|
+
Object.defineProperty(exports, '__esModule', {
|
|
117
|
+
value: true
|
|
118
|
+
});
|
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import { execFile } from "node:child_process";
|
|
2
|
-
import { realpathSync } from "node:fs";
|
|
2
|
+
import { existsSync, realpathSync } from "node:fs";
|
|
3
3
|
import node_path from "node:path";
|
|
4
4
|
import { promisify } from "node:util";
|
|
5
|
+
import { refreshTsgoCheckerConfig } from "@modern-js/builder";
|
|
5
6
|
const execute = promisify(execFile);
|
|
6
7
|
const native_type_checker_name = 'UltramodernNativeTypeChecker';
|
|
7
|
-
const watchDependencyPath = (file)=>
|
|
8
|
+
const watchDependencyPath = (file)=>{
|
|
9
|
+
if ('win32' !== process.platform) return file;
|
|
10
|
+
try {
|
|
11
|
+
return realpathSync.native(file);
|
|
12
|
+
} catch {
|
|
13
|
+
return file;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
8
16
|
class UltramodernNativeTypeChecker {
|
|
9
17
|
async check() {
|
|
10
18
|
const { configFile, build } = this.options;
|
|
@@ -40,6 +48,7 @@ class UltramodernNativeTypeChecker {
|
|
|
40
48
|
}
|
|
41
49
|
async watchInputs() {
|
|
42
50
|
const inputs = new Set();
|
|
51
|
+
const missing = new Set();
|
|
43
52
|
const projects = [
|
|
44
53
|
this.options.configFile
|
|
45
54
|
];
|
|
@@ -48,11 +57,20 @@ class UltramodernNativeTypeChecker {
|
|
|
48
57
|
if (visited.has(configFile)) continue;
|
|
49
58
|
visited.add(configFile);
|
|
50
59
|
inputs.add(configFile);
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
60
|
+
if (!existsSync(configFile)) {
|
|
61
|
+
missing.add(configFile);
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
let config;
|
|
65
|
+
try {
|
|
66
|
+
config = JSON.parse(await this.run([
|
|
67
|
+
'--showConfig',
|
|
68
|
+
'--project',
|
|
69
|
+
configFile
|
|
70
|
+
]));
|
|
71
|
+
} catch {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
56
74
|
const directory = node_path.dirname(configFile);
|
|
57
75
|
for (const file of config.files ?? [])inputs.add(node_path.resolve(directory, file));
|
|
58
76
|
for (const reference of config.references ?? []){
|
|
@@ -60,14 +78,25 @@ class UltramodernNativeTypeChecker {
|
|
|
60
78
|
projects.push('.json' === node_path.extname(target) ? target : node_path.join(target, 'tsconfig.json'));
|
|
61
79
|
}
|
|
62
80
|
}
|
|
63
|
-
return
|
|
81
|
+
return {
|
|
82
|
+
inputs,
|
|
83
|
+
missing
|
|
84
|
+
};
|
|
64
85
|
}
|
|
65
86
|
apply(compiler) {
|
|
66
87
|
compiler.hooks.thisCompilation.tap(native_type_checker_name, (compilation)=>{
|
|
67
88
|
compilation.hooks.processAssets.tapPromise(native_type_checker_name, async ()=>{
|
|
68
89
|
try {
|
|
69
90
|
compilation.fileDependencies.add(watchDependencyPath(this.options.configFile));
|
|
70
|
-
|
|
91
|
+
const projectConfigFile = refreshTsgoCheckerConfig(this.options.configFile);
|
|
92
|
+
if (projectConfigFile) {
|
|
93
|
+
const watched = watchDependencyPath(projectConfigFile);
|
|
94
|
+
compilation.fileDependencies.add(watched);
|
|
95
|
+
if (!existsSync(projectConfigFile)) compilation.missingDependencies.add(watched);
|
|
96
|
+
}
|
|
97
|
+
const { inputs, missing } = await this.watchInputs();
|
|
98
|
+
for (const file of inputs)compilation.fileDependencies.add(watchDependencyPath(file));
|
|
99
|
+
for (const file of missing)compilation.missingDependencies.add(watchDependencyPath(file));
|
|
71
100
|
await this.check();
|
|
72
101
|
} catch (cause) {
|
|
73
102
|
compilation.errors.push(new Error(cause instanceof Error ? cause.message : String(cause), {
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { collectRuntimePackageModuleDirectories, createRuntimePackageResolutionPlugin } from "./runtime-package-resolution.mjs";
|
|
2
|
+
const RENDERER_EXTENSIONS_PACKAGE = '@modern-js/runtime-renderer-extensions';
|
|
3
|
+
const RENDERER_EXTENSIONS_PLUGIN_NAME = 'rendererHead';
|
|
4
|
+
const SERVER_EXTENSIONS_PLUGIN_NAME = '@modern-js/app-tools/server-plugin';
|
|
5
|
+
const POLICY_DEFAULTS_PLUGIN_NAME = '@modern-js/ultramodern-policy-defaults';
|
|
6
|
+
const applyPolicyDefaults = (api, options = {})=>{
|
|
7
|
+
if (false !== options.rendererExtensions) {
|
|
8
|
+
api._internalRuntimePlugins(({ entrypoint, plugins })=>{
|
|
9
|
+
if (!plugins.some((plugin)=>plugin.path === RENDERER_EXTENSIONS_PACKAGE)) plugins.push({
|
|
10
|
+
name: RENDERER_EXTENSIONS_PLUGIN_NAME,
|
|
11
|
+
path: RENDERER_EXTENSIONS_PACKAGE,
|
|
12
|
+
config: {}
|
|
13
|
+
});
|
|
14
|
+
return {
|
|
15
|
+
entrypoint,
|
|
16
|
+
plugins
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
const moduleDirectories = collectRuntimePackageModuleDirectories([
|
|
20
|
+
RENDERER_EXTENSIONS_PACKAGE
|
|
21
|
+
], import.meta.url);
|
|
22
|
+
if (moduleDirectories.length > 0) api.modifyResolvedConfig((config)=>({
|
|
23
|
+
...config,
|
|
24
|
+
builderPlugins: [
|
|
25
|
+
...config.builderPlugins ?? [],
|
|
26
|
+
createRuntimePackageResolutionPlugin(moduleDirectories)
|
|
27
|
+
]
|
|
28
|
+
}));
|
|
29
|
+
}
|
|
30
|
+
if (false !== options.serverExtensions) api._internalServerPlugins(({ plugins })=>{
|
|
31
|
+
if (!plugins.some((plugin)=>plugin.name === SERVER_EXTENSIONS_PLUGIN_NAME)) plugins.push({
|
|
32
|
+
name: SERVER_EXTENSIONS_PLUGIN_NAME
|
|
33
|
+
});
|
|
34
|
+
return {
|
|
35
|
+
plugins
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
const createPolicyDefaultsPlugin = (options = {})=>({
|
|
40
|
+
name: POLICY_DEFAULTS_PLUGIN_NAME,
|
|
41
|
+
setup (api) {
|
|
42
|
+
applyPolicyDefaults(api, options);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
export { POLICY_DEFAULTS_PLUGIN_NAME, RENDERER_EXTENSIONS_PACKAGE, RENDERER_EXTENSIONS_PLUGIN_NAME, SERVER_EXTENSIONS_PLUGIN_NAME, applyPolicyDefaults, createPolicyDefaultsPlugin };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import node_fs from "node:fs";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import node_path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
const findHostingModuleDirectory = (packageName, fromDirectory)=>{
|
|
6
|
+
let directory = node_path.resolve(fromDirectory);
|
|
7
|
+
for(;;){
|
|
8
|
+
const candidate = node_path.join(directory, 'node_modules');
|
|
9
|
+
if (node_fs.existsSync(node_path.join(candidate, packageName))) return candidate;
|
|
10
|
+
const parent = node_path.dirname(directory);
|
|
11
|
+
if (parent === directory) return;
|
|
12
|
+
directory = parent;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
const collectRuntimePackageModuleDirectories = (packageNames, registrarUrl)=>{
|
|
16
|
+
const registrarDirectory = node_path.dirname(fileURLToPath(registrarUrl));
|
|
17
|
+
const directories = [];
|
|
18
|
+
for (const packageName of packageNames){
|
|
19
|
+
const directory = findHostingModuleDirectory(packageName, registrarDirectory);
|
|
20
|
+
if (directory && !directories.includes(directory)) directories.push(directory);
|
|
21
|
+
}
|
|
22
|
+
return directories;
|
|
23
|
+
};
|
|
24
|
+
const appendModuleDirectories = (config, directories)=>{
|
|
25
|
+
if (0 === directories.length) return;
|
|
26
|
+
config.resolve ??= {};
|
|
27
|
+
const existing = config.resolve.modules ?? [
|
|
28
|
+
'node_modules'
|
|
29
|
+
];
|
|
30
|
+
config.resolve.modules = [
|
|
31
|
+
...existing,
|
|
32
|
+
...directories.filter((directory)=>!existing.includes(directory))
|
|
33
|
+
];
|
|
34
|
+
};
|
|
35
|
+
const createRuntimePackageResolutionPlugin = (directories)=>({
|
|
36
|
+
name: 'ultramodern:runtime-package-resolution',
|
|
37
|
+
setup (api) {
|
|
38
|
+
api.modifyRspackConfig({
|
|
39
|
+
order: 'post',
|
|
40
|
+
handler (config) {
|
|
41
|
+
appendModuleDirectories(config, directories);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
api.onBeforeCreateCompiler({
|
|
45
|
+
order: 'post',
|
|
46
|
+
handler ({ bundlerConfigs }) {
|
|
47
|
+
for (const config of bundlerConfigs)appendModuleDirectories(config, directories);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
const canResolveRuntimePackage = (packageName, registrarUrl)=>{
|
|
53
|
+
try {
|
|
54
|
+
createRequire(registrarUrl).resolve(packageName);
|
|
55
|
+
return true;
|
|
56
|
+
} catch {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
export { canResolveRuntimePackage, collectRuntimePackageModuleDirectories, createRuntimePackageResolutionPlugin, findHostingModuleDirectory };
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
import "node:module";
|
|
2
2
|
import { execFile } from "node:child_process";
|
|
3
|
-
import { realpathSync } from "node:fs";
|
|
3
|
+
import { existsSync, realpathSync } from "node:fs";
|
|
4
4
|
import node_path from "node:path";
|
|
5
5
|
import { promisify } from "node:util";
|
|
6
|
+
import { refreshTsgoCheckerConfig } from "@modern-js/builder";
|
|
6
7
|
const execute = promisify(execFile);
|
|
7
8
|
const native_type_checker_name = 'UltramodernNativeTypeChecker';
|
|
8
|
-
const watchDependencyPath = (file)=>
|
|
9
|
+
const watchDependencyPath = (file)=>{
|
|
10
|
+
if ('win32' !== process.platform) return file;
|
|
11
|
+
try {
|
|
12
|
+
return realpathSync.native(file);
|
|
13
|
+
} catch {
|
|
14
|
+
return file;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
9
17
|
class UltramodernNativeTypeChecker {
|
|
10
18
|
async check() {
|
|
11
19
|
const { configFile, build } = this.options;
|
|
@@ -41,6 +49,7 @@ class UltramodernNativeTypeChecker {
|
|
|
41
49
|
}
|
|
42
50
|
async watchInputs() {
|
|
43
51
|
const inputs = new Set();
|
|
52
|
+
const missing = new Set();
|
|
44
53
|
const projects = [
|
|
45
54
|
this.options.configFile
|
|
46
55
|
];
|
|
@@ -49,11 +58,20 @@ class UltramodernNativeTypeChecker {
|
|
|
49
58
|
if (visited.has(configFile)) continue;
|
|
50
59
|
visited.add(configFile);
|
|
51
60
|
inputs.add(configFile);
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
61
|
+
if (!existsSync(configFile)) {
|
|
62
|
+
missing.add(configFile);
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
let config;
|
|
66
|
+
try {
|
|
67
|
+
config = JSON.parse(await this.run([
|
|
68
|
+
'--showConfig',
|
|
69
|
+
'--project',
|
|
70
|
+
configFile
|
|
71
|
+
]));
|
|
72
|
+
} catch {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
57
75
|
const directory = node_path.dirname(configFile);
|
|
58
76
|
for (const file of config.files ?? [])inputs.add(node_path.resolve(directory, file));
|
|
59
77
|
for (const reference of config.references ?? []){
|
|
@@ -61,14 +79,25 @@ class UltramodernNativeTypeChecker {
|
|
|
61
79
|
projects.push('.json' === node_path.extname(target) ? target : node_path.join(target, 'tsconfig.json'));
|
|
62
80
|
}
|
|
63
81
|
}
|
|
64
|
-
return
|
|
82
|
+
return {
|
|
83
|
+
inputs,
|
|
84
|
+
missing
|
|
85
|
+
};
|
|
65
86
|
}
|
|
66
87
|
apply(compiler) {
|
|
67
88
|
compiler.hooks.thisCompilation.tap(native_type_checker_name, (compilation)=>{
|
|
68
89
|
compilation.hooks.processAssets.tapPromise(native_type_checker_name, async ()=>{
|
|
69
90
|
try {
|
|
70
91
|
compilation.fileDependencies.add(watchDependencyPath(this.options.configFile));
|
|
71
|
-
|
|
92
|
+
const projectConfigFile = refreshTsgoCheckerConfig(this.options.configFile);
|
|
93
|
+
if (projectConfigFile) {
|
|
94
|
+
const watched = watchDependencyPath(projectConfigFile);
|
|
95
|
+
compilation.fileDependencies.add(watched);
|
|
96
|
+
if (!existsSync(projectConfigFile)) compilation.missingDependencies.add(watched);
|
|
97
|
+
}
|
|
98
|
+
const { inputs, missing } = await this.watchInputs();
|
|
99
|
+
for (const file of inputs)compilation.fileDependencies.add(watchDependencyPath(file));
|
|
100
|
+
for (const file of missing)compilation.missingDependencies.add(watchDependencyPath(file));
|
|
72
101
|
await this.check();
|
|
73
102
|
} catch (cause) {
|
|
74
103
|
compilation.errors.push(new Error(cause instanceof Error ? cause.message : String(cause), {
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
import { collectRuntimePackageModuleDirectories, createRuntimePackageResolutionPlugin } from "./runtime-package-resolution.mjs";
|
|
3
|
+
const RENDERER_EXTENSIONS_PACKAGE = '@modern-js/runtime-renderer-extensions';
|
|
4
|
+
const RENDERER_EXTENSIONS_PLUGIN_NAME = 'rendererHead';
|
|
5
|
+
const SERVER_EXTENSIONS_PLUGIN_NAME = '@modern-js/app-tools/server-plugin';
|
|
6
|
+
const POLICY_DEFAULTS_PLUGIN_NAME = '@modern-js/ultramodern-policy-defaults';
|
|
7
|
+
const applyPolicyDefaults = (api, options = {})=>{
|
|
8
|
+
if (false !== options.rendererExtensions) {
|
|
9
|
+
api._internalRuntimePlugins(({ entrypoint, plugins })=>{
|
|
10
|
+
if (!plugins.some((plugin)=>plugin.path === RENDERER_EXTENSIONS_PACKAGE)) plugins.push({
|
|
11
|
+
name: RENDERER_EXTENSIONS_PLUGIN_NAME,
|
|
12
|
+
path: RENDERER_EXTENSIONS_PACKAGE,
|
|
13
|
+
config: {}
|
|
14
|
+
});
|
|
15
|
+
return {
|
|
16
|
+
entrypoint,
|
|
17
|
+
plugins
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
const moduleDirectories = collectRuntimePackageModuleDirectories([
|
|
21
|
+
RENDERER_EXTENSIONS_PACKAGE
|
|
22
|
+
], import.meta.url);
|
|
23
|
+
if (moduleDirectories.length > 0) api.modifyResolvedConfig((config)=>({
|
|
24
|
+
...config,
|
|
25
|
+
builderPlugins: [
|
|
26
|
+
...config.builderPlugins ?? [],
|
|
27
|
+
createRuntimePackageResolutionPlugin(moduleDirectories)
|
|
28
|
+
]
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
if (false !== options.serverExtensions) api._internalServerPlugins(({ plugins })=>{
|
|
32
|
+
if (!plugins.some((plugin)=>plugin.name === SERVER_EXTENSIONS_PLUGIN_NAME)) plugins.push({
|
|
33
|
+
name: SERVER_EXTENSIONS_PLUGIN_NAME
|
|
34
|
+
});
|
|
35
|
+
return {
|
|
36
|
+
plugins
|
|
37
|
+
};
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
const createPolicyDefaultsPlugin = (options = {})=>({
|
|
41
|
+
name: POLICY_DEFAULTS_PLUGIN_NAME,
|
|
42
|
+
setup (api) {
|
|
43
|
+
applyPolicyDefaults(api, options);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
export { POLICY_DEFAULTS_PLUGIN_NAME, RENDERER_EXTENSIONS_PACKAGE, RENDERER_EXTENSIONS_PLUGIN_NAME, SERVER_EXTENSIONS_PLUGIN_NAME, applyPolicyDefaults, createPolicyDefaultsPlugin };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
import node_fs from "node:fs";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
import node_path from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
const findHostingModuleDirectory = (packageName, fromDirectory)=>{
|
|
7
|
+
let directory = node_path.resolve(fromDirectory);
|
|
8
|
+
for(;;){
|
|
9
|
+
const candidate = node_path.join(directory, 'node_modules');
|
|
10
|
+
if (node_fs.existsSync(node_path.join(candidate, packageName))) return candidate;
|
|
11
|
+
const parent = node_path.dirname(directory);
|
|
12
|
+
if (parent === directory) return;
|
|
13
|
+
directory = parent;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
const collectRuntimePackageModuleDirectories = (packageNames, registrarUrl)=>{
|
|
17
|
+
const registrarDirectory = node_path.dirname(fileURLToPath(registrarUrl));
|
|
18
|
+
const directories = [];
|
|
19
|
+
for (const packageName of packageNames){
|
|
20
|
+
const directory = findHostingModuleDirectory(packageName, registrarDirectory);
|
|
21
|
+
if (directory && !directories.includes(directory)) directories.push(directory);
|
|
22
|
+
}
|
|
23
|
+
return directories;
|
|
24
|
+
};
|
|
25
|
+
const appendModuleDirectories = (config, directories)=>{
|
|
26
|
+
if (0 === directories.length) return;
|
|
27
|
+
config.resolve ??= {};
|
|
28
|
+
const existing = config.resolve.modules ?? [
|
|
29
|
+
'node_modules'
|
|
30
|
+
];
|
|
31
|
+
config.resolve.modules = [
|
|
32
|
+
...existing,
|
|
33
|
+
...directories.filter((directory)=>!existing.includes(directory))
|
|
34
|
+
];
|
|
35
|
+
};
|
|
36
|
+
const createRuntimePackageResolutionPlugin = (directories)=>({
|
|
37
|
+
name: 'ultramodern:runtime-package-resolution',
|
|
38
|
+
setup (api) {
|
|
39
|
+
api.modifyRspackConfig({
|
|
40
|
+
order: 'post',
|
|
41
|
+
handler (config) {
|
|
42
|
+
appendModuleDirectories(config, directories);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
api.onBeforeCreateCompiler({
|
|
46
|
+
order: 'post',
|
|
47
|
+
handler ({ bundlerConfigs }) {
|
|
48
|
+
for (const config of bundlerConfigs)appendModuleDirectories(config, directories);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
const canResolveRuntimePackage = (packageName, registrarUrl)=>{
|
|
54
|
+
try {
|
|
55
|
+
createRequire(registrarUrl).resolve(packageName);
|
|
56
|
+
return true;
|
|
57
|
+
} catch {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
export { canResolveRuntimePackage, collectRuntimePackageModuleDirectories, createRuntimePackageResolutionPlugin, findHostingModuleDirectory };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The fork's renderer policy (head rendering, HTML template assembly and asset
|
|
3
|
+
* ordering) and server policy (localised loaders, error responses, telemetry,
|
|
4
|
+
* module-federation CSS and asset cache headers, static serving) are the
|
|
5
|
+
* default behaviour of an UltraModern.js app.
|
|
6
|
+
*
|
|
7
|
+
* They live in their own packages so they can also be composed explicitly, but
|
|
8
|
+
* a plain `appTools()` app gets them without opting in — that is what this fork
|
|
9
|
+
* has always done. Pass `appTools({ rendererExtensions: false })` or
|
|
10
|
+
* `appTools({ serverExtensions: false })` to run without them.
|
|
11
|
+
*/
|
|
12
|
+
export declare const RENDERER_EXTENSIONS_PACKAGE = "@modern-js/runtime-renderer-extensions";
|
|
13
|
+
export declare const RENDERER_EXTENSIONS_PLUGIN_NAME = "rendererHead";
|
|
14
|
+
export declare const SERVER_EXTENSIONS_PLUGIN_NAME = "@modern-js/app-tools/server-plugin";
|
|
15
|
+
export interface PolicyDefaultsOptions {
|
|
16
|
+
/** Default `true`. Set to `false` to drop the fork's renderer policy. */
|
|
17
|
+
rendererExtensions?: boolean;
|
|
18
|
+
/** Default `true`. Set to `false` to drop the fork's server policy. */
|
|
19
|
+
serverExtensions?: boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The subset of the CLI plugin API these defaults use. Typed structurally, and
|
|
23
|
+
* loosely at the hook boundary, so this package stays free of a dependency on
|
|
24
|
+
* the solution that consumes it — which depends on this one.
|
|
25
|
+
*/
|
|
26
|
+
export interface PolicyDefaultsPluginApi {
|
|
27
|
+
_internalRuntimePlugins(fn: (input: any) => any): void;
|
|
28
|
+
_internalServerPlugins(fn: (input: any) => any): void;
|
|
29
|
+
modifyResolvedConfig(fn: (config: any) => any): void;
|
|
30
|
+
}
|
|
31
|
+
export declare const POLICY_DEFAULTS_PLUGIN_NAME = "@modern-js/ultramodern-policy-defaults";
|
|
32
|
+
/** Registers the fork's default renderer and server policy. */
|
|
33
|
+
export declare const applyPolicyDefaults: (api: PolicyDefaultsPluginApi, options?: PolicyDefaultsOptions) => void;
|
|
34
|
+
/**
|
|
35
|
+
* The fork defaults as a CLI plugin.
|
|
36
|
+
*
|
|
37
|
+
* The descriptor this registers may land before the ones it wraps — CLI
|
|
38
|
+
* ordering cannot be constrained here without a cycle, because the plugins
|
|
39
|
+
* that emit those descriptors are themselves ordered after `appTools()`.
|
|
40
|
+
* Ordering is settled on the runtime side instead: `rendererHeadPlugin`
|
|
41
|
+
* declares the runtime plugins that run before it.
|
|
42
|
+
*/
|
|
43
|
+
export declare const createPolicyDefaultsPlugin: (options?: PolicyDefaultsOptions) => {
|
|
44
|
+
name: string;
|
|
45
|
+
setup(api: PolicyDefaultsPluginApi): void;
|
|
46
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { RsbuildPlugin } from '@rsbuild/core';
|
|
2
|
+
/**
|
|
3
|
+
* A generated `runtime-register.js` lives inside the *application*, so every
|
|
4
|
+
* runtime plugin it imports has to resolve from the application's own
|
|
5
|
+
* `node_modules`. Packages registered by a CLI plugin are dependencies of that
|
|
6
|
+
* CLI plugin, not of the application, and under an isolated (pnpm) linker the
|
|
7
|
+
* application cannot see them — the build fails with `Module not found`.
|
|
8
|
+
*
|
|
9
|
+
* Instead of freezing a single resolved file (which would lock one export
|
|
10
|
+
* condition and break the web/node split), the registering package contributes
|
|
11
|
+
* the `node_modules` directory that actually hosts the package as a *fallback*
|
|
12
|
+
* module directory. Bare specifiers keep their normal `exports` resolution, the
|
|
13
|
+
* application's own copy still wins when it declares the dependency, and both
|
|
14
|
+
* the workspace source layout and a published pnpm layout work.
|
|
15
|
+
*/
|
|
16
|
+
export declare const findHostingModuleDirectory: (packageName: string, fromDirectory: string) => string | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Collect the fallback module directories for the given packages, starting the
|
|
19
|
+
* search at the module that registers them.
|
|
20
|
+
*/
|
|
21
|
+
export declare const collectRuntimePackageModuleDirectories: (packageNames: readonly string[], registrarUrl: string) => string[];
|
|
22
|
+
/**
|
|
23
|
+
* Rsbuild plugin that adds the given directories as fallback module roots for
|
|
24
|
+
* every environment (web, node and worker bundles alike).
|
|
25
|
+
*/
|
|
26
|
+
export declare const createRuntimePackageResolutionPlugin: (directories: readonly string[]) => RsbuildPlugin;
|
|
27
|
+
/** `true` when the package resolves from the registering module at all. */
|
|
28
|
+
export declare const canResolveRuntimePackage: (packageName: string, registrarUrl: string) => boolean;
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"directory": "packages/solutions/app-tools-extensions"
|
|
12
12
|
},
|
|
13
13
|
"license": "MIT",
|
|
14
|
-
"version": "3.9.0-ultramodern.
|
|
14
|
+
"version": "3.9.0-ultramodern.9",
|
|
15
15
|
"files": [
|
|
16
16
|
"dist",
|
|
17
17
|
"src"
|
|
@@ -87,6 +87,16 @@
|
|
|
87
87
|
"import": "./dist/esm-node/native-type-checker.mjs",
|
|
88
88
|
"require": "./dist/cjs/native-type-checker.js"
|
|
89
89
|
},
|
|
90
|
+
"./runtime-package-resolution": {
|
|
91
|
+
"types": "./dist/types/runtime-package-resolution.d.ts",
|
|
92
|
+
"import": "./dist/esm-node/runtime-package-resolution.mjs",
|
|
93
|
+
"require": "./dist/cjs/runtime-package-resolution.js"
|
|
94
|
+
},
|
|
95
|
+
"./policy-defaults": {
|
|
96
|
+
"types": "./dist/types/policy-defaults.d.ts",
|
|
97
|
+
"import": "./dist/esm-node/policy-defaults.mjs",
|
|
98
|
+
"require": "./dist/cjs/policy-defaults.js"
|
|
99
|
+
},
|
|
90
100
|
"./build-config/precompress/plugin": {
|
|
91
101
|
"types": "./dist/types/build-config/precompress/plugin.d.ts",
|
|
92
102
|
"import": "./dist/esm-node/build-config/precompress/plugin.mjs",
|
|
@@ -135,13 +145,14 @@
|
|
|
135
145
|
"@babel/parser": "^8.0.4",
|
|
136
146
|
"@babel/traverse": "^8.0.4",
|
|
137
147
|
"@loadable/component": "5.16.7",
|
|
138
|
-
"@modern-js/backend-federation-contracts": "npm:@bleedingdev/modern-js-backend-federation-contracts@3.9.0-ultramodern.
|
|
139
|
-
"@modern-js/builder": "npm:@bleedingdev/modern-js-builder@3.9.0-ultramodern.
|
|
140
|
-
"@modern-js/prod-server": "npm:@bleedingdev/modern-js-prod-server@3.9.0-ultramodern.
|
|
141
|
-
"@modern-js/
|
|
142
|
-
"@modern-js/server-
|
|
143
|
-
"@modern-js/
|
|
144
|
-
"@modern-js/
|
|
148
|
+
"@modern-js/backend-federation-contracts": "npm:@bleedingdev/modern-js-backend-federation-contracts@3.9.0-ultramodern.9",
|
|
149
|
+
"@modern-js/builder": "npm:@bleedingdev/modern-js-builder@3.9.0-ultramodern.9",
|
|
150
|
+
"@modern-js/prod-server": "npm:@bleedingdev/modern-js-prod-server@3.9.0-ultramodern.9",
|
|
151
|
+
"@modern-js/runtime-renderer-extensions": "npm:@bleedingdev/modern-js-runtime-renderer-extensions@3.9.0-ultramodern.9",
|
|
152
|
+
"@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.9.0-ultramodern.9",
|
|
153
|
+
"@modern-js/server-runtime-extensions": "npm:@bleedingdev/modern-js-server-runtime-extensions@3.9.0-ultramodern.9",
|
|
154
|
+
"@modern-js/types": "npm:@bleedingdev/modern-js-types@3.9.0-ultramodern.9",
|
|
155
|
+
"@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.9.0-ultramodern.9",
|
|
145
156
|
"@swc/helpers": "^0.5.23",
|
|
146
157
|
"compression-webpack-plugin": "^12.0.0",
|
|
147
158
|
"esbuild": "^0.28.2",
|
|
@@ -151,8 +162,8 @@
|
|
|
151
162
|
"@rsbuild/core": "2.2.3"
|
|
152
163
|
},
|
|
153
164
|
"devDependencies": {
|
|
154
|
-
"@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.9.0-ultramodern.
|
|
155
|
-
"@modern-js/plugin-bff-extensions": "npm:@bleedingdev/modern-js-plugin-bff-extensions@3.9.0-ultramodern.
|
|
165
|
+
"@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.9.0-ultramodern.9",
|
|
166
|
+
"@modern-js/plugin-bff-extensions": "npm:@bleedingdev/modern-js-plugin-bff-extensions@3.9.0-ultramodern.9",
|
|
156
167
|
"@module-federation/runtime-tools": "2.9.0",
|
|
157
168
|
"@rsbuild/core": "2.2.3",
|
|
158
169
|
"@rslib/core": "1.0.0",
|
|
@@ -1,15 +1,24 @@
|
|
|
1
1
|
import { execFile } from 'node:child_process';
|
|
2
|
-
import { realpathSync } from 'node:fs';
|
|
2
|
+
import { existsSync, realpathSync } from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { promisify } from 'node:util';
|
|
5
|
+
import { refreshTsgoCheckerConfig } from '@modern-js/builder';
|
|
5
6
|
import type { Rspack, RspackChain } from '@rsbuild/core';
|
|
6
7
|
|
|
7
8
|
const execute = promisify(execFile);
|
|
8
9
|
const name = 'UltramodernNativeTypeChecker';
|
|
9
10
|
|
|
10
11
|
// Windows file events expand 8.3 aliases; register the same native path spelling.
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
// A path that does not exist yet (a project tsconfig mid-edit) cannot be
|
|
13
|
+
// realpathed; it is registered as spelled so its return still triggers a build.
|
|
14
|
+
const watchDependencyPath = (file: string): string => {
|
|
15
|
+
if (process.platform !== 'win32') return file;
|
|
16
|
+
try {
|
|
17
|
+
return realpathSync.native(file);
|
|
18
|
+
} catch {
|
|
19
|
+
return file;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
13
22
|
|
|
14
23
|
export class UltramodernNativeTypeChecker {
|
|
15
24
|
constructor(
|
|
@@ -45,20 +54,33 @@ export class UltramodernNativeTypeChecker {
|
|
|
45
54
|
}
|
|
46
55
|
}
|
|
47
56
|
|
|
48
|
-
private async watchInputs(): Promise<
|
|
57
|
+
private async watchInputs(): Promise<{
|
|
58
|
+
inputs: Set<string>;
|
|
59
|
+
missing: Set<string>;
|
|
60
|
+
}> {
|
|
49
61
|
const inputs = new Set<string>();
|
|
62
|
+
const missing = new Set<string>();
|
|
50
63
|
const projects = [this.options.configFile];
|
|
51
64
|
const visited = new Set<string>();
|
|
52
65
|
for (const configFile of projects) {
|
|
53
66
|
if (visited.has(configFile)) continue;
|
|
54
67
|
visited.add(configFile);
|
|
68
|
+
// Registered before it is parsed: a referenced config that is absent or
|
|
69
|
+
// unparsable right now must still be watched, or creating or repairing
|
|
70
|
+
// it never re-triggers the compilation. `check()` reports the error.
|
|
55
71
|
inputs.add(configFile);
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
72
|
+
if (!existsSync(configFile)) {
|
|
73
|
+
missing.add(configFile);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
let config: { files?: string[]; references?: { path: string }[] };
|
|
77
|
+
try {
|
|
78
|
+
config = JSON.parse(
|
|
79
|
+
await this.run(['--showConfig', '--project', configFile]),
|
|
80
|
+
);
|
|
81
|
+
} catch {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
62
84
|
const directory = path.dirname(configFile);
|
|
63
85
|
for (const file of config.files ?? [])
|
|
64
86
|
inputs.add(path.resolve(directory, file));
|
|
@@ -71,7 +93,7 @@ export class UltramodernNativeTypeChecker {
|
|
|
71
93
|
);
|
|
72
94
|
}
|
|
73
95
|
}
|
|
74
|
-
return inputs;
|
|
96
|
+
return { inputs, missing };
|
|
75
97
|
}
|
|
76
98
|
|
|
77
99
|
apply(compiler: Rspack.Compiler): void {
|
|
@@ -81,8 +103,28 @@ export class UltramodernNativeTypeChecker {
|
|
|
81
103
|
compilation.fileDependencies.add(
|
|
82
104
|
watchDependencyPath(this.options.configFile),
|
|
83
105
|
);
|
|
84
|
-
|
|
106
|
+
// A generated checker config restates values TypeScript does not
|
|
107
|
+
// inherit through `extends` (project references above all). Rebuild
|
|
108
|
+
// it from the project's own tsconfig before every check, and watch
|
|
109
|
+
// that tsconfig, so an edit during `modern dev` reaches the next
|
|
110
|
+
// compilation instead of the next restart.
|
|
111
|
+
const projectConfigFile = refreshTsgoCheckerConfig(
|
|
112
|
+
this.options.configFile,
|
|
113
|
+
);
|
|
114
|
+
if (projectConfigFile) {
|
|
115
|
+
const watched = watchDependencyPath(projectConfigFile);
|
|
116
|
+
compilation.fileDependencies.add(watched);
|
|
117
|
+
// Absent mid-edit: a missing dependency makes its (re)appearance
|
|
118
|
+
// a rebuild trigger, so the dev server recovers on its own.
|
|
119
|
+
if (!existsSync(projectConfigFile)) {
|
|
120
|
+
compilation.missingDependencies.add(watched);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
const { inputs, missing } = await this.watchInputs();
|
|
124
|
+
for (const file of inputs)
|
|
85
125
|
compilation.fileDependencies.add(watchDependencyPath(file));
|
|
126
|
+
for (const file of missing)
|
|
127
|
+
compilation.missingDependencies.add(watchDependencyPath(file));
|
|
86
128
|
await this.check();
|
|
87
129
|
} catch (cause) {
|
|
88
130
|
compilation.errors.push(
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import {
|
|
2
|
+
collectRuntimePackageModuleDirectories,
|
|
3
|
+
createRuntimePackageResolutionPlugin,
|
|
4
|
+
} from './runtime-package-resolution';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The fork's renderer policy (head rendering, HTML template assembly and asset
|
|
8
|
+
* ordering) and server policy (localised loaders, error responses, telemetry,
|
|
9
|
+
* module-federation CSS and asset cache headers, static serving) are the
|
|
10
|
+
* default behaviour of an UltraModern.js app.
|
|
11
|
+
*
|
|
12
|
+
* They live in their own packages so they can also be composed explicitly, but
|
|
13
|
+
* a plain `appTools()` app gets them without opting in — that is what this fork
|
|
14
|
+
* has always done. Pass `appTools({ rendererExtensions: false })` or
|
|
15
|
+
* `appTools({ serverExtensions: false })` to run without them.
|
|
16
|
+
*/
|
|
17
|
+
export const RENDERER_EXTENSIONS_PACKAGE =
|
|
18
|
+
'@modern-js/runtime-renderer-extensions';
|
|
19
|
+
|
|
20
|
+
export const RENDERER_EXTENSIONS_PLUGIN_NAME = 'rendererHead';
|
|
21
|
+
|
|
22
|
+
export const SERVER_EXTENSIONS_PLUGIN_NAME =
|
|
23
|
+
'@modern-js/app-tools/server-plugin';
|
|
24
|
+
|
|
25
|
+
export interface PolicyDefaultsOptions {
|
|
26
|
+
/** Default `true`. Set to `false` to drop the fork's renderer policy. */
|
|
27
|
+
rendererExtensions?: boolean;
|
|
28
|
+
/** Default `true`. Set to `false` to drop the fork's server policy. */
|
|
29
|
+
serverExtensions?: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
type RuntimePluginDescriptor = {
|
|
33
|
+
name?: string;
|
|
34
|
+
path: string;
|
|
35
|
+
config?: unknown;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
type ServerPluginDescriptor = { name: string };
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The subset of the CLI plugin API these defaults use. Typed structurally, and
|
|
42
|
+
* loosely at the hook boundary, so this package stays free of a dependency on
|
|
43
|
+
* the solution that consumes it — which depends on this one.
|
|
44
|
+
*/
|
|
45
|
+
export interface PolicyDefaultsPluginApi {
|
|
46
|
+
_internalRuntimePlugins(fn: (input: any) => any): void;
|
|
47
|
+
_internalServerPlugins(fn: (input: any) => any): void;
|
|
48
|
+
modifyResolvedConfig(fn: (config: any) => any): void;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
type RuntimePluginsInput = {
|
|
52
|
+
entrypoint: unknown;
|
|
53
|
+
plugins: RuntimePluginDescriptor[];
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
type ServerPluginsInput = { plugins: ServerPluginDescriptor[] };
|
|
57
|
+
|
|
58
|
+
export const POLICY_DEFAULTS_PLUGIN_NAME =
|
|
59
|
+
'@modern-js/ultramodern-policy-defaults';
|
|
60
|
+
|
|
61
|
+
/** Registers the fork's default renderer and server policy. */
|
|
62
|
+
export const applyPolicyDefaults = (
|
|
63
|
+
api: PolicyDefaultsPluginApi,
|
|
64
|
+
options: PolicyDefaultsOptions = {},
|
|
65
|
+
): void => {
|
|
66
|
+
if (options.rendererExtensions !== false) {
|
|
67
|
+
api._internalRuntimePlugins(
|
|
68
|
+
({ entrypoint, plugins }: RuntimePluginsInput) => {
|
|
69
|
+
// An explicit composition (`ultramodernAppTools()`) may already have
|
|
70
|
+
// registered it; the descriptor list must stay free of duplicates.
|
|
71
|
+
if (
|
|
72
|
+
!plugins.some(plugin => plugin.path === RENDERER_EXTENSIONS_PACKAGE)
|
|
73
|
+
) {
|
|
74
|
+
plugins.push({
|
|
75
|
+
name: RENDERER_EXTENSIONS_PLUGIN_NAME,
|
|
76
|
+
path: RENDERER_EXTENSIONS_PACKAGE,
|
|
77
|
+
config: {},
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
return { entrypoint, plugins };
|
|
81
|
+
},
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const moduleDirectories = collectRuntimePackageModuleDirectories(
|
|
85
|
+
[RENDERER_EXTENSIONS_PACKAGE],
|
|
86
|
+
import.meta.url,
|
|
87
|
+
);
|
|
88
|
+
if (moduleDirectories.length > 0) {
|
|
89
|
+
api.modifyResolvedConfig(config => ({
|
|
90
|
+
...config,
|
|
91
|
+
builderPlugins: [
|
|
92
|
+
...(config.builderPlugins ?? []),
|
|
93
|
+
createRuntimePackageResolutionPlugin(moduleDirectories),
|
|
94
|
+
],
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (options.serverExtensions !== false) {
|
|
100
|
+
api._internalServerPlugins(({ plugins }: ServerPluginsInput) => {
|
|
101
|
+
if (
|
|
102
|
+
!plugins.some(plugin => plugin.name === SERVER_EXTENSIONS_PLUGIN_NAME)
|
|
103
|
+
) {
|
|
104
|
+
plugins.push({ name: SERVER_EXTENSIONS_PLUGIN_NAME });
|
|
105
|
+
}
|
|
106
|
+
return { plugins };
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* The fork defaults as a CLI plugin.
|
|
113
|
+
*
|
|
114
|
+
* The descriptor this registers may land before the ones it wraps — CLI
|
|
115
|
+
* ordering cannot be constrained here without a cycle, because the plugins
|
|
116
|
+
* that emit those descriptors are themselves ordered after `appTools()`.
|
|
117
|
+
* Ordering is settled on the runtime side instead: `rendererHeadPlugin`
|
|
118
|
+
* declares the runtime plugins that run before it.
|
|
119
|
+
*/
|
|
120
|
+
export const createPolicyDefaultsPlugin = (
|
|
121
|
+
options: PolicyDefaultsOptions = {},
|
|
122
|
+
) => ({
|
|
123
|
+
name: POLICY_DEFAULTS_PLUGIN_NAME,
|
|
124
|
+
setup(api: PolicyDefaultsPluginApi) {
|
|
125
|
+
applyPolicyDefaults(api, options);
|
|
126
|
+
},
|
|
127
|
+
});
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import type { RsbuildPlugin, Rspack } from '@rsbuild/core';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A generated `runtime-register.js` lives inside the *application*, so every
|
|
9
|
+
* runtime plugin it imports has to resolve from the application's own
|
|
10
|
+
* `node_modules`. Packages registered by a CLI plugin are dependencies of that
|
|
11
|
+
* CLI plugin, not of the application, and under an isolated (pnpm) linker the
|
|
12
|
+
* application cannot see them — the build fails with `Module not found`.
|
|
13
|
+
*
|
|
14
|
+
* Instead of freezing a single resolved file (which would lock one export
|
|
15
|
+
* condition and break the web/node split), the registering package contributes
|
|
16
|
+
* the `node_modules` directory that actually hosts the package as a *fallback*
|
|
17
|
+
* module directory. Bare specifiers keep their normal `exports` resolution, the
|
|
18
|
+
* application's own copy still wins when it declares the dependency, and both
|
|
19
|
+
* the workspace source layout and a published pnpm layout work.
|
|
20
|
+
*/
|
|
21
|
+
export const findHostingModuleDirectory = (
|
|
22
|
+
packageName: string,
|
|
23
|
+
fromDirectory: string,
|
|
24
|
+
): string | undefined => {
|
|
25
|
+
let directory = path.resolve(fromDirectory);
|
|
26
|
+
for (;;) {
|
|
27
|
+
const candidate = path.join(directory, 'node_modules');
|
|
28
|
+
if (fs.existsSync(path.join(candidate, packageName))) {
|
|
29
|
+
return candidate;
|
|
30
|
+
}
|
|
31
|
+
const parent = path.dirname(directory);
|
|
32
|
+
if (parent === directory) {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
directory = parent;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Collect the fallback module directories for the given packages, starting the
|
|
41
|
+
* search at the module that registers them.
|
|
42
|
+
*/
|
|
43
|
+
export const collectRuntimePackageModuleDirectories = (
|
|
44
|
+
packageNames: readonly string[],
|
|
45
|
+
registrarUrl: string,
|
|
46
|
+
): string[] => {
|
|
47
|
+
const registrarDirectory = path.dirname(fileURLToPath(registrarUrl));
|
|
48
|
+
const directories: string[] = [];
|
|
49
|
+
for (const packageName of packageNames) {
|
|
50
|
+
const directory = findHostingModuleDirectory(
|
|
51
|
+
packageName,
|
|
52
|
+
registrarDirectory,
|
|
53
|
+
);
|
|
54
|
+
if (directory && !directories.includes(directory)) {
|
|
55
|
+
directories.push(directory);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return directories;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const appendModuleDirectories = (
|
|
62
|
+
config: Rspack.Configuration,
|
|
63
|
+
directories: readonly string[],
|
|
64
|
+
) => {
|
|
65
|
+
if (directories.length === 0) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
config.resolve ??= {};
|
|
69
|
+
const existing = config.resolve.modules ?? ['node_modules'];
|
|
70
|
+
// Appended, never prepended: the application's own upward `node_modules`
|
|
71
|
+
// search keeps priority, so a declared dependency still wins.
|
|
72
|
+
config.resolve.modules = [
|
|
73
|
+
...existing,
|
|
74
|
+
...directories.filter(directory => !existing.includes(directory)),
|
|
75
|
+
];
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Rsbuild plugin that adds the given directories as fallback module roots for
|
|
80
|
+
* every environment (web, node and worker bundles alike).
|
|
81
|
+
*/
|
|
82
|
+
export const createRuntimePackageResolutionPlugin = (
|
|
83
|
+
directories: readonly string[],
|
|
84
|
+
): RsbuildPlugin => ({
|
|
85
|
+
name: 'ultramodern:runtime-package-resolution',
|
|
86
|
+
setup(api) {
|
|
87
|
+
api.modifyRspackConfig({
|
|
88
|
+
order: 'post',
|
|
89
|
+
handler(config) {
|
|
90
|
+
appendModuleDirectories(config, directories);
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
api.onBeforeCreateCompiler({
|
|
94
|
+
order: 'post',
|
|
95
|
+
handler({ bundlerConfigs }) {
|
|
96
|
+
for (const config of bundlerConfigs) {
|
|
97
|
+
appendModuleDirectories(config, directories);
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
/** `true` when the package resolves from the registering module at all. */
|
|
105
|
+
export const canResolveRuntimePackage = (
|
|
106
|
+
packageName: string,
|
|
107
|
+
registrarUrl: string,
|
|
108
|
+
): boolean => {
|
|
109
|
+
try {
|
|
110
|
+
createRequire(registrarUrl).resolve(packageName);
|
|
111
|
+
return true;
|
|
112
|
+
} catch {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
};
|