1+ #include  < filesystem> 
12#pragma  warning(disable : 4251)
23
3- #include  " main/NodeJsHelper.h" 
4- 
54#include  " api/EventAPI.h" 
65#include  " engine/EngineManager.h" 
76#include  " engine/EngineOwnData.h" 
87#include  " engine/RemoteCall.h" 
8+ #include  " fmt/format.h" 
99#include  " ll/api/chrono/GameChrono.h" 
1010#include  " ll/api/coro/CoroTask.h" 
1111#include  " ll/api/io/FileUtils.h" 
1414#include  " ll/api/thread/ServerThreadExecutor.h" 
1515#include  " ll/api/utils/StringUtils.h" 
1616#include  " main/Global.h" 
17+ #include  " main/NodeJsHelper.h" 
1718#include  " uv/uv.h" 
1819#include  " v8/v8.h" 
1920
@@ -130,14 +131,17 @@ script::ScriptEngine* newEngine() {
130131    return  engine;
131132}
132133
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) {
139135    //  Process requireDir
140136    if  (!pluginDirPath.ends_with (' /' " /" 
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+     }
141145    pluginDirPath   = ll::string_utils::replaceAll (pluginDirPath, " \\ " " /" 
142146    entryScriptPath = ll::string_utils::replaceAll (entryScriptPath, " \\ " " /" 
143147
@@ -151,23 +155,58 @@ bool loadPluginCode(script::ScriptEngine* engine, std::string entryScriptPath, s
151155        using  namespace  v8 ; 
152156        EngineScope enter (engine);
153157
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) { " value ()
162-                          + " \n })({}, __LLSE_PublicRequire, __LLSE_PublicModule, '" " ', '" 
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+         }
165204
166205        //  Set exit handler
167206        node::SetProcessExitHandler (env, [](node::Environment* env_, int  exit_code) { stopEngine (getEngine (env_)); });
168207
169208        //  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 ());
171210        if  (loadenv_ret.IsEmpty ()) //  There has been a JS exception.
172211        {
173212            node::Stop (env);
@@ -311,6 +350,25 @@ bool doesPluginPackHasDependency(const std::string& dirPath) {
311350    }
312351}
313352
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" " type" " module" 
364+             return  true ;
365+         }
366+         return  false ;
367+     } catch  (...) {
368+         return  false ;
369+     }
370+ }
371+ 
314372bool  processConsoleNpmCmd (const  std::string& cmd) {
315373#ifdef  LEGACY_SCRIPT_ENGINE_BACKEND_NODEJS
316374    if  (cmd.starts_with (" npm " 
0 commit comments