ckb-cell / rgbpp-sdk

Utilities for Bitcoin and RGB++ asset integration
ISC License
53 stars 15 forks source link

refactor(rgbpp-sdk): Support ESM package #246

Open duanyytop opened 2 weeks ago

duanyytop commented 2 weeks ago

Main Changes

ShookLyngs commented 2 weeks ago

I will test if the following changes bring any issues:


A snapshot version is released: 0.0.0-snap-20240702110120

Will also test if the refactored libs can be imported/called normally in both ESM and CJS projects:

duanyytop commented 1 week ago

The lint staged commands and changeset have been updated @ShookLyngs

ShookLyngs commented 1 week ago

The new commits 4f61ed8, 6096395 and 53fc8ee should have resolved the previous issues. If they occur again, we can update them in new comments to make the entire timeline clearer.

The repo for testing the compatibility of ESM/CJS has also been updated to refence a new snapshot version (0.0.0-20240705090030): https://github.com/ShookLyngs/test-rgbpp-pure-esm/commit/789c114ba8fa71ffc368e0c49a904b97b88d0a61. You can run command make test to test if the rgbpp package can be imported and executed in both .cjs and .mjs environments.

ShookLyngs commented 1 week ago

Discussion: Should we change the moduleResolution to NodeNext?

Previously, when testing rgbpp in ESM, an error was reported indicating that subpath imports should always contain file extensions. For example, when importing a JS file, the .js extension must be included in the import syntax:

import { xx } from './a'; // Invalid
import { xx } from './a.js'; // Valid

Ref to documentation of Node.js for more: https://nodejs.org/api/esm.html#mandatory-file-extensions

Since all our source files will be packed into a single file when bundling with tsup, there should be no import { xx } from './a' syntax. The only type of imports left after bundling are package imports for importing packages. To address the issue, all subpath package imports in the packages have been refactored to include the .js file extension:

import { xx } from 'pkg/lib/some'; // From
import { xx } from 'pkg/lib/some.js'; // To

However, there is still an issue: our current tsconfig settings do not enforce the inclusion of file extensions in imports, and both tsc and tsup do not handle file extension in the imports. Related discussions:

This leads to an incompatibility problem where, if in the future we add new package dependencies, there is nothing to help us check or validate if the new imports are handled correctly:

import { a } from 'old-pkg/lib/some.js'; // Handled correctly
import { b } from 'new-pkg/lib/other'; // Lacks ".js" extension in the path, but no warning

Possible solutions:

  1. Update "moduleResolution": "NodeNext" in tsconfig.json. This requires all relative imports to contain file extensions, but we would need to refactor all our code to satisfy this requirement.
  2. Configure eslint to add a rule that requires package imports to include file extension: https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/extensions.md.
  3. Add "bundle libs" and "execute bundled libs" as a form of integration testing to ensure packages can be executed in both CJS and ESM environments.

Ideas and comments are welcomed.

duanyytop commented 1 week ago

The first solution makes sense to me and the reason can be found in the following comment https://github.com/ckb-cell/rgbpp-sdk/pull/246#discussion_r1670137658.