Skip to content

Commit 88c3060

Browse files
fix: Improved node_modules handling during game exports.
- Internally, scripts now retain their module dependency hierarchy, even when the module being loaded was previously cached. Prior to this fix, scripts incorrectly only stored dependencies that were not previously encountered as a dependency of another script. - .cjs extension is now more widely support. Previously support was limited to being imported from a GodotJS script, but .cjs files themselves were not considered scripts. This caused .cjs files contained within node_modules to be incorrectly omitted during export since they weren't recognized as scripts. - No longer blingly bundling transitive node_modules. Really, we don't support transitive node_modules. node_modules should be hoisted.
1 parent 54aa108 commit 88c3060

File tree

10 files changed

+73
-56
lines changed

10 files changed

+73
-56
lines changed

.changeset/moody-cars-sell.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@godot-js/editor": patch
3+
---
4+
5+
fix: Improved node_modules handling during game exports.

bridge/jsb_environment.cpp

Lines changed: 49 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1058,10 +1058,10 @@ namespace jsb
10581058
JavaScriptModule* Environment::_load_module(const String& p_parent_id, const String& p_module_id)
10591059
{
10601060
JSB_BENCHMARK_SCOPE(JSRealm, _load_module);
1061-
JavaScriptModule* existing_module = module_cache_.find(p_module_id);
1062-
if (existing_module && !existing_module->is_reloading())
1061+
JavaScriptModule* resolved_module = module_cache_.find(p_module_id);
1062+
if (resolved_module && !resolved_module->is_reloading())
10631063
{
1064-
return existing_module;
1064+
return resolved_module;
10651065
}
10661066

10671067
v8::Isolate* isolate = this->isolate_;
@@ -1071,7 +1071,7 @@ namespace jsb
10711071
// find loader with the module id
10721072
if (IModuleLoader* loader = this->find_module_loader(p_module_id))
10731073
{
1074-
jsb_checkf(!existing_module, "module loader does not support reloading");
1074+
jsb_checkf(!resolved_module, "module loader does not support reloading");
10751075
JavaScriptModule& module = module_cache_.insert(isolate, context, p_module_id, false, false);
10761076

10771077
//NOTE the loader should throw error if failed
@@ -1107,35 +1107,37 @@ namespace jsb
11071107
const StringName module_id = source_info.source_filepath;
11081108

11091109
// check again with the resolved module_id
1110-
existing_module = module_cache_.find(module_id);
1111-
if (existing_module && !existing_module->is_reloading())
1112-
{
1113-
return existing_module;
1114-
}
1110+
resolved_module = module_cache_.find(module_id);
1111+
1112+
v8::Local<v8::Object> module_obj;
11151113

11161114
// supported module properties: id, filename, cache, loaded, exports, children
1117-
if (existing_module)
1115+
if (resolved_module)
11181116
{
1119-
jsb_check(existing_module->id == module_id);
1120-
jsb_check(existing_module->source_info.source_filepath == source_info.source_filepath);
1121-
1122-
JSB_LOG(VeryVerbose, "reload module %s", module_id);
1123-
existing_module->mark_as_reloaded();
1124-
if (!resolver->load(this, source_info.source_filepath, *existing_module))
1117+
if (resolved_module->is_reloading())
11251118
{
1126-
return nullptr;
1119+
jsb_check(resolved_module->id == module_id);
1120+
jsb_check(resolved_module->source_info.source_filepath == source_info.source_filepath);
1121+
1122+
JSB_LOG(VeryVerbose, "reload module %s", module_id);
1123+
resolved_module->mark_as_reloaded();
1124+
if (!resolver->load(this, source_info.source_filepath, *resolved_module))
1125+
{
1126+
return nullptr;
1127+
}
1128+
ScriptClassInfo::_parse_script_class(context, *resolved_module);
11271129
}
1128-
ScriptClassInfo::_parse_script_class(context, *existing_module);
1129-
return existing_module;
1130+
1131+
module_obj = resolved_module->module.Get(isolate);
11301132
}
11311133
else
11321134
{
11331135
JSB_LOG(Verbose, "instantiating module %s", module_id);
11341136
JavaScriptModule& module = module_cache_.insert(isolate, context, module_id, true, false);
11351137
v8::Local<v8::Object> exports_obj = v8::Object::New(isolate);
1136-
v8::Local<v8::Object> module_obj = module.module.Get(isolate);
11371138

11381139
// init the new module obj
1140+
module_obj = module.module.Get(isolate);
11391141
module_obj->Set(context, jsb_name(this, children), v8::Array::New(isolate)).Check();
11401142
module_obj->Set(context, jsb_name(this, exports), exports_obj).Check();
11411143
module.source_info = source_info;
@@ -1148,29 +1150,6 @@ namespace jsb
11481150
return nullptr;
11491151
}
11501152

1151-
// build the module tree
1152-
if (!p_parent_id.is_empty())
1153-
{
1154-
if (const JavaScriptModule* parent_ptr = module_cache_.find(p_parent_id))
1155-
{
1156-
const v8::Local<v8::Object> parent_module = parent_ptr->module.Get(isolate);
1157-
if (v8::Local<v8::Value> temp; parent_module->Get(context, jsb_name(this, children)).ToLocal(&temp) && temp->IsArray())
1158-
{
1159-
const v8::Local<v8::Array> children = temp.As<v8::Array>();
1160-
const uint32_t children_num = children->Length();
1161-
children->Set(context, children_num, module_obj).Check();
1162-
}
1163-
else
1164-
{
1165-
JSB_LOG(Error, "can not access children on '%s'", p_parent_id);
1166-
}
1167-
}
1168-
else
1169-
{
1170-
JSB_LOG(Warning, "parent module not found with the name '%s'", p_parent_id);
1171-
}
1172-
}
1173-
11741153
module.on_load(isolate, context);
11751154
{
11761155
const impl::TryCatch try_catch_run(isolate);
@@ -1180,8 +1159,34 @@ namespace jsb
11801159
JSB_LOG(Error, "something wrong when parsing '%s'\n%s", module_id, BridgeHelper::get_exception(try_catch_run));
11811160
}
11821161
}
1183-
return &module;
1162+
1163+
resolved_module = &module;
1164+
}
1165+
1166+
// build the module tree
1167+
if (!p_parent_id.is_empty())
1168+
{
1169+
if (const JavaScriptModule* parent_ptr = module_cache_.find(p_parent_id))
1170+
{
1171+
const v8::Local<v8::Object> parent_module = parent_ptr->module.Get(isolate);
1172+
if (v8::Local<v8::Value> temp; parent_module->Get(context, jsb_name(this, children)).ToLocal(&temp) && temp->IsArray())
1173+
{
1174+
const v8::Local<v8::Array> children = temp.As<v8::Array>();
1175+
const uint32_t children_num = children->Length();
1176+
children->Set(context, children_num, module_obj).Check();
1177+
}
1178+
else
1179+
{
1180+
JSB_LOG(Error, "can not access children on '%s'", p_parent_id);
1181+
}
1182+
}
1183+
else
1184+
{
1185+
JSB_LOG(Warning, "parent module not found with the name '%s'", p_parent_id);
1186+
}
11841187
}
1188+
1189+
return resolved_module;
11851190
}
11861191

