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

Allow deploy to a custom location #98

Closed
wants to merge 8 commits into from
Closed

Allow deploy to a custom location #98

wants to merge 8 commits into from

Conversation

limira
Copy link
Contributor

@limira limira commented May 5, 2018

Solve issue #96

Basically, this work. But no code for auto-test yet! Reading the code, I am unable to figure out how to run test locally!

How can I run tests locally? Especially, with a custom deploy-path?

Copy link
Owner

@koute koute left a comment

Choose a reason for hiding this comment

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

Thanks!

Initial review done. I'll take an even closer look at this later.

package: &CargoPackage,
target: &CargoTarget,
result: &CargoResult,
mut with_serve_path: Option<DeployWithServePath>
Copy link
Owner

@koute koute May 6, 2018

Choose a reason for hiding this comment

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

Please make this function take serve_path: String instead of with_serve_path. There is no point in making anything here Optional since both deploy_path and serve_path have well defined defaults we can use (one being target/deploy, the other /), so it makes no sense to overcomplicate the code.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

tldr:
It is complicated because I want to check if we need to process the js contents or not. If serve_path is default or there is no .wasm file: do nothing on js contents, else, must process it. Another reason is I am too lazy (:-1: to myself) to add more code (than a None) to cmd_start.rs.

Long story: (Please correct me if I say something not correct, and apologies for my poor English)

This is because of the involvement in cmd_start.rs (line 146),

let deployment = Deployment::new( &package, &target, &result, None )?;

If don't want to take an Option, then it will become (None would be better?)

let config = project.get_default....
let deployment = Deployment::new( &package, &target, &result, config )?;

