developit / microbundle

📦 Zero-configuration bundler for tiny modules.
https://npm.im/microbundle
MIT License
8.05k stars 362 forks source link

[typing import error][help wanted] The {{ package-name }} library may need to update its package.json or typings. #1070

Closed FranciscoKloganB closed 9 months ago

FranciscoKloganB commented 9 months ago

Description

Hey folks. I have been using microbundle for a while now, with great success. I have happily created a GitHub template that I pretty much use whenever I want to create a new package to reuse across projects, or that I want to open-source. However, this time around, I am having issues with typings.

Context

When I run my package.json build script (microbundle --target node && cp -r ./src/codegen ./dist/codegen, ), even tho I add --target node, I still get a warning message, telling me that a browser build was created.

$ npm run build

Creating a browser bundle that depends on Node.js built-in modules ("path"). You might need to include https://github.com/FredKSchott/rollup-plugin-polyfill-node;

Build "@franciscokloganb/appwrite-database-migration-tool" to dist:
      5.44 kB: index.cjs.gz
      4.61 kB: index.cjs.br
      5.78 kB: index.modern.mjs.gz
      4.94 kB: index.modern.mjs.br
      5.11 kB: index.module.js.gz
      4.35 kB: index.module.js.br
      5.45 kB: index.umd.js.gz
      4.61 kB: index.umd.js.br

Either way, I am able to publish the package to my local machine registry and use it on a single file typescript project I use to test the package locally.:

// No TypeScript errors
import * as APKG from '@franciscokloganb/appwrite-database-migration-tool';
import { createMigrationCollection } from '@franciscokloganb/appwrite-database-migration-tool';

console.log('MJS named import as aliased object:', typeof APKG.createMigrationCollection === 'function');
console.log('MJS named import destruct:', typeof createMigrationCollection === 'function');

However, once I publish my package to the NPM Registry and install it on a personal project to test the functionality from a real consumer perspective, I am getting the following error on the code below:

import { createMigrationCollection } from '@franciscokloganb/appwrite-database-migration-tool';

export default async (ctx) => {
  await createMigrationCollection({
    log: ctx.log,
    error: ctx.error,
  });
};
image

My package.json configuration

{
  "main": "./dist/index.js",
  "exports": {
    "require": "./dist/index.js",
    "default": "./dist/index.modern.mjs"
  },
  "module": "./dist/index.module.js",
  "unpkg": "./dist/index.umd.js",
  "source": "./index.ts",
  "types": "./dist/index.d.ts",
}

Questions

rschristian commented 9 months ago

Please provide a reproduction.

Some TS module resolutions require you add "types" your package.json#exports, i.e.,

{
  "main": "./dist/index.js",
  "exports": {
    "types": "./dist/index.d.ts",
    "require": "./dist/index.js",
    "default": "./dist/index.modern.mjs"
  },
  "module": "./dist/index.module.js",
  "unpkg": "./dist/index.umd.js",
  "source": "./index.ts",
  "types": "./dist/index.d.ts",
}

Edit:

How do I avoid creating a browser build.

You're not. This comes from Rollup, and can be safely ignored, though I have no clue how you're triggering it.

FranciscoKloganB commented 9 months ago

I will add the explicit "exports.types" as you suggested. If that fails, I will try to create a reproduction.

In the meantime... I noticed that the "test-project" that I use to test my exports had a different tsconfig.json.

The "test-project" uses "moduleResolution": "Node", whereas my "real-project", uses "moduleResolution": "Bundler".

I can't recall why I opted to use Bundler over ESNext... 🤔

The "real-project" kind of runs bun build ./functions/some-serverless-fn --outdir ./dist from where my Appwrite Backend as a Service reads the JS file from. Maybe that's why I did it.

See bun recommendations [here](https://bun.sh/docs/typescript#suggested-compileroptions.

rschristian commented 9 months ago

"moduleResolution": "bundler" requires exports.types, yes, see: https://www.typescriptlang.org/tsconfig#moduleResolution

FranciscoKloganB commented 9 months ago

Bless. Exports types worked. What a god send. Thanks for the prompt response @rschristian!

Question not at all related with microbundle, maybe you know how to do it.

It's my first time needing to add codegen utilities to a open-sourced package. Right now I am doing a recursive copy of codegen JS files and telling my users to run them like node node_modules/a_huge_path/file.js, do you happen to know how I could tell them to instead just do:

npx my-package script? Would it suffice to add the script to the package.json, like a regular project?

rschristian commented 9 months ago

Yay!

As for the second part, package.json#bin is what you're after. For example:

{
    "bin": "./dist/index.js"
}

Packages installed with this entry will be added to node_modules/.bin/ (typically through symlinks) which will allow you to run npx <package>, executing <package>/dist/index.js. If you wanted to offer it through a different name (like if it's namespaced, might be nicer to offer a shorter name), you can do so by making package.json#bin an object:

{
    "bin": {
        "short-name": "./dist/index.js"
    }
}

This'll allow npx short-name.

Full docs

Would it suffice to add the script to the package.json, like a regular project?

Depends a bit on what you want to offer I suppose. Do you want them to install & keep a copy in their project, or just offer a script to do something? npx is pretty loose here in that it'll run the package if it's already installed in the project, else, it'll pull it straight from NPM to run it. You don't necessarily need to tell users to install it/add it to a package.json if it's going to be more of a one-off or occasional thing.

FranciscoKloganB commented 9 months ago

Hmm nice. I am creating a migration-tool for structured database migration management with Appwrite. To ensure "stuff" works as intended and avoid errors from manual procedures, I want the users to be able to generate "empty" migration files, with commands.

So the idea would be something like npx admt new <outdir> <description>; So I guess it's an occasional thing.

rschristian commented 9 months ago

Fair enough, up to you then. npx can consume from a somewhat ill-defined cache, so the consequence of not installing it into the project as you would any other tool is that it can use a really old version (if its around) or pull a newer version than the user expects (with breaking changes they might not be aware of). I've personally always been happy with adding even an occasionally-used tool to my package.json and prefer it to the nebulous npx behavior, but that's just me.

FranciscoKloganB commented 9 months ago

Thanks so much for the tips! :)