11871192
impl::Helper::throw_error(isolate, jsb_format("unknown module: %s", normalized_id));

internal/jsb_path_util.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,14 @@ namespace jsb::internal
9595

9696
String PathUtil::convert_javascript_path(const String& p_source_path)
9797
{
98-
if (p_source_path.ends_with("." JSB_JAVASCRIPT_EXT))
98+
bool is_js_extension = p_source_path.ends_with("." JSB_JAVASCRIPT_EXT);
99+
if (is_js_extension || p_source_path.ends_with("." JSB_COMMONJS_EXT))
99100
{
101+
int extension_length = is_js_extension ? 3 : 4;
100102
const String root_path = Settings::get_jsb_out_res_path();
101103
jsb_checkf(p_source_path.begins_with(root_path), "can not proceed javascript sources not under the project data directory");
102104
const String replaced = String("res://").path_join(
103-
p_source_path.substr(root_path.length() + 1, p_source_path.length() - root_path.length() - 3)
105+
p_source_path.substr(root_path.length() + 1, p_source_path.length() - root_path.length() - extension_length)
104106
+ JSB_TYPESCRIPT_EXT);
105107
return replaced;
106108
}

internal/jsb_settings.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ namespace jsb::internal
7979
if (!inited)
8080
{
8181
inited = true;
82-
static constexpr char filter[] = "*." JSB_JAVASCRIPT_EXT
82+
static constexpr char filter[] = "*." JSB_JAVASCRIPT_EXT ",*." JSB_COMMONJS_EXT
8383
#if JSB_USE_TYPESCRIPT
8484
",*." JSB_TYPESCRIPT_EXT
8585
#endif

weaver-editor/jsb_editor_plugin.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ void GodotJSEditorPlugin::collect_invalid_files(const String& p_path, Vector<Str
436436
}
437437
else
438438
{
439-
if (!it_path.ends_with("." JSB_JAVASCRIPT_EXT) || !FileAccess::exists(jsb::internal::PathUtil::convert_javascript_path(it_path)))
439+
if (!(it_path.ends_with("." JSB_JAVASCRIPT_EXT) || it_path.ends_with("." JSB_COMMONJS_EXT)) || !FileAccess::exists(jsb::internal::PathUtil::convert_javascript_path(it_path)))
440440
{
441441
// invalid if it's not a source map file, or no corresponding .js file exist
442442
if (!it_path.ends_with("." JSB_JAVASCRIPT_EXT ".map") || !FileAccess::exists(it_path.substr(0, it_path.length() - 4)))

weaver-editor/jsb_export_plugin.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ void GodotJSExportPlugin::export_raw_files(const PackedStringArray &p_paths, boo
4545
}
4646
}
4747

48-
void GodotJSExportPlugin::get_script_resources(const String &p_dir, Vector<String> &r_list)
48+
void GodotJSExportPlugin::get_script_resources(const String &p_dir, Vector<String> &r_list, bool p_is_node_module)
4949
{
5050
Ref<DirAccess> dir = DirAccess::open(p_dir);
5151

@@ -60,7 +60,7 @@ void GodotJSExportPlugin::get_script_resources(const String &p_dir, Vector<Strin
6060

6161
while (!filename.is_empty())
6262
{
63-
if (filename == "." || filename == "..")
63+
if (filename == "." || filename == ".." || (p_is_node_module && filename == "node_modules"))
6464
{
6565
filename = dir->get_next();
6666
continue;
@@ -70,7 +70,7 @@ void GodotJSExportPlugin::get_script_resources(const String &p_dir, Vector<Strin
7070

7171
if (dir->current_is_dir())
7272
{
73-
get_script_resources(path, r_list);
73+
get_script_resources(path, r_list, p_is_node_module);
7474
}
7575
else if (ResourceLoader::get_resource_type(path) == jsb_typename(GodotJSScript) && !get_ignored_paths().has(path))
7676
{
@@ -175,7 +175,7 @@ bool GodotJSExportPlugin::export_compiled_script(const String& p_path)
175175

176176
String package_path = p_path.substr(0, package_path_slash_index);
177177
Vector<String> script_paths;
178-
get_script_resources(package_path, script_paths);
178+
get_script_resources(package_path, script_paths, true);
179179

180180
const String package_json_path = jsb::internal::PathUtil::combine(package_path, "package.json");
181181

weaver-editor/jsb_export_plugin.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class GodotJSExportPlugin: public EditorExportPlugin
3434
bool export_module_files(const jsb::JavaScriptModule& p_module);
3535
bool export_raw_file(const String& p_path);
3636
void export_raw_files(const PackedStringArray& p_paths, bool p_permit_typescript);
37-
void get_script_resources(const String &p_dir, Vector<String> &r_list);
37+
void get_script_resources(const String &p_dir, Vector<String> &r_list, bool p_is_node_module = false);
3838

3939
HashSet<String> exported_paths_;
4040
std::shared_ptr<jsb::Environment> env_;

weaver/jsb_resource_loader.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ namespace
1313
|| p_path.ends_with(".worker." JSB_TYPESCRIPT_EXT)
1414
# endif
1515
|| p_path.ends_with(".worker." JSB_JAVASCRIPT_EXT)
16+
|| p_path.ends_with(".worker." JSB_COMMONJS_EXT)
1617
#endif
1718
;
1819
}
@@ -25,6 +26,7 @@ namespace
2526
|| p_path.ends_with(".test." JSB_TYPESCRIPT_EXT)
2627
# endif
2728
|| p_path.ends_with(".test." JSB_JAVASCRIPT_EXT)
29+
|| p_path.ends_with(".test." JSB_COMMONJS_EXT)
2830
#endif
2931
;
3032
}
@@ -67,7 +69,7 @@ Ref<Resource> ResourceFormatLoaderGodotJSScript::load(const String& p_path, cons
6769
return {};
6870
}
6971
#endif
70-
jsb_check(p_path.ends_with(JSB_TYPESCRIPT_EXT) || p_path.ends_with(JSB_JAVASCRIPT_EXT));
72+
jsb_check(p_path.ends_with(JSB_TYPESCRIPT_EXT) || p_path.ends_with(JSB_JAVASCRIPT_EXT) || p_path.ends_with(JSB_COMMONJS_EXT));
7173

7274
// in case `node_modules` is not ignored (which is not expected though), we do not want any GodotJSScript to be generated from it.
7375
if (p_path.begins_with("res://node_modules"))
@@ -129,6 +131,7 @@ void ResourceFormatLoaderGodotJSScript::get_recognized_extensions(List<String>*
129131
p_extensions->push_back(JSB_TYPESCRIPT_EXT);
130132
#endif
131133
p_extensions->push_back(JSB_JAVASCRIPT_EXT);
134+
p_extensions->push_back(JSB_COMMONJS_EXT);
132135
}
133136

134137
bool ResourceFormatLoaderGodotJSScript::handles_type(const String& p_type) const
@@ -141,9 +144,9 @@ String ResourceFormatLoaderGodotJSScript::get_resource_type(const String& p_path
141144
const String el = p_path.get_extension().to_lower();
142145

143146
#if JSB_USE_TYPESCRIPT
144-
if (el == JSB_TYPESCRIPT_EXT || el == JSB_JAVASCRIPT_EXT)
147+
if (el == JSB_TYPESCRIPT_EXT || el == JSB_JAVASCRIPT_EXT || el == JSB_COMMONJS_EXT)
145148
#else
146-
if (el == JSB_JAVASCRIPT_EXT)
149+
if (el == JSB_JAVASCRIPT_EXT || el == JSB_COMMONJS_EXT)
147150
#endif // JSB_USE_TYPESCRIPT
148151
{
149152
return !is_worker_script(p_path) && !is_test_script(p_path)

weaver/jsb_resource_saver.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ void ResourceFormatSaverGodotJSScript::get_recognized_extensions(const Ref<Resou
3838
p_extensions->push_back(JSB_TYPESCRIPT_EXT);
3939
#endif
4040
p_extensions->push_back(JSB_JAVASCRIPT_EXT);
41+
p_extensions->push_back(JSB_COMMONJS_EXT);
4142
}
4243
}
4344

weaver/jsb_script_language.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,7 @@ void GodotJSScriptLanguage::get_recognized_extensions(List<String>* p_extensions
316316
p_extensions->push_back(JSB_TYPESCRIPT_EXT);
317317
#endif
318318
p_extensions->push_back(JSB_JAVASCRIPT_EXT);
319+
p_extensions->push_back(JSB_COMMONJS_EXT);
319320
}
320321

321322

0 commit comments

Comments
 (0)