Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some relative module imports fail in preload with Module "(path)" not found! #1373

Closed
cmidgley opened this issue Jul 19, 2024 · 2 comments
Closed

Comments

@cmidgley
Copy link
Contributor

Build environment: Windows
Moddable SDK version: Latest released
Target device: Win, ESP32

Description
Another path resolution issue similar to #1372, but this time with preload. It appears that preload is unable to resolve some relative module loads using the private-scope style (root/#module/...). I've found that it works with ..\myfile.js but not ..\..\myfile.js, such as "import { xyz } from "../../myfile.js";" where it reports Module "../../myfile.js" not found!.

See this repo for a small demo of the problem. If you remove the preload, the module runs fine, but with the preload the build fails with:

ReferenceError: module "../../root.js" not found
### ReferenceError: module "../../root.js" not found!
NMAKE : fatal error U1077: 'xsl args.txt ' : return code '0xd'
Stop.

Steps to Reproduce

  1. Clone this repo
  2. Build with mcconfig -m -d and see the preload failure
  3. Remove the preload from manifest.json
  4. Build again, and see the module runs fine
@phoddie
Copy link
Collaborator

phoddie commented Aug 2, 2024

The XS linker (xsl) performs the preload operation. It didn't implement support for module specifiers containing ../../specifier. This hasn't generally been an issue because module specifiers in XS are not usually paths. It comes up when preloading modules from Node packages in XS.

We've got a fix for that which works for your test case. The changes will be in the next repository update. If you want to try them sooner, here's the updated fxFindModule function.

source code
txID fxFindModule(txMachine* the, txSlot* realm, txID moduleID, txSlot* slot)
{
	txLinker* linker = (txLinker*)(the->context);
	char name[C_PATH_MAX];
	char buffer[C_PATH_MAX];
	char separator;
	txInteger dot = 0;
	txInteger i = 0;
	txInteger hash = 0;
	txString slash;
	txString path;
	txID id;
		
	fxToStringBuffer(the, slot, name, sizeof(name) - 4);
	if (name[0] == '.') {
		if (name[1] == '/') {
			dot = 1;
			i = 1;
		}
		else if ((name[1] == '.') && (name[2] == '/')) {
			dot = 2;
			i = 2;
			while ((name[i + 1] == '.') && (name[i + 2] == '.') && (name[i + 3] == '/')) {
				dot++;
				i += 3;
			}
		}
	}
	else if (name[0] == '#') {
		hash = 1;
	}
	else if (c_strncmp(name, "moddable:", 9) == 0)
		c_memmove(name, name + 9, c_strlen(name) - 8);
	
	separator = linker->base[0];
	fxSlashPath(name, '/', separator);
	slash = c_strrchr(name, separator);
	if (!slash)
		slash = name;
	slash = c_strrchr(slash, '.');
	if (slash && (!c_strcmp(slash, ".js") || !c_strcmp(slash, ".mjs") || !c_strcmp(slash, ".xsb")))
		*slash = 0;
		
	if (dot > 0) {
		if (moduleID == XS_NO_ID)
			return XS_NO_ID;
		buffer[0] = separator;
		path = buffer + 1;
		c_strcpy(path, fxGetKeyName(the, moduleID));
		slash = c_strrchr(buffer, separator);
		if (!slash)
			return XS_NO_ID;
		*slash = 0;
		dot--;
		while (dot > 0) {
			slash = c_strrchr(buffer, separator);
			if (!slash)
				return XS_NO_ID;
			*slash = 0;
			dot--;
		}
		if ((c_strlen(buffer) + c_strlen(name + i)) >= sizeof(buffer))
			mxRangeError("path too long");
		c_strcat(buffer, name + i);
	}
	else if (hash) {
		if (moduleID == XS_NO_ID)
			return XS_NO_ID;
		path = buffer;
		c_strcpy(path, fxGetKeyName(the, moduleID));
		slash = c_strchr(buffer, separator);
		if (!slash)
			return XS_NO_ID;
		if (path[0] == '@') {
			slash = c_strchr(slash + 1, mxSeparator);
			if (!slash)
				return XS_NO_ID;
		}
		*(slash + 1) = 0;
		if ((c_strlen(buffer) + c_strlen(name)) >= sizeof(buffer))
			mxRangeError("path too long");
		c_strcat(buffer, name);
	}
	else
		path = name;
		
	if (fxFindScript(the, path, &id))
		return id;
	return XS_NO_ID;
}

Note: the example's manifest preloads "root/main". That causes "root/#another" to be preloaded too, so it executes the traces at link time (you will see them as part of the build output). To make the test do something meaningful at runtime, preload "root/#another" instead.

@cmidgley
Copy link
Contributor Author

cmidgley commented Sep 2, 2024

All my private modules preload - totally awesome. Thanks!

@cmidgley cmidgley closed this as completed Sep 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants