dop251 / goja_nodejs

Nodejs compatibility library for Goja
MIT License
336 stars 81 forks source link

Require lacks support for absolute paths #83

Open shixiawuheng opened 1 month ago

shixiawuheng commented 1 month ago

require.(RequireModule).loadModule (resolve.go:188) github.com/dop251/goja_nodejs/require require.(RequireModule).loadAsFile (resolve.go:90) github.com/dop251/goja_nodejs/require require.(RequireModule).loadAsFileOrDirectory (resolve.go:82) github.com/dop251/goja_nodejs/require require.(RequireModule).loadNodeModule (resolve.go:136) github.com/dop251/goja_nodejs/require require.(RequireModule).loadNodeModules (resolve.go:152) github.com/dop251/goja_nodejs/require require.(RequireModule).resolve (resolve.go:48) github.com/dop251/goja_nodejs/require require.(RequireModule).Require (module.go:182) github.com/dop251/goja_nodejs/require require.(RequireModule).require (module.go:166) github.com/dop251/goja_nodejs/require

:2 goja.(*nativeFuncObject).vmCall (func.go:563) github.com/dop251/goja goja.call.exec (vm.go:3629) github.com/dop251/goja :2 goja.(*vm).run (vm.go:628) github.com/dop251/goja goja.(*vm).runTryInner (vm.go:880) github.com/dop251/goja goja.(*vm).runTry (vm.go:866) github.com/dop251/goja goja.(*Runtime).RunProgram (runtime.go:1472) github.com/dop251/goja goja.(*Runtime).RunScript (runtime.go:1408) github.com/dop251/goja goja.(*Runtime).RunString (runtime.go:1397) github.com/dop251/goja Client.TestVerSion (Client_test.go:10) Amp/Client testing.tRunner (testing.go:1689) testing testing.(*T).Run.gowrap1 (testing.go:1742) testing runtime.goexit (asm_amd64.s:1695) runtime ---以上是执行堆栈 I used an absolute path to introduce require ('D: \ \ Code \ \ node \ \ test \\ dist \\ bundle. js') during debugging, which resulted in incorrect parsing When the loadModule parameter path is reached, it has changed to /node_modules/D:\Code\node\test\dist\bundle.js
ganigeorgiev commented 1 month ago

I'm not the maintainer of goja, but I've made a contribution in the past in relation to loading Windows paths so it is possible that either my solution doesn't handle all cases or that you are running in a non-Windows environment.

I don't have access to a Windows VM at the moment to test it but the last time I checked it worked fine with Windows absolute paths (there is also an automated test for this case in the linked PR).

The caveat though is that loading Windows paths works only when the running program operating system target is Windows (runtime.GOOS == "windows"), aka. I'm not sure if this will work if you are running under WSL for example.

To rule out this you can try to print runtime.GOOS before running the goja script to ensure that it outputs windows. If it prints something else (e.g. linux) then loading Windows absolute paths as it is will not work (and I'm not sure if it should to be honest because Node.js on Linux will most likely also fail loading Windows absolute paths).

But in general, I'd personally would avoid using Windows paths. If that's not possible, one workaround for "universal" absolute paths loading I use in one of my projects is to define programmatically a global goja variable that holds the path to the current working directory or to the executable (_kind of similar to the Node.js __dirname_) and then concatenate that with the specific local module path. For example:

vm := goja.New()

// set the current working directory or any other path as global variable
// (see https://pkg.go.dev/os#Getwd)
cwd, _ := os.Getwd()
vm.Set("__dirname", cwd)

// should work also with Windows separator too (\)
vm.RunString("require(`${__dirname}/my/local/module.js`)")
shixiawuheng commented 1 month ago

Firstly, I appreciate your response! I can fix this absolute path issue myself! I have identified an issue while tracking the stack! https://github.com/dop251/goja_nodejs/blob/master/require/resolve.go Line 240 `func (r RequireModule) loadNodeModules(modpath, start string) (module js.Object, err error) { for _, dir := range r.r.globalFolders { if module, err = r.loadNodeModule(modpath, dir); module != nil || err != nil { return } } for { // The following code is the culprit behind this reason var p string if path.Base(start) != "node_modules" { //When loaded with an absolute path, this block will assign the value p to node_modules p = path.Join(start, "node_modules") } else { p = start } //We will merge p and modpath here , I think we can make a judgment on whether a file exists here. If the file exists, there is no need to process it if module, err = r.loadNodeModule(modpath, p); module != nil || err != nil { return } if start == ".." { // Dir('..') is '.' break } parent := path.Dir(start) if parent == start { break } start = parent }

return nil, InvalidModuleError

}`

shixiawuheng commented 1 month ago

I understand that my file writing is not standardized! Because I am only doing simple debugging work and I do not rely heavily on JavaScript, only for simple scripting work. Thank you again for your reply