I think it is ok with that. But there is a more important thing to consider is that we must process the contents of the js file. If I understand correctly, we do not need to process it in case of asmjs, is this right? (don't know this exactly because I do not use asmjs) (and do not process the js file if serve-path is default) So, I add DeployWithServePath to monitor if there is a .wasm file and to store its actual name (on the filesystem, and that is also use in the js). Then when process the js contents, we check if it is required or not, if not, just do nothing. Otherwise, find the .wasm filename (recorded by DeployWithServePath) in js file, insert serve-path.

If you want to pass serve-path as a String, then we need a second parameter that indicate if target is a wasm32 or not (If it is not, we do not process the js contents), and it will become something like this:

    pub fn new(
            package: &CargoPackage,
            target: &CargoTarget,
            result: &CargoResult,
            serve_path: String,      // this
            target_is_wasm: bool,    // and this
        ) -> Result< Self, Error >

Finally, with the fn declaration above, we check if it is default or not by comparing serve_path.len() == 0 to know if it is needed to process or not process the js contents. If we pass as Option<String> it is clearer if we are in the default case or not.

Copy link
Owner

Choose a reason for hiding this comment

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

But there is a more important thing to consider is that we must process the contents of the js file.

Hm, yeah, you're right that we need to mess around with the .js file when serve-path != "/".

  • asmjs-unknown-emscripten - nothing to do
  • wasm32-unknown-emscripten - we need to replace the path to the .wasm file or (if possible) tell Emscripten to use the path we want right from the start (it might be possible to pass that info to Emscripten through EMMAKEN_CFLAGS, I don't know)
  • wasm32-unknown-unknown - we need to generate the .js file with the right path

I think that doing this during building (instead of adding hacks to change the path during deployment) would be simpler.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What I tried is actually hacking the .js file 👎! The reason is that I don't want to touch any code outside of the deploy process. I think that putting any hacky things into DeployWithServePath then if we have full support for serve-path in both wasm32-unknown-emscripten and wasm32-unknown-unknown just remove it all.

But I understand that it is not good for the consistency of the whole project! I just don't have much time to dive deeper into build process and especially into Emscripten right now (even you have to say "I don't know"). So, let this halted here for awhile, until I have some free time to devote more into this.

Copy link
Owner

Choose a reason for hiding this comment

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

Well, initially I would be fine with just doing a search and replace for wasm32-unknown-emscripten; as long as it works we can always fix it later. The initial version of this doesn't have to be perfect, but I'm willing to accept only minor hacks as opposed to major ones. (:

Sure, no problem, thanks for investing the time into this. (:

// It is not allow to contains `\\` or `..`
if path.contains( &double_sep ) || path.contains( ".." ) {
return Err( Error::ConfigurationError( format!("serve-path is invalid: {}", path) ) );
}
Copy link
Owner

Choose a reason for hiding this comment

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

The validity of these should all be checked when the config file is loaded.

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, it is better to do this when loading config

}
}
_ => unreachable!()
}
Copy link
Owner

@koute koute May 6, 2018

Choose a reason for hiding this comment

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

This looks a little too complicated; we shouldn't (mostly) need these functions, I think.

It would be simpler to just to do something like this:

fn rebase_url( serve_path: &str, url: &str ) -> String {
    // ...
}

and then:

         for path in result.artifacts() {
             let (is_js, key) = match path.extension() {
-                Some( ext ) if ext == "js" => (true, js_name.clone()),
+                Some( ext ) if ext == "js" => (true, rebase_url( &serve_path, &js_name )),
-                Some( ext ) if ext == "wasm" => (false, path.file_name().unwrap().to_string_lossy().into_owned()),
+                Some( ext ) if ext == "wasm" => (false, rebase_url( &serve_path, path.file_name().unwrap().to_string_lossy() )),
                 _ => continue
             };

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As I mentioned this in my first reply above. We need to know the actual name of the .wasm file (its name only, not include the serve_path, because what we want to insert the serve_path into js, before its actual name).

let target_config = match project.config_of_default_target() {
Some(config) => config.clone(),
None => ::config::PerTargetConfig::default()
};
Copy link
Owner

Choose a reason for hiding this comment

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

Instead of this please add deploy_path and serve_path getters to Project. Have them always return String.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree with the deploy_path. But with serve_path, I think return Option<String> is better, because we do different things if there is a serve-path or not.

Copy link
Owner

Choose a reason for hiding this comment

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

How do we do different things if there is a serve-path? By default the behavior should be the same as if serve-path was set to /, no?

@koute
Copy link
Owner

koute commented May 6, 2018

As far as the standalone tests go you need to do something like this to run them locally:

cargo build
export REPOSITORY_ROOT=/path/where/you/have/cloned/cargo-web
export CARGO_WEB=$REPOSITORY_ROOT/target/debug/cargo-web
cd integration-tests
cargo run

Running ci/run_tests.sh should also work, but that will take significantly longer as it will run everything.

@limira
Copy link
Contributor Author

limira commented Jun 2, 2018

Oh no, +36,709 lines!!!

I added custom_deploy_path_here/* to .gitignore, but apparently not effect! I will try to read the document then try it again.

Edit:
It is now +666 −66. Beautiful numbers!!!

Copy link
Owner

@koute koute left a comment

Choose a reason for hiding this comment

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

Thanks!

And sorry for taking so long. I had no access to a computer for a few weeks, and then it took me a while to get through this PR as it's so big. (:

let raw: toml::Value = match toml::from_str( config_toml.as_str() ) {
Ok(value) => value,
Err(error) => return Err( Error::ConfigurationError(
format!( "Failed to parse Web.toml: {}", error )
Copy link
Owner

Choose a reason for hiding this comment

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

Can you format this error the same way as other errors generated here? e.g. format!( "cannot parse {}: {}", config.source(), error ).into() Also, not much point in putting it into Error::ConfigurationError (I'll probably get rid of those variants.)

"deploy-path" => if is_main_crate {
config.add_deploy_path(ALL_BACKENDS, toplevel_value, "deploy-path")?;
},
"js-wasm-path" => if is_main_crate {
Copy link
Owner

Choose a reason for hiding this comment

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

js-wasm-path -> wasm-path

"js-wasm-path" => if is_main_crate {
config.add_js_wasm_path(ALL_BACKENDS, toplevel_value, "js-wasm-path")?;
},
"serve-url" => if is_main_crate {
Copy link
Owner

Choose a reason for hiding this comment

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

serve-url -> serve-path (What we're specifying there are not URLs, e.g. URLs have scheme followed by a semicolon.)

return Err( Error::ConfigurationError( format!("serve-url is invalid: {}", path) ) );
}
Ok(())
}
Copy link
Owner

Choose a reason for hiding this comment

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

  1. The serve path should:
  • not contain more than two consequtive / nor .. (you're already checking for this)
  • not contain any \ (they should always use forward slashes, so we shouldn't use MAIN_SEPARATOR)
  1. Please keep the format of the error messages consistent with others.

let double_sep = format!("{0}{0}", SEP);
if path.contains( &double_sep ) || path.contains( ".." ) {
return Err( Error::ConfigurationError( format!("js-wasm-path is invalid: {}", path) ) );
}
Copy link
Owner

Choose a reason for hiding this comment

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

Same issues as in serve path validation.

# The default value of `js-wasm-path` is "/" (means the root of `deploy-path`)
js-wasm-path = "js/and/wasm/folder/inside/deploy/path"

# [Optional] If ommitted, the value of `serve-url` will be the same as `js-wasm-path`
Copy link
Owner

Choose a reason for hiding this comment

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

The path under which the `.js` file will be served; by default equal to `/`.

In general I'd like the serve-path to be the "main" one, instead of how is it now where it's the other way around. (Also remember that with the asmjs target we don't even have a .wasm file.) Basically:

  1. By default put both .js and .wasm under serve-path.
  2. If the user wants to put the .wasm file somewhere else then they can set wasm-path.
  3. The path to the .wasm file in the .js file will be always consistent with what cargo web start is serving and cargo web deploy is outputting.

I know there's also the use case of deploying the .js or .wasm to a different directory than the path from which they're served (e.g. if you're rewriting URLs in your webserver), but I'd rather handle that separately in a future PR.

# If specified, the folder must exist.
deploy-path = "path/to/deploy/folder/"

# The default value of `js-wasm-path` is "/" (means the root of `deploy-path`)
Copy link
Owner

Choose a reason for hiding this comment

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

The path from which the `.wasm` file will be served; by default the same as `serve-path`.
  1. Put it after serve-path.

deploy-path = "path/to/deploy/folder/"
js-wasm-path = "js/and/wasm/folder/inside/deploy/path"
serve-url = "url/to/retrieve/js/and/wasm/files"
```
Copy link
Owner

Choose a reason for hiding this comment

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

Please merge this example Web.toml into the main one. (So that everything is in a single place.)


[target.wasm32-unknown-unknown]
# If you specify these parameters for a specific target then global `deploy-path`,
# `js-wasm-path` and `serve-url` are not allowed.
Copy link
Owner

Choose a reason for hiding this comment

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

This comment here is unnecessary; instead we can extend the list of keys in A few restrictions concerning paragraph higher in the README.

If you have your wasm-app files and other static files serve like
the above example. Please notes:
* An `index.html` must be provided in `crate-root/static` and have it point to
the right `url` of `.js` file for browsers to be able to load it.
Copy link
Owner

Choose a reason for hiding this comment

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

Hm... with good enough one/two line comments in the example Web.toml file I feel like this long winded explanation might not be necessary? (Expect the warning about the files being overwritten, which should be spelled out separately.)

@limira
Copy link
Contributor Author

limira commented Jun 29, 2018

Thanks for your review!

Why do I use loop instead of for

As far as I see self is only borrowed once inside, so you should be able to turn it into a normal for loop.

    let mut iter = backends.iter();
    let error = loop {
        if let Some(backend) = iter.next(){
            let per_target = self.per_target.entry( *backend ).or_insert( Default::default() );
            if per_target.$field_ident.is_none() {
                per_target.$field_ident = Some( string_value.clone() );
            }else{
                break true;
            }
        }else{
            break false;
        }
    };
    if error {
        Err( format!( "{}: you can't have multiple '{}' defined for a single target", self.source(), stringify!($field_ident)).into())
    }else{
        Ok(())
    }

If I remember correctly. When I return this directly inside the for loop:

Err( format!( "{}: you can't have multiple '{}' defined for a single target", self.source(), stringify!($field_ident)).into())

The compiler complains about mutable of self at

let per_target = self.per_target.entry...

and immutable borrow at

self.source() // in Err(...)

(because the Err(...) is now inside the loop). Therefore, I must transform the for into what it is now.

Can we move this into Project::build from build.rs?

Edit: I think I know how to do this now!

wasm-path/serve-path

What you want is:

  1. By default put both .js and .wasm under serve-path.
  2. If the user wants to put the .wasm file somewhere else then they can set wasm-path.
  3. The path to the .wasm file in the .js file will be always consistent with what cargo web start is serving and cargo web deploy is outputting.

The first case is that the user want only serve-path. Nothing special in this case.
The second case: .js in serve-path, .wasm in wasm-path, then:

  • index.html have its .js src point to /serve-path/<name>.js
  • .js loads .wasm from /wasm-path/<name>.wasm

in this case, serve-path is not actually/fully a served/serving path any more. (Does this cause any confusion?). And I think users that want their .wasm file (only one file) in a separate folder is very rare?

You say that you like to have a separate PR for the case where users want that their request-path (the path to load .wasm from browsers) different to the path they deploy it. I think that such a PR will modify the path where .wasm is loaded from - it is exactly what we are doing now in this PR. Why not just do it now?

To make things simpler, I propose this:

# Default value: `target/deploy`
deploy-path = "path/to/put/deploy/files"

# `wasm-serve-path` is the path under which the `.wasm` file will be served.
# This means `https://example.com/wasm-serve-path/<name>.wasm`
# Default value: `/`
wasm-serve-path = "path/to/load/.wasm/file/from/browser"

With this proposal:

  • We will force .js, .wasm and all files in crate-root/static/ to be placed at the root of deploy-path.
  • Both deploy-path, wasm-serve-path will only accept /, any \ will cause error.
  • deploy-path is always relative! (My intention is also allow absolute path for the case where a absolute path is simpler than a relative path. How about this case? But it is not a big thing, we can ignore this)

@koute
Copy link
Owner

koute commented Jun 29, 2018

Why do I use loop instead of for

You can just simply run self.source() and assign it to a variable before the loop. (:

in this case, serve-path is not actually/fully a served/serving path any more. (Does this cause any confusion?). And I think users that want their .wasm file (only one file) in a separate folder is very rare?

Well, the idea is that serve-path means "the path under which the generated artifacts are served", which includes the .js and (depending on the --target) the .wasm file. That's pretty simple conceptually. And then for those who want to put the .wasm file somewhere else they can do it.

I agree that it's probably rare that someone wants to keep the .js file and the .wasm file separately. I'm fine with having that; I'm also fine with removing it for now and only keeping serve-path and deploy-path.

You say that you like to have a separate PR for the case where users want that their request-path (the path to load .wasm from browsers) different to the path they deploy it. I think that such a PR will modify the path where .wasm is loaded from - it is exactly what we are doing now in this PR. Why not just do it now?

Mostly because this PR is already very big, and in most cases it probably won't be necessary. (:

Having a different path for deployment does bring some additional complexity (e.g. we'll need to add forced rebuilding to be able to patch the filename again if someone first does cargo build and then cargo deploy, or perhaps a better idea would be to backup the original data before patching it, and then we wouldn't have to force a rebuild).

To make things simpler, I propose this: [...]

So basically - disentangle the paths to .js and .wasm, have them be set to / by default, and have them separately overridable? Hmm... I guess that is somewhat less confusing than having a shared serve-path. Okay, sounds fine to me.

However, I'd still like to keep the invariant that cargo deploy generates exactly what cargo start serves. The idea is that you can use cargo start to develop your application, and then you can cargo deploy it somewhere and run it as-is with a static HTTP server of your choice with no modification. If we'll always deploy the .wasm file to / regardless of the path set in Web.toml then we'll break that.

My intention is also allow absolute path for the case where a absolute path is simpler than a relative path. How about this case? But it is not a big thing, we can ignore this)

There are two main problems with absolute paths: 1) they're OS specific (e.g. Windows uses drive letters, Linux doesn't), and 2) they effectively make the crate unusable if you, for example, copy your project to a different directory or a different drive. So I don't think it'd be really worth supporting them? (And I don't think encouraging (2) is a good idea.)

@limira
Copy link
Contributor Author

limira commented Jun 30, 2018

After some long thought about this, I think we should make things simpler by

  • always output to the root of deploy-path
  • and by breaking this PR into different steps

First step: close this PR 😁

  • Because you do not like big PR.
  • There are some conflict between this PR and the master branch now! If I make more changes on old code, maybe more conflict appears???

Second: A new PR only for deploy-path

Most users just only use deploy-path (for simple sites, or sites with few static-files)

# Default value: `target/deploy`
deploy-path = "where/to/put/deploy/files"
  • .js/.wasm and crate-root/static/* are always copied to the root of deploy-path.
  • .js/.wasm are always served at the root. It means: example.com/<name>.js and example.com/<name>.wasm.

This case, cargo web start will be no different between before and after this PR. The output (content of js files) of cargo web deploy and cargo web start are exactly the same. The only benefit provides by this PR is that cargo web deploy will put everything in the right folder (rather than target/deploy that requires further manual actions to be actually useful).

Some users may not happy because they are unable to put .js/.wasm in other folder. But they just have few files in their static folder, therefore, it is not a big problem.

Third: A new PR for serve-path

For some users who have a big site and want to serve .js/wasm under another path rather than /, for example:

http://example.com
    /               # this will serve index.html
    /users          # contents...
    /pages          # ...from...
    /posts          # ...database!
    /and
    /many
    /more
    /routes
    /here!
    /static         # all static files will be served under this route
        /other-files/*
        /<name>.js
        /<name>.wasm

In this case, because of the complexity of the project, users will want to serve all static files under a special route such as /static/. Therefore, .js/.wasm files will be served at /static/ or even deeper!

To support this, we add two more parameters:

# `serve-path` is the path under which the `.js`/`.wasm` files will be served.
# Default value: `/`
serve-path = "path/to/load/.js/and/.wasm/file/from/browser"

# `index-path` is where to put `index.html`
# Default value: Same as `deploy-path`
index-path = "where/to/put/index/html"
  • .js/.wasm and crate-root/static/* are still always copied to the root of deploy-path.
  • Of course, if there is index-path, index.html will be copied to that instead of deploy-path.
  • cargo web start always serves index.html at /, but all other files will be served under serve-path.
  • (When users serve these by their own server, I think they should know what to do).
  • Users must make sure that every request (from browser) for static files are prefixed by serve-path.
  • If users provide their own index.html, they must make sure it load .js under serve-path.
  • If there is no index.html, then cargo web start/deploy generates it with <script src="/server-path/<name>.js"></script>.
  • cargo web start will strip prefix serve-path from request-url, then just serve requested files as it does without serve-path.
  • The content of .js file (with serve-path inserted) will be exactly the same in both cargo web deploy and cargo web start.

There is a place in the test code (that I have written to test this current PR) that I have to hack the .js file again to pass the test successfully. It is only happen to wasm32-unknown-emscripten because I insert serve-path into the .js content in the deployment process. The content that is received from cargo web start is the modified content (cargo web start served it from memory). The .js file on disk (in folder target/wasm32-unknown-emscripten) is the original one (it is loaded and modified by deployment but not saved back to disk). When comparing these (content served by cargo web start, and content loaded from disk), I must hack it again like that.

Maybe you have concern about differences between cargo web deploy and cargo web start from that portion of code? But now, you have a demand that serve-path must be insert in the build process. The problem will just simply vanish! Because the content of .js file on disk will be the modified one!

Relative/absolute path for deploy-path?

An absolute path is better in these cases:

  • Users move their source code to other location/partition, but they still want to deploy to the current absolute deploy-path in Web.toml
  • Or even on a local network, users may move their source code from machine to machine, but always deploy to a single network location (on a server, which is rarely changed)

I still think it is better to support both relative and absolute path for deploy-path!

@koute
Copy link
Owner

koute commented Jul 1, 2018

Sounds mostly good to me, except a few points:

Of course, if there is index-path, index.html will be copied to that instead of deploy-path.

index-path should be relative to deploy-path and be equal to /index.html by default. (That is - it should be a virtual path instead of being a physical path like deploy-path.)

Users must make sure that every request (from browser) for static files are prefixed by serve-path.

Am I misunderstanding what you just said, or are you suggesting that we should serve everything under the serve-path? I don't think that's necessary.

The static files from the $crate/static folder are currently always served from /, and there is no point in making this configurable. If the user wants those files to be served from /foobar they can always move them to $crate/static/foobar.

cargo web start will strip prefix serve-path from request-url, then just serve requested files as it does without serve-path.

Unless you're talking purely conceptually here, internally there is no need to do any fiddly stripping; the files should just be mounted under serve-path, e.g. here:

let (is_js, key) = match path.extension() {
    Some( ext ) if ext == "js" => (true, js_name.clone()),
    Some( ext ) if ext == "wasm" => (false, path.file_name().unwrap().to_string_lossy().into_owned()),
    _ => continue
}

just prepend the serve-path:

let key = format!( "{}/{}", serve_path, key );

This will automatically make the file appear in the same place with both start and deploy.

I still think it is better to support both relative and absolute path for deploy-path!

Well, I'm fine with supporting it as long as someone actually needs this feature.

@limira
Copy link
Contributor Author

limira commented Jul 2, 2018

This will go into detail, I just want to make sure that we are talking and thinking about exactly the same thing!

Pretend we a going to build a site name rusters, to be run at rusters.com

The rust source code that will be deployed by cargo web:

rusters/
    |--- src/
    |--- static/
            |--- images/
                    |--- background1.png
            |--- index.html

In Web.toml

deploy-path = "/path/to/rusters-static"

Then after cargo web deploy, we expect /path/to/rusters-static looks like this:

rusters-static/
    |--- other-static-files/*       # from other sources
    |--- images/
            |--- background1.png
    |--- index.html
    |--- rusters.js
    |--- rusters.wasm

Because of the complexity of the project, we want our server serves things like this:

rusters.com
    /               # serve index.html
    /users
    /posts
    /....
    /s-files        # serve all content of `rusters-static` under `s-files`

Our server code similar to:

let server = Server::new()
    .index(serve_index_html)
    .route("users", handle_users)
    .route("posts", handle_posts)
    ....
    .route("s-files", StaticFiles::new("/path/to/rusters-static"));      // under `s-files`

This way, what we expect are: (all of them have s-files)

rusters.com/s-files/images/background1.png
rusters.com/s-files/rusters.js
rusters.com/s-files/rusters.wasm

Although we deploy everything to the root of deploy-path, but they are all served under a common route s-files. Therefore, we need to tell rusters.js that the path for rusters.wasm is /s-files/rusters.wasm. And similarly, /s-files/images/*. This is why we have to use serve-path in Web.toml:

serve-path = "s-files"

If we prepend serve-path to the key of deployment::Route like:

let key = format!( "{}/{}", serve_path, key );

Then, cargo web start runs ok.
But, cargo web deploy cause a problem because it also use Route.key to create file's path. Therefore, cargo web deploy will give results like:

rusters-static/
    |--- other-static-files/*       # from other sources
    |--- s-files  # <================ this new folder
            |--- images/
                    |--- background1.png
            |--- index.html
            |--- rusters.js
            |--- rusters.wasm

With rusters-static content like this, and the server code above, all urls for static files change to: (all of them have /s-files/s-files)

rusters.com/s-files/s-files/images/background1.png
rusters.com/s-files/s-files/rusters.js
rusters.com/s-files/s-files/rusters.wasm

Maybe we could say we are running into a recursive problem??

I can only figure out two solutions for this problem:

  • Do not prepend serve-path to key, then we must strip serve-path from request path when runing cargo web start
  • Or, change deployment::Route to
struct Route {
    serve_key: String,      // use for `cargo web start`
    deploy_key: String,     // use for `cargo web deploy`
}

@koute
Copy link
Owner

koute commented Jul 3, 2018

After we set serve-path:

serve-path = "s-files"

the deployment (both start and deploy) should look like this:

rusters-static/
    |--- other-static-files/*       # from other sources
    |--- images/
            |--- background1.png
    |--- index.html
    |--- s-files
            |--- rusters.js
            |--- rusters.wasm

If the user wants to have the index.html under s-files they should set index-path, and if the user wants to move the images directory they should move it from $crate/static/images to $crate/static/s-files/images.

Or to reiterate:

  • $crate/src/static/* always gets copied to $deploy_path/* and served under http://.../*
  • .js and .wasm are copied to $deploy_path/$serve_path/{.js, .wasm} and served under http://.../$serve_path/{.js, .wasm} (I'm also fine with splitting serve-path into separate js-path and wasm-path so that it's perhaps less confusing that it's not affecting everything that's served?)
  • index.html is copied to $deploy_path/$index_path and served under http://.../$index_path
  • $deploy_path is always at the root of what's being served at the root

If we prepend serve-path to the key of deployment::Route [...] But, cargo web deploy cause a problem

Sorry, I don't fully understand what's the problem here. (: We prepend the serve-path to the keys for .js and .wasm in Deployment, and automatically those files will be deployed to $deploy_path/$serve_path and served under http://localhost:8000/$serve_path. Then if you manually go into the $deploy_path directory and manually start your own server those files will still be served under http://localhost.$port/$serve_path. Nowhere do we get double $serve_paths. Am I missing something here?

@limira
Copy link
Contributor Author

limira commented Jul 4, 2018

Maybe you missed this

In this comment, maybe you missed the following line?

  • .js/.wasm and crate-root/static/* are still always copied to the root of deploy-path.

If you missed that line, I think I should say it more clearly that:

  • Both .js and.wasm and all content of crate-root/static/* are still always copied to the root of deploy-path.
  • Therefore, serve-path is only purely using as a serving-path, not using to make a sub folder for .js/.wasm any more.

There are only just two files (.js and .wasm), I think it is not a big problem if we force them into the root of deploy path. (Except for index.html, users can put everything else into static/sub-folders)

We are still talking about different things:

$deploy_path is always at the root of what's being served at the root

Yes, if we serve things that way, it's ok with the very first version of serve-path that we disccussed before I start this PR.

I said about a different case, where users want to put them under a route. I said it two times, and somehow you missed both. The first time in this comment, that:

http://example.com
    /               # this will serve index.html
    /users          # contents...
    /pages          # ...from...
    /posts          # ...database!
    /and
    /many
    /more
    /routes
    /here!
    /static         # all static files will be served under this route
        /other-files/*
        /<name>.js
        /<name>.wasm

The second time in this comment, that:

rusters.com
    /               # serve index.html
    /users
    /posts
    /....
    /s-files        # serve all content of `rusters-static` under `s-files`

Maybe a simpler solution?

Here, simpler means it only needs a minimal change in cargo-web.

wasm32-unknown-emscripten

Leave it as is. I read all emscripten`s flags/settings about 3 for 4 times but I am unable to find anything that can change the url to load wasm file from js file. Maybe we should open an issue on emscripten? Wait until emscripten support it?

wasm32-unknown-unknown

Instead of hard-code $serve-path/<name>.wasm into .js file, we use a js const. In the generated index.html, in the <script>:

const STDWEB_WASM_PATH = "/<name>.wasm";

Then the .js file loads .wasm file using this const.

This way, most users just need a normal deploy-path (with everything at its root). When users want to change STDWEB_WASM_PATH, they must provide their own index.html with a correct value for STDWEB_WASM_PATH.

Using this solution: cargo-web do not need serve-path, then do not have to trigger a rebuild when serve-path changed (how could it changed if it does not exist?).

@koute
Copy link
Owner

koute commented Jul 9, 2018

@limira Apologies for the late reply.

I said about a different case, where users want to put them under a route. I said it two times, and somehow you missed both.

Sorry, I was a little confused, but I think I get it now... (:

Just to double check, by this:

Both .js and.wasm and all content of crate-root/static/* are still always copied to the root of deploy-path. Therefore, serve-path is only purely using as a serving-path, not using to make a sub folder for .js/.wasm any more.

... do you mean you want the serve paths to affect only two things:

  1. the URL under which cargo web start will serve everything except index.html (.js, .wasm, and everything from the $crate/static)
  2. and the path to the .wasm in the .js file,

but when running cargo web deploy it's going to dump everything in the root of deploy-path just as it's doing now?

Hmmm.... this is starting to get messy.

Okay, so, can we for now have a PR with only the deploy-path? That is relatively simple and uncontroversial. And I'll try to think a little more about how we should proceed with doing the rest.

@kellytk
Copy link

kellytk commented Jul 9, 2018

At @koute's invitation I'd like to register a related feature request. I need to, ideally using Web.toml, specify a host and path for the generated .js to use when fetching the .wasm file.

I also need to have the option to customize the specified host and path depending on the environment I'll deploy the build to and serve it from. (eg., development, production) STDWEB_ENVIRONMENT=production cargo web build or cargo web build -e production.

Example using the current behavior in development and serving from a CDN in production:

// Web.toml
[environment.production]
serve-url = "htts://cdn.example.com/v1/app.wasm"

./cargo web build -e production

@limira
Copy link
Contributor Author

limira commented Jul 10, 2018

I just come to say that I am currently unable to continue the work on this PR. I don't know if I may come back again to finish this or not. Thank you for all your time spending to review my work!

@koute
Copy link
Owner

koute commented Jul 11, 2018

@limira Thanks for all of your work!

I'll close this PR for now; if someone wants to resurrect this feel free to open a new one!

@kellytk I've added a new argument to the current master: --runtime. You can specify --runtime=library-es6 which will generate a .js file that instead of loading the .wasm file by itself only exports a factory function with which you can instantiate your module manually.

For example, you can do something like this:

import factory from "./module.js";
const instance = factory();
fetch( "http://example.com/url/to/your/module/module.wasm" )
    .then( response => { return response.arrayBuffer(); } )
    .then( bytes => { return WebAssembly.compile( bytes ); } )
    .then( mod => { return WebAssembly.instantiate( mod, instance.imports ) } )
    .then( wasm_instance => {
        const exports = instance.initialize( wasm_instance );
        exports.functionExportedWithTheJsExportMacro();
    });

Basically, the generated .js file exports a factory function which when executed returns the following object:

{
    initialize: function( wasm_instance ) { ... },
    imports: { ... }
}

So while this might not be as ergonomic as having this in Web.toml you should be able to customize your URL now if you load the module yourself.

@koute koute closed this Jul 11, 2018
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.

None yet

3 participants