1
+ #include < filesystem>
1
2
#pragma warning(disable : 4251)
2
3
3
- #include " main/NodeJsHelper.h"
4
-
5
4
#include " api/EventAPI.h"
6
5
#include " engine/EngineManager.h"
7
6
#include " engine/EngineOwnData.h"
8
7
#include " engine/RemoteCall.h"
8
+ #include " fmt/format.h"
9
9
#include " ll/api/chrono/GameChrono.h"
10
10
#include " ll/api/coro/CoroTask.h"
11
11
#include " ll/api/io/FileUtils.h"
14
14
#include " ll/api/thread/ServerThreadExecutor.h"
15
15
#include " ll/api/utils/StringUtils.h"
16
16
#include " main/Global.h"
17
+ #include " main/NodeJsHelper.h"
17
18
#include " uv/uv.h"
18
19
#include " v8/v8.h"
19
20
@@ -130,14 +131,17 @@ script::ScriptEngine* newEngine() {
130
131
return engine;
131
132
}
132
133
133
- bool loadPluginCode (script::ScriptEngine* engine, std::string entryScriptPath, std::string pluginDirPath) {
134
- auto mainScripts = ll::file_utils::readFile (ll::string_utils::str2u8str (entryScriptPath));
135
- if (!mainScripts) {
136
- return false ;
137
- }
138
-
134
+ bool loadPluginCode (script::ScriptEngine* engine, std::string entryScriptPath, std::string pluginDirPath, bool esm) {
139
135
// Process requireDir
140
136
if (!pluginDirPath.ends_with (' /' )) pluginDirPath += " /" ;
137
+
138
+ // check if entryScriptPath is not absolute path
139
+ if (auto path = std::filesystem::path (entryScriptPath); !path.is_absolute ()) {
140
+ entryScriptPath = std::filesystem::absolute (path).string ();
141
+ }
142
+ if (auto path = std::filesystem::path (pluginDirPath); !path.is_absolute ()) {
143
+ pluginDirPath = std::filesystem::absolute (path).string ();
144
+ }
141
145
pluginDirPath = ll::string_utils::replaceAll (pluginDirPath, " \\ " , " /" );
142
146
entryScriptPath = ll::string_utils::replaceAll (entryScriptPath, " \\ " , " /" );
143
147
@@ -151,23 +155,58 @@ bool loadPluginCode(script::ScriptEngine* engine, std::string entryScriptPath, s
151
155
using namespace v8 ;
152
156
EngineScope enter (engine);
153
157
154
- string executeJs = " const __LLSE_PublicRequire = "
155
- " require('module').createRequire(process.cwd() + '/"
156
- + pluginDirPath + " ');"
157
- + " const __LLSE_PublicModule = require('module'); "
158
- " __LLSE_PublicModule.exports = {};"
159
- + " ll.export = ll.exports; ll.import = ll.imports; "
160
-
161
- + " (function (exports, require, module, __filename, __dirname) { " + mainScripts.value ()
162
- + " \n })({}, __LLSE_PublicRequire, __LLSE_PublicModule, '" + entryScriptPath + " ', '"
163
- + pluginDirPath + " '); " ; // TODO __filename & __dirname need to be reviewed
164
- // TODO: ESM Support
158
+ string compiler;
159
+ if (esm) {
160
+ compiler = fmt::format (
161
+ R"(
162
+ import('url').then(url => {{
163
+ const moduleUrl = url.pathToFileURL('{1}').href;
164
+ import(moduleUrl).catch(error => {{
165
+ console.error('Failed to load ESM module:', error);
166
+ process.exit(1);
167
+ }});
168
+ }}).catch(error => {{
169
+ console.error('Failed to import url module:', error);
170
+ process.exit(1);
171
+ }});
172
+ )" ,
173
+ pluginDirPath,
174
+ entryScriptPath
175
+ );
176
+ } else {
177
+ compiler = fmt::format (
178
+ R"(
179
+ const __Path = require("path");
180
+ const __PluginPath = __Path.join("{0}");
181
+ const __PluginNodeModulesPath = __Path.join(__PluginPath, "node_modules");
182
+
183
+ __dirname = __PluginPath;
184
+ __filename = "{1}";
185
+ (function ReplaeRequire() {{
186
+ const PublicModule = require('module').Module;
187
+ const OriginalResolveLookupPaths = PublicModule._resolveLookupPaths;
188
+ PublicModule._resolveLookupPaths = function (request, parent) {{
189
+ let result = OriginalResolveLookupPaths.call(this, request, parent);
190
+ if (Array.isArray(result)) {{
191
+ result.push(__PluginNodeModulesPath);
192
+ result.push(__PluginPath);
193
+ }}
194
+ return result;
195
+ }};
196
+ require = PublicModule.createRequire(__PluginPath);
197
+ }})();
198
+ require("{1}");
199
+ )" ,
200
+ pluginDirPath,
201
+ entryScriptPath
202
+ );
203
+ }
165
204
166
205
// Set exit handler
167
206
node::SetProcessExitHandler (env, [](node::Environment* env_, int exit_code) { stopEngine (getEngine (env_)); });
168
207
169
208
// Load code
170
- MaybeLocal<v8::Value> loadenv_ret = node::LoadEnvironment (env, executeJs .c_str ());
209
+ MaybeLocal<v8::Value> loadenv_ret = node::LoadEnvironment (env, compiler .c_str ());
171
210
if (loadenv_ret.IsEmpty ()) // There has been a JS exception.
172
211
{
173
212
node::Stop (env);
@@ -311,6 +350,25 @@ bool doesPluginPackHasDependency(const std::string& dirPath) {
311
350
}
312
351
}
313
352
353
+ bool isESModulesSystem (const std::string& dirPath) {
354
+ auto dirPath_obj = std::filesystem::path (dirPath);
355
+
356
+ std::filesystem::path packageFilePath = dirPath_obj / std::filesystem::path (" package.json" );
357
+ if (!std::filesystem::exists (packageFilePath)) return false ;
358
+
359
+ try {
360
+ std::ifstream file (ll::string_utils::u8str2str (packageFilePath.make_preferred ().u8string ()));
361
+ nlohmann::json j;
362
+ file >> j;
363
+ if (j.contains (" type" ) && j[" type" ] == " module" ) {
364
+ return true ;
365
+ }
366
+ return false ;
367
+ } catch (...) {
368
+ return false ;
369
+ }
370
+ }
371
+
314
372
bool processConsoleNpmCmd (const std::string& cmd) {
315
373
#ifdef LEGACY_SCRIPT_ENGINE_BACKEND_NODEJS
316
374
if (cmd.starts_with (" npm " )) {
0 commit comments