gopherjs / gopherjs.github.io

GopherJS Playground
https://gopherjs.github.io/playground/
23 stars 12 forks source link

Try to write a playground like program, but failed to import the 3rd. library with compiled #51

Closed PeerXu closed 8 years ago

PeerXu commented 8 years ago

I want to compile some golang program online, but failed to compile (on compiler.Compile) it. There is my program.

package main

import (
    "bytes"
    "fmt"
    "go/ast"
    "go/parser"
    "go/token"
    "go/types"
    "time"

    "honnef.co/go/js/xhr"

    "github.com/gopherjs/gopherjs/compiler"
    "github.com/gopherjs/gopherjs/js"
)

func main() {
    codeReady := make(chan interface{})
    go func() {
        select {
        case <-time.After(1 * time.Second):
            close(codeReady)
        }
    }()
    codeString := `
package main
import "honnef.co/go/js/xhr"
func main() {
    req := xhr.NewRequest("GET", "pkg/strings.a.js")
    req.ResponseType = xhr.ArrayBuffer
    err := req.Send(nil)
    if err != nil || req.Status != 200 {
        return
    }
    println(req.Response)
}
`
    packages := make(map[string]*compiler.Archive)
    var pkgsToLoad map[string]struct{}
    importContext := &compiler.ImportContext{
        Packages: make(map[string]*types.Package),
        Import: func(path string) (*compiler.Archive, error) {
            if pkg, found := packages[path]; found {
                return pkg, nil
            }
            pkgsToLoad[path] = struct{}{}
            return &compiler.Archive{}, nil
        },
    }
    fileSet := token.NewFileSet()
    pkgsReceived := 0

    var run func(bool)
    run = func(loadOnly bool) {
        pkgsToLoad = make(map[string]struct{})
        file, err := parser.ParseFile(fileSet, "prog.go", []byte(codeString), parser.ParseComments)
        if err != nil {
            println("ParseFile: ", err)
            return
        }
        mainPkg, err := compiler.Compile("main", []*ast.File{file}, fileSet, importContext, false)
        if err != nil {
            println("Compile: ", err.Error())
            return
        }
        packages["main"] = mainPkg
        if err != nil && len(pkgsToLoad) == 0 {
            println(err)
            return
        }
        var allPkgs []*compiler.Archive
        if len(pkgsToLoad) == 0 {
            allPkgs, _ = compiler.ImportDependencies(mainPkg, importContext.Import)
        }

        if len(pkgsToLoad) != 0 {
            pkgsReceived = 0
            for path := range pkgsToLoad {
                url := "/pkg/" + path + ".a.js"
                req := xhr.NewRequest("GET", "pkg/"+path+".a.js")
                req.ResponseType = xhr.ArrayBuffer
                go func(path string) {
                    println("send request to " + url)
                    err := req.Send(nil)
                    println("recive response from " + url)
                    println(fmt.Sprintf("err: %v, status: %v", err, req.Status))
                    if err != nil || req.Status != 200 {
                        return
                    }
                    data := js.Global.Get("Uint8Array").New(req.Response).Interface().([]byte)
                    packages[path], err = compiler.ReadArchive(path+".a", path, bytes.NewReader(data), importContext.Packages)
                    if err != nil {
                        println(err)
                        return
                    }
                    pkgsReceived++
                    fmt.Printf("pkgsReceived: %v, len(pkgsToLoad): %v\n", pkgsReceived, len(pkgsToLoad))
                    if pkgsReceived == len(pkgsToLoad) {
                        run(loadOnly)
                    }
                }(path)
            }
            return
        }

        if loadOnly {
            return
        }

        jsCode := bytes.NewBuffer(nil)
        jsCode.WriteString("try{\n")
        compiler.WriteProgramCode(allPkgs, &compiler.SourceMapFilter{Writer: jsCode})
        jsCode.WriteString("} catch (err) {\nconsole.log(err.message);\n}\n")
        js.Global.Set("$checkForDeadlock", true)
        js.Global.Call("eval", js.InternalObject(jsCode.String()))
    }

    go func() {
        println("waiting code ready")
        <-codeReady
        println("code ready")
        run(false)
    }()

}

codeString is imported the 3rd. library code string, I want to compile and run it online. But failed on compiler.Compile method. Got the error: Compile: prog.go:3:8: could not import honnef.co/go/js/xhr (Config.Importer.Import(honnef.co/go/js/xhr) returned nil but no error)

There is my steps:

  1. save the code to playground.go file.
  2. run gopherjs build playground.go -o index.js
  3. write an index page and import index.js
  4. startup a http server, like python -m SimpleHTTPServer 8000
  5. copy pkg folder to my folder, and copy honnef.co/go/js/xhr package to correct path.
  6. use your browser to visit http://localhost:8000 and get the error on js console.

index.html:

<!DOCTYPE html>
<html>
  <head>
    <script src="index.js"></script>
  </head>
  <body>

  </body>
</html>

thanks.

dmitshur commented 8 years ago

But failed on compiler.Compile method. Got the error: Compile: prog.go:3:8: could not import honnef.co/go/js/xhr (Config.Importer.Import(honnef.co/go/js/xhr) returned nil but no error)

Have you tried looking into the details? Why does it return nil but no error? What does it do for other packages?

PeerXu commented 8 years ago

It is right, I should not check error after compiler.Compile immediately.