dnt icon indicating copy to clipboard operation
dnt copied to clipboard

Building NPM module fails to find local module

Open rajinder-yadav opened this issue 11 months ago • 3 comments

Version: Deno 2.1.9

When building a NPM module with deno, it will error out and fail to find the local module.

deno run -A build_npm.ts 0.0.1"

Error

[dnt] Building project...
[dnt] Type checking ESM...
src/main.ts:6:17 - error TS2339: Property 'main' does not exist on type 'ImportMeta'.

6 if (import.meta.main) {
                  ~~~~
src/main_test.ts:2:30 - error TS2307: Cannot find module '@std/assert' or its corresponding type declarations.

2 import { assertEquals } from "@std/assert";
                               ~~~~~~~~~~~~~

error: Uncaught (in promise) Error: Had 2 diagnostics.
          throw new Error(`Had ${diagnostics.length} diagnostics.`);
                ^
    at getProgramAndMaybeTypeCheck (https://deno.land/x/[email protected]/mod.ts:450:17)
    at build (https://deno.land/x/[email protected]/mod.ts:343:17)
    at eventLoopTick (ext:core/01_core.js:177:7)
    at async file:///tmp/npm/myadd/build_npm.ts:5:1

deno.json

{
  "tasks": {
    "dev": "deno run --watch main.ts",
    "npm": "deno run -A build_npm.ts 0.0.1"
  },
  "imports": {
    "@std/assert": "jsr:@std/assert@1"
  }
}

main_test.ts

import { assertEquals } from "@std/assert";
import { myAdd } from "./main.ts";

Deno.test(function addTest() {
  assertEquals(myAdd(2, 3), 5);
});

main.ts

export function myAdd(a: number, b: number): number {
  return a + b;
}

// Learn more at https://docs.deno.com/runtime/manual/examples/module_metadata#concepts
if (import.meta.main) {
  console.log("Add 2 + 3 =", myAdd(2, 3));
}

build_npm.ts

import { build, emptyDir } from "https://deno.land/x/[email protected]/mod.ts";

await emptyDir("./npm");

await build({
  entryPoints: ["./main.ts"],
  outDir: "./npm",
  shims: {
    deno: true,
  },
  package: {
    name: "myapp",
    version: Deno.args[0],
    description:
      "Boolean function that returns whether or not parameter is the number 42",
    license: "MIT",
    repository: {
      type: "git",
      url: "git+https://github.com/lambtron/is-42.git",
    },
    bugs: {
      url: "https://github.com/lambtron/is-42/issues",
    },
  },
  postBuild() {
    Deno.copyFileSync("README.md", "npm/README.md");
  },
});

rajinder-yadav avatar Feb 07 '25 03:02 rajinder-yadav

I seem to be having the same issue, execution and tests work fine in deno, but when I try to bundle for npm i get a series of errors relating to the included packages:

build script

$ cat scripts/build_npm.ts
import { build, emptyDir } from "@deno/dnt";
import deno from "../deno.json" with { type: "json" };

await emptyDir("./npm");

await build({
  typeCheck: "both",
  entryPoints: ["./index.ts"],
  outDir: "./npm",
  shims: {
    deno: "dev",
    timers: true
  },
  package: {
    // package.json properties
    name: deno.name,
    version: deno.version,
    description: deno.description,
    license: deno.license,
    repository: {
      type: "git",
      url: "git+https://github.com/silverbucket/ajv-formats-draft2019.git",
    },
    bugs: {
      url: "https://github.com/silverbucket/ajv-formats-draft2019/issues",
    },
  },
  postBuild() {
    // steps to run after building and before running the tests
    Deno.copyFileSync("LICENSE", "npm/LICENSE");
    Deno.copyFileSync("README.md", "npm/README.md");
  },
});

deno.json

{
  "name": "@silverbucket/ajv-formats-draft2019",
  "version": "1.6.5",
  "description": "Plugin for AJV that adds support for some of string formats adding in the draft2019 JSON Schema.",
  "exports": "./index.ts",
  "tasks": {
    "coverage": "deno coverage | deno run jsr:@silverbucket/threshold 77 93",
    "test": "deno test --fail-fast --coverage --clean --allow-env --allow-read *.test.ts",
    "build:npm": "deno run -A scripts/build_npm.ts",
    "publish:npm": "cd npm && npm publish && cd .."
  },
  "license": "MIT",
  "imports": {
    "@deno/dnt": "jsr:@deno/dnt@^0.41.3",
    "@silverbucket/iana-schemes": "jsr:@silverbucket/iana-schemes@^1.4.2",
    "punycode-esm": "npm:punycode-esm@^1.0.14",
    "smtp-address-parser": "npm:smtp-address-parser@^1.1.0",
    "uri-js-replace": "npm:uri-js-replace@^1.0.1",
    "ajv": "npm:ajv@^8.17.1"
  }
}

build output

$ deno clean && deno i && deno task build:npm
Removed /Users/njenning/Library/Caches/deno (1606 files, 28.81MB)
Task build:npm deno run -A scripts/build_npm.ts
[dnt] Transforming...
Download https://jsr.io/@std/assert/meta.json
...
Download https://jsr.io/@std/internal/1.0.5/types.ts
[dnt] Running npm install...

added 13 packages, and audited 14 packages in 3s

2 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
[dnt] Building project...
[dnt] Type checking ESM...
src/deps/jsr.io/@std/assert/1.0.11/assertion_error.ts:27:42 - error TS2304: Cannot find name 'ErrorOptions'.

27   constructor(message: string, options?: ErrorOptions) {
                                            ~~~~~~~~~~~~
src/deps/jsr.io/@std/assert/1.0.11/assertion_error.ts:28:20 - error TS2554: Expected 0-1 arguments, but got 2.

28     super(message, options);
                      ~~~~~~~
src/deps/jsr.io/@std/assert/1.0.11/equal.ts:148:22 - error TS2339: Property 'symmetricDifference' does not exist on type 'Set<unknown>'.

148             return a.symmetricDifference(b).size === 0;
                         ~~~~~~~~~~~~~~~~~~~
src/deps/jsr.io/@std/assert/1.0.11/equal.ts:194:31 - error TS2339: Property 'union' does not exist on type 'Set<string | symbol>'.

194         keys = getKeysDeep(a).union(getKeysDeep(b));
                                  ~~~~~
src/deps/jsr.io/@std/assert/1.0.11/object_match.ts:136:47 - error TS2339: Property 'intersection' does not exist on type 'Set<any>'.

136           defineProperty(filtered, key, value.intersection(subset));
                                                  ~~~~~~~~~~~~
src/deps/jsr.io/@std/assert/1.0.11/object_match.ts:201:31 - error TS2339: Property 'intersection' does not exist on type 'Set<any>'.

201           filtered.push(value.intersection(subset));
                                  ~~~~~~~~~~~~
src/deps/jsr.io/@std/expect/1.0.13/_equal.ts:169:22 - error TS2339: Property 'symmetricDifference' does not exist on type 'Set<unknown>'.

169             return a.symmetricDifference(b).size === 0;
                         ~~~~~~~~~~~~~~~~~~~
src/formats/idn-email.ts:1:23 - error TS2307: Cannot find module 'smtp-address-parser' or its corresponding type declarations.

1 import { parse } from "smtp-address-parser";
                        ~~~~~~~~~~~~~~~~~~~~~
src/formats/idn-hostname.ts:1:25 - error TS2307: Cannot find module 'punycode-esm' or its corresponding type declarations.

1 import { toASCII } from "punycode-esm";
                          ~~~~~~~~~~~~~~
src/formats/iri-reference.ts:1:43 - error TS2307: Cannot find module 'uri-js-replace' or its corresponding type declarations.

1 import { parse, type URIComponents } from "uri-js-replace";
                                            ~~~~~~~~~~~~~~~~
src/formats/iri-reference.ts:2:40 - error TS2307: Cannot find module 'smtp-address-parser' or its corresponding type declarations.

2 import { parse as addressParser } from "smtp-address-parser";
                                         ~~~~~~~~~~~~~~~~~~~~~
src/formats/iri-reference.ts:3:21 - error TS2307: Cannot find module '@silverbucket/iana-schemes' or its corresponding type declarations.

3 import schemes from "@silverbucket/iana-schemes";
                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/formats/iri.ts:1:41 - error TS2307: Cannot find module 'uri-js-replace' or its corresponding type declarations.

1 import uri, { type URIComponents } from "uri-js-replace";
                                          ~~~~~~~~~~~~~~~~
src/formats/iri.ts:2:25 - error TS2307: Cannot find module 'smtp-address-parser' or its corresponding type declarations.

2 import smtpAddress from "smtp-address-parser";
                          ~~~~~~~~~~~~~~~~~~~~~
src/formats/iri.ts:3:21 - error TS2307: Cannot find module '@silverbucket/iana-schemes' or its corresponding type declarations.

3 import schemes from "@silverbucket/iana-schemes";
                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~

error: Uncaught (in promise) Error: Had 15 diagnostics.
          throw new Error(`Had ${diagnostics.length} diagnostics.`);
                ^
    at getProgramAndMaybeTypeCheck (https://jsr.io/@deno/dnt/0.41.3/mod.ts:468:17)
    at build (https://jsr.io/@deno/dnt/0.41.3/mod.ts:354:17)
    at eventLoopTick (ext:core/01_core.js:177:7)
    at async file:///Users/njenning/code/projects/ajv-formats-draft2019/scripts/build_npm.ts:6:1

Repository: https://github.com/silverbucket/ajv-formats-draft2019

silverbucket avatar Feb 08 '25 11:02 silverbucket

I can get around the type checking failures by adding typeCheck: false, to my dnt build script:

await build({
  typeCheck: false,
  entryPoints: ["./index.ts"],
...

However this leads to another issue where the npm packages are not being added to the generated package.json:

$ deno clean && deno i && deno task build:npm
Removed /Users/njenning/Library/Caches/deno (1601 files, 32.56MB)
Task build:npm deno run -A scripts/build_npm.ts
[dnt] Transforming...
Download https://deno.land/x/punycode/punycode.js
Download https://jsr.io/@std/assert/meta.json
...
Download https://jsr.io/@std/internal/1.0.5/types.ts
[dnt] Running npm install...

added 12 packages, and audited 13 packages in 4s

2 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
[dnt] Building project...
[dnt] Emitting ESM package...
[dnt] Emitting script package...
[dnt] Running post build action...
[dnt] Running tests...

> @silverbucket/[email protected] test
> node test_runner.js

Running tests in ./script/index.test.js...

Error: Cannot find module 'uri-js-replace'
Require stack:
- /Users/njenning/code/projects/ajv-formats-draft2019/npm/script/formats/iri.js
- /Users/njenning/code/projects/ajv-formats-draft2019/npm/script/formats/index.js
- /Users/njenning/code/projects/ajv-formats-draft2019/npm/script/index.test.js
- /Users/njenning/code/projects/ajv-formats-draft2019/npm/test_runner.js
    at Function._resolveFilename (node:internal/modules/cjs/loader:1249:15)
    at Function._load (node:internal/modules/cjs/loader:1075:27)
    at TracingChannel.traceSync (node:diagnostics_channel:322:14)
    at wrapModuleLoad (node:internal/modules/cjs/loader:219:24)
    at Module.require (node:internal/modules/cjs/loader:1340:12)
    at require (node:internal/modules/helpers:138:16)
    at Object.<anonymous> (/Users/njenning/code/projects/ajv-formats-draft2019/npm/script/formats/iri.js:6:42)
    at Module._compile (node:internal/modules/cjs/loader:1565:14)
    at Object..js (node:internal/modules/cjs/loader:1708:10)
    at Module.load (node:internal/modules/cjs/loader:1318:32) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [
    '/Users/njenning/code/projects/ajv-formats-draft2019/npm/script/formats/iri.js',
    '/Users/njenning/code/projects/ajv-formats-draft2019/npm/script/formats/index.js',
    '/Users/njenning/code/projects/ajv-formats-draft2019/npm/script/index.test.js',
    '/Users/njenning/code/projects/ajv-formats-draft2019/npm/test_runner.js'
  ]
}
error: Uncaught (in promise) Error: npm run test failed with exit code 1
      throw new Error(
            ^
    at runCommand (https://jsr.io/@deno/dnt/0.41.3/lib/utils.ts:56:13)
    at eventLoopTick (ext:core/01_core.js:177:7)
    at async build (https://jsr.io/@deno/dnt/0.41.3/mod.ts:419:5)
    at async file:///Users/njenning/code/projects/ajv-formats-draft2019/scripts/build_npm.ts:6:1

The needed packages do not exist:

$ cat npm/package.json
{
  "name": "@silverbucket/ajv-formats-draft2019",
  "version": "1.6.5",
  "description": "Plugin for AJV that adds support for some of string formats adding in the draft2019 JSON Schema.",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/silverbucket/ajv-formats-draft2019.git"
  },
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/silverbucket/ajv-formats-draft2019/issues"
  },
  "main": "./script/index.js",
  "module": "./esm/index.js",
  "exports": {
    ".": {
      "import": "./esm/index.js",
      "require": "./script/index.js"
    }
  },
  "scripts": {
    "test": "node test_runner.js"
  },
  "devDependencies": {
    "@types/node": "^20.9.0",
    "picocolors": "^1.0.0",
    "ajv": "*",
    "@deno/shim-deno": "~0.18.0"
  },
  "_generatedBy": "dnt@dev"
}%

$ cat deno.json
{
  "name": "@silverbucket/ajv-formats-draft2019",
  "version": "1.6.5",
  "description": "Plugin for AJV that adds support for some of string formats adding in the draft2019 JSON Schema.",
  "exports": "./index.ts",
  "tasks": {
    "coverage": "deno coverage | deno run jsr:@silverbucket/threshold 77 93",
    "test": "deno test --fail-fast --coverage --clean --allow-env --allow-read *.test.ts",
    "build:npm": "deno run -A scripts/build_npm.ts",
    "publish:npm": "cd npm && npm publish && cd .."
  },
  "license": "MIT",
  "imports": {
    "@deno/dnt": "jsr:@deno/dnt@^0.41.3",
    "@silverbucket/iana-schemes": "jsr:@silverbucket/iana-schemes@^1.4.4",
    "smtp-address-parser": "npm:smtp-address-parser@^1.1.0",
    "uri-js-replace": "npm:uri-js-replace@^1.0.1",
    "ajv": "npm:ajv@^8.17.1"
  }
}

I'm a little surprised at how complicated this is, these are already node packages, and I'm trying to build a package to publish to npm. All that needs to happen are the packages included in the package.json. Or is there something else I'm missing?

silverbucket avatar Feb 08 '25 13:02 silverbucket

@silverbucket you might also want to add to the npm build script the following to skip test, which is where I was seeing the build error with dnt.

test:false,

With this setting, I was able to build and publish my npm library.

rajinder-yadav avatar Feb 24 '25 02:02 rajinder-yadav