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 the user to fully customize the package name #427

Closed
stristr opened this issue Nov 4, 2018 · 6 comments
Closed

Allow the user to fully customize the package name #427

stristr opened this issue Nov 4, 2018 · 6 comments

Comments

@stristr
Copy link

stristr commented Nov 4, 2018

💡 Feature description

Currently, the NPM package name generated by wasm-pack is the (optionally scoped) name of the Rust crate being packed. There is utility in being able to choose the name of the package; for example, I might want to publish multiple packages to the NPM repository using different --target options.

💻 Basic example

I propose a command line flag, --package-name, for this purpose, which should work in conjunction with --scope.

For example:

wasm-pack build examples/js-hello-world --scope test --package-name custom-name

should result in an NPM package named @test/custom-name.

@fitzgen
Copy link
Member

fitzgen commented Nov 5, 2018

While I agree that we want to allow this functionality, I don't think adding a new flag is quite the fix we want.

rustwasm/rfcs#4 will likely end up allowing crates to write package.json snippets that are then merged into the package.json that wasm-pack creates. I think using this package.json merging would be the right way to customize the package name.

In the meantime, one can always edit the pkg/package.json manually.

@stristr
Copy link
Author

stristr commented Nov 5, 2018

Thanks for the response @fitzgen! I wanted to explain a bit more about the use case I imagine, because I don't think snippet-merging would help here and runtime renaming is actually preferable.

  1. I am building a Rust crate, bar. It is meant to be used anywhere I can use a Rust crate (e.g. I can build a native binary, I can compile it into an iOS or Android app, etc.).
  2. Separately, I would like to use wasm-bindgen to publish multiple different WebAssembly packages for different targets. For example, I might want to publish in the @foo scope twice, once with --target=browser (@foo/bar) and once with --target=commonjs (@foo/bar-node).
  3. Finally and perhaps most crucially, I don't want to deviate from standard tooling in order to manually edit package.json for these two different use cases.

As a basic example of how a runtime option would let me have it both ways: the excellent @wasm-tool/wasm-pack-plugin could be used like this, so that one webpack build produces both desired outputs:

module.exports = {
  plugins: [
    new WasmPackPlugin({
      crateDirectory: path.resolve(__dirname, "crate"),
      extraArgs: "--scope=foo",
    }),
    new WasmPackPlugin({
      crateDirectory: path.resolve(__dirname, "crate"),
      extraArgs: "--scope=foo --package-name=bar-node --out-dir=pkg-node",
    }), 
  ],
};

The first invocation produces a standard browser-compatible target called @foo/bar in ./crate/pkg. Most people will probably want this. But the second invocation produces a Node-compatible target called @foo/bar-node in ./crate/pkg-node. I might want to use @foo/bar-node directly in Node projects where I can't/don't want to transpile it with something like webpack; I also might want to hot-swap @foo/bar for @foo/bar-node in certain contexts, like if I'm writing unit tests for a library that depends on @foo/bar (jest and other unit testing frameworks make it very easy to hot-swap a module dependency without transpiling, but relatively difficult to do anything else).

So, in summary, I thought a new flag could be merited because it lets us use multiple package names with the same code base without having to rewrite anything.

@Pauan
Copy link
Contributor

Pauan commented Nov 5, 2018

For example, I might want to publish in the @foo scope twice, once with --target=browser (@foo/bar) and once with --target=commonjs (@foo/bar-node).

FYI, this is not common practice. Instead, it is standard to publish both the ES6 and CommonJS versions within the same package (using the main and module fields in package.json to distinguish them).

wasm-pack doesn't currently support this, but it will: #157 #313

As for browser vs Node, that's usually handled with the browser field in package.json, and/or runtime polyfilling, and/or dynamic loading.

As a basic example of how a runtime option would let me have it both ways

I think it's reasonable for the wasm-pack-plugin to support customized package.json names, however that doesn't mean that wasm-pack needs a new CLI flag.

If we add in ad-hoc flags to wasm-pack, that raises some questions like: why only allow for customizing the name? Why not the version? Why not other things? That leads to an explosion of various flags, which I don't think is very good.

Rather than adding flags to wasm-pack, I think the wasm-pack-plugin can auto-generate a package.json with different name fields, thus requiring no changes to wasm-pack.

It could even support a nice API like this:

module.exports = {
  plugins: [
    new WasmPackPlugin({
      crateDirectory: path.resolve(__dirname, "crate"),
      packageJson: {
        name: "@foo/bar"
      }
    }),
    new WasmPackPlugin({
      crateDirectory: path.resolve(__dirname, "crate"),
      packageJson: {
        name: "@foo/bar-node"
      }
    }), 
  ],
};

That would allow you to customize all of the package.json fields, which is much more flexible, and doesn't require adding any new flags to wasm-pack.

@stristr
Copy link
Author

stristr commented Nov 5, 2018

I agree #313 (with both main and module fields) is a more elegant solution. I'll pile on there, thanks 😄

@stristr stristr closed this as completed Nov 5, 2018
@Gisleburt
Copy link

Gisleburt commented Jan 28, 2019

For anyone else coming to this needing to change the package name more than just the --scope option allows, and for whom the above isn't ideal, my solution was this makefile.

SHELL = /bin/bash
.SHELLFLAGS := -eu -o pipefail -c
.DEFAULT_GOAL := build
.DELETE_ON_ERROR:
.SUFFIXES:

build: pkg

pkg: src
	wasm-pack build
	sed -i ".bak" -e 's/"name": "rust-package-name"/"name": "npm-package-name"/g' pkg/package.json
	rm pkg/package.json.bak

For those unfamiliar with make files, there is a bit of unnecessary fluff here but the important parts are:

  • pkg: src If the src directory is newer than pkg run the commands that follow.
  • wasm-pack build speaks for itself, feel free to customise
  • sed -i ".bak" -e "s/rust-package-name/npm-package-name/" pkg/package.json Allows us to change the name of the package from our rust package name to whatever we want to call it on npm. Note, the -i ".bak" is compatible with both OSX and Linux, however it will leave a file behind called package.json.bak.
  • rm pkg/package.json.bak Just removes that file.

Then, whenever you want to build, just run make.

One thing to watch out for, if the build fails it will remove the target (ie. the pkg directory), so just be aware of that and don't put non-generated files in there. Alternatively you could change the target to pkg/package.json and only that file will be removed.

@loky-lp
Copy link

loky-lp commented Jan 15, 2024

I don't think this issue should be marked as resolved because, while the original problem of @stristr was resolved, and I'm happy for it, the functionality is still missing and I think it's needed.

In my case I have multiple packages in a monorepo and I would like to prefix them with something like @repo/my-lib or @workspace/my-lib, but the @ it's not supported as a package name inside Cargo.toml.

Every way to replace generated package.json name seems a bit hacky to me and since lots of npm packages are scoped I don't see why this is not supported yet, but I'm open to discussion.

I think that a flag, like --package-name, would be the best way to implement this, allowing external tools, like the aforementioned @wasm-tool/wasm-pack-plugin, to easily create APIs like these

module.exports = {
  plugins: [
    new WasmPackPlugin({
      crateDirectory: path.resolve(__dirname, "crate"),
      packageJson: {
        name: "@foo/bar"
      }
    }),
    new WasmPackPlugin({
      crateDirectory: path.resolve(__dirname, "crate"),
      packageJson: {
        name: "@foo/bar-node"
      }
    }), 
  ],
};

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

5 participants