deno
deno copied to clipboard
Ability to use a local copy of npm package
Is there any way to use a local (modified) copy of an NPM package instead of a published one in this command? Thanks!
deno run -A --unstable npm:vite
No, it's not something that's possible at the moment, but definitely on our radar. It wouldn't be difficult to implement. It's more a question of how it's specified so if anyone has any ideas let us know.
Maybe like npm:///path/to/local/package/folder, then if you do npm:///path/to/local/package/folder/some/sub_path.js it would resolve the first actual package.json going up the parents (so at /path/to/local/package/folder/package.json) and then resolve the rest of the path (./some/sub_path.js) as a subpath from there. I'm not sure though and there's probably some way that breaks down.
For now, I suppose just some way to use tarball would be sufficient, one can just do npm pack and deno run. 🤔
This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 7 days if no further activity occurs. Thank you for your contributions.
Yes, we need the ability to import local packages.
Usage scenario: I am an author of an npm package and I need to test if my npm package works well in deno.
+1 here, I am attempting to make test an npm package using native modules in deno and this would have made my life much easier
@dsherret mind providing some extra context around this? I might try and find some time to give this a go
This one probably requires about 1-2 weeks of work because we'd have to support having multiple paths for what we consider to be "node code" and it introduces a new concept in npm resolution where we need to get package information from the file system instead of just the npm registry and then also make this work with node resolution. I wouldn't recommend it as a first task.
In the meantime, for testing npm packages locally you can use the --node-modules-dir flag to cache an existing version of a package locally and make modifications to it. For example:
> cat main.ts
import CodeBlockWriter from "npm:[email protected]";
console.log(CodeBlockWriter);
> deno cache --node-modules-dir main.ts
> # overwrite the contents of node_modules/.deno/[email protected]/node_modules/code-block-writer here and make sure to leave the `.initialized` file
> deno run --node-modules-dir main.ts # this will now use your modifications
Something like verdaccio should also work along with NPM_CONFIG_REGISTRY env var 👀
This would solve the problems with CI testing that npm packages work with Deno: https://github.com/denoland/deno/issues/19621
In the meantime, for testing npm packages locally you can use the
--node-modules-dirflag to cache an existing version of a package locally and make modifications to it. For example:
I could not get this to work at all until I added a package.json file containing an empty object {} in the same directory. Then it worked.
👋 I maintain the replicate package, and recently added integration tests for Deno, following @dsherret's suggestion in https://github.com/denoland/deno/issues/15624#issuecomment-1511621310 and @alexgleason's tip in https://github.com/denoland/deno/issues/15624#issuecomment-1967080476.
Here's what worked for us:
- Create a tarball of the package using
npm --loglevel error pack[^1] - Create a Deno test project with the following files:
// deno.json
{
"imports": {
"replicate": "npm:replicate"
}
}
// package.json
{}
The app runs a hello-world model on Replicate that echoes back the string input sent to it. The test runs the app and tests its expected output.
// index.ts
import Replicate from "replicate";
const replicate = new Replicate({
auth: Deno.env.get("REPLICATE_API_TOKEN"),
});
export default async function main() {
return await replicate.run(
"replicate/hello-world:5c7d5dc6dd8bf75c1acaa8565735e7986bc5b66206b55cca93cb72c9bf15ccaa",
{
input: {
text: "Deno the dinosaur",
},
}
);
}
// index.test.ts
import { assertEquals } from "jsr:@std/assert";
import main from "./index.ts";
Deno.test({
name: "main",
async fn() {
const output = await main();
assertEquals({ output }, { output: "hello Deno the dinosaur" });
},
});
- In the Deno test project, run
deno cache --node-modules-dir index.tsto initialize anode_modulesdirectory - Overwrite the
replicatemodule with the contents of the tarball from before by runningtar -xzf path/to/tarball --strip-components=1 -C integration/deno/replicate[^2] - Invoke the test with
deno test --allow-env --allow-net --node-modules-dir index.test.ts
It'd be nice for Deno to support overriding npm modules directly from a tarball file. But for now, this seems to work for us, and I'm happy to have found a way to verify that our package supports Deno.
[^1]: In our GitHub Actions workflow we have a build job that uses actions/upload-artifact to use this tarball in integration tests
[^2]: npm pack creates an archive with the contents nested under a top-level package directory. The --strip-components=1 option tells tar to write the contents of that directory into node_modules/replicate without nesting.
@mattt I wonder if that works if the package has dependencies though? I don't see any dependencies in replicate's package.json.
@jedwards1211 Good question. I think it might. The replicate package has an optional dependency on readable-stream, and after applying this workflow, the node_modules/.deno directory includes a cache of [email protected]. So Deno is resolving that at least.