Skip to content

Add optional root argument to gopherjs serve. Fixes #384 #429

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

Merged
merged 3 commits into from
Mar 31, 2016

Conversation

jargv
Copy link
Contributor

@jargv jargv commented Mar 22, 2016

Fixes #384.

@neelance
Copy link
Member

This looks really good, thanks for contributing! Two small wishes:

  1. Make gopherjs help serve show the new optional argument.
  2. Print the same help content if more than one argument is given.

@dmitshur
Copy link
Member

Thanks for working on resolving that issue! I have some questions about the code changes.

@@ -555,7 +571,7 @@ func (fs serveCommandFileSystem) Open(name string) (http.File, error) {
if isPkg || isMap || isIndex {
// If we're going to be serving our special files, make sure there's a Go command in this folder.
s := gbuild.NewSession(fs.options)
pkg, err := gbuild.Import(path.Dir(name[1:]), 0, s.InstallSuffix(), fs.options.BuildTags)
pkg, err := gbuild.Import(path.Dir(strings.Trim(name, "/")), 0, s.InstallSuffix(), fs.options.BuildTags)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the reason for this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the first character was unconditionally dropped with name[1:] it was always a slash. With this change the first character is sometimes a slash, but not always. I was seeing it pass strings like ithub.com/jargv/... into path.Dir, which fails, of course. strings.Trim seemed like a good way to conditionally drop the first character if it's a '/'. I'm new(ish) to go so I'd love to learn if there's a more idiomatic approach. :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this change the first character is sometimes a slash, but not always.

I see. I asked I'd like to understand exactly in what situations it'a slash, and in what situations it's not.

strings.Trim seemed like a good way to conditionally drop the first character if it's a '/'. I'm new(ish) to go so I'd love to learn if there's a more idiomatic approach. :)

One immediate improvement suggestion would be to use strings.TrimLeft rather than strings.Trim, since you said you only want to drop the first character being /, not the last character. strings.Trim trims from both ends.

However, I understand what's happening better now, and I have a suggestion for how you can go back to just having an unconditional trim of first character (which should be simpler to reason about).

The signature of this method used to be Open(name string), and name[1:] used to be done to drop the first "/" that's a part of each *http.Request.URL.Path. Since you've re-arranged the code to be Open(requestName string), I think you can move the the [:1] operation to happen earlier:

func (fs serveCommandFileSystem) Open(requestName string) (http.File, error) {
    name := path.Join(fs.serveRoot, requestName[1:])

Then this line can become simply:

pkg, err := gbuild.Import(path.Dir(name), 0, s.InstallSuffix(), fs.options.BuildTags)

What do you think of that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I agree TrimLeft would be better, and the move you suggest would be better still! I'll make that change shortly.

@dmitshur
Copy link
Member

How does this change affect the source maps that are served as well?

@jargv
Copy link
Contributor Author

jargv commented Mar 23, 2016

@shurcooL Source maps seem to work as expected with this change.

@@ -35,6 +35,8 @@ For example, navigating to `http://localhost:8080/example.com/user/project/` sho

Refreshing in the browser will rebuild the served files if needed. Compilation errors will be displayed in terminal, and in browser console. Additionally, it will serve $GOROOT and $GOPATH for sourcemaps.

If you include an argument, it will be the root from which everything is served. For example, if you run `gopherjs serve example.com/user` then the generated JavaScript will be served at `http://localhost:7979/project/project.js`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand how the command gopherjs serve example.com/user maps to something being served at /project/.

I also feel like making it a positional argument is confusing. Other tools (build, install) take the package as an argument. I can accept serve not accepting a package, but IMO it shouldn't interpret the argument in an entirely different way. Wouldn't it make more sense to make this an explicit flag?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about changing it to this:

"For example, if you run gopherjs serve github.com/user/project then the generated JavaScript for the package github.com/user/project/mypkg will be served at http://localhost:7979/mypkg/mypkg.js."

I think the semantics are not too far off compared to other commands.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I don't understand what the argument does. I thought gopherjs serve foo would serve the package in $PWD at /foo/.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dominikh, no, it does what @neelance described more clearly above. See #384 that this PR resolves for more context.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, okay. I guess it's fine then.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does behave like other commands which take a package. It just also handles the case where the argument is not a complete package path, in which case it serves all packages at that root.

@@ -35,6 +35,8 @@ For example, navigating to `http://localhost:8080/example.com/user/project/` sho

Refreshing in the browser will rebuild the served files if needed. Compilation errors will be displayed in terminal, and in browser console. Additionally, it will serve $GOROOT and $GOPATH for sourcemaps.

If you include an argument, it will be the root from which everything is served. For example, if you run gopherjs serve github.com/user/project then the generated JavaScript for the package github.com/user/project/mypkg will be served at http://localhost:7979/mypkg/mypkg.js.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One last thing: Let's use :8080 here, since that is the default.

@neelance
Copy link
Member

I'd like the port number changed, see above. LGTM otherwise. @dominikh? @shurcooL?

@dominikh
Copy link
Member

LGTM

@dmitshur
Copy link
Member

I can see some minor followup enhancements, but no blockers for this getting merged to resolve #384.

LGTM.

@jargv
Copy link
Contributor Author

jargv commented Mar 26, 2016

I found an issue with sourcemaps that needs to be resolved before this can be merged.

The source maps work well enough to map errors to the right file/line. So for example instead of the error being reported at output.js:15912 it is reported correctly at main.go:7.

The problem occurs when I click on main.go:7, the devtools can't load main.go to display the error in the context of the file. I hope to have this fixed soon.

@jargv
Copy link
Contributor Author

jargv commented Mar 26, 2016

I added a fix but it has an assumption. When the requested file ends in ".go" I ignore the serveRoot. The assumption is that source maps will only map to .go files, and .go files will only be requested because the source maps reference them. Is that true?

@flimzy
Copy link
Member

flimzy commented Mar 26, 2016

GopherJS also accepts *.inc.js files as input. I don't know if these are presently supported for source maps. If it's easy to support such files as well, I would encourage doing so. If that's presently not supported, then at least it's not a regression not to support them here.

@jargv
Copy link
Contributor Author

jargv commented Mar 26, 2016

@flimzy source maps don't appear to work for .inc.js files.

@neelance
Copy link
Member

What about trying both? First try the prefixed path, but if that file does not exist then try the non-prefixed path? I think this should be possible by adding to serveCommandFileSystem.dirs. And also for the implementation in general, it might be easier to prefix entries of dirs instead of adding serveRoot. I just realized that now, sorry for not mentioning it earlier.

@jargv
Copy link
Contributor Author

jargv commented Mar 27, 2016

@neelance I actually tried that first. The trouble I ran into was how serveCommandFileSystem.Open determines when to compile or not. Specifically these variables never evaluated to true:

isPkg := file == base+".js"
isMap := file == base+".js.map"

because base is derived from the request path.

Of course this could be changed to work in some other way, but it's not clear to me that that would be simpler. For example, how would you disambiguate a request to "/"? Should that compile the package at serveRoot, or serve the directory listing with http.Dir(...).Open(...)?

That said, I'm happy to make the change if that's determined to be the best way forward.

@jargv
Copy link
Contributor Author

jargv commented Mar 29, 2016

Ok I changed it to serve files both inside and outside of the serveRoot. There's no longer special casing around .go files.

@neelance is this what you meant? I tried adding to serveCommandFileSystem.dirs in order to get rid of the serveRoot variable, but the problem becomes mapping back to a valid package path. Right now we can assume that the request path (with the serve root prepended) is a valid package without having to look through GOPATH and GOROOT looking for a match.

Anything else to make this good to merge?

@neelance neelance merged commit 234e9ee into gopherjs:master Mar 31, 2016
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

Successfully merging this pull request may close these issues.

5 participants