'Best practice to publish src folder that contains esm modules

Consider this package.json:

{
  "main": "./index.js",
  "name": "@myorg/foo",
  "scripts": {
    "build": "babel src -d dist --delete-dir-on-start --source-maps inline --copy-files --no-copy-ignored",
    "check-release": "npm run release --dry-run",
    "postbuild": "cp package.json dist",
    "release": "npm run build && cd dist && npm publish"
  }
}

I'm trying to figure out what's the best practice in order to adjust it so it'll publish the src folder that contains ESM modules in a way that'll allow tree-shaking in the final app (CRA app).

Right now there are some issues with the above package.json:

  • npm publish won't behave as I'd like to - you need to use npm run release instead and that's not good as other tooling will rely on publish
  • To create the dist folder I'm using Babel but that doesn't feel right, is it better to use another tool instead to bundle it? My goal is the final app being able to use all imports easily (with no subpath exports, index, aliases, ...)

How would you adjust the above package.json to fullfill the above requirements?



Solution 1:[1]

Below are the two points answered!


npm publish won't behave as I'd like to... you need to use npm run release instead and that's not good as other tooling will rely on publish.

If you look below, you can see that Babel has been removed. Due to this, there is no need for your release script anymore.

You can just run the publish command when it is ready.

$ npm publish --access=public

Remember, this only works if you did the below!


To create the dist folder I'm using Babel but that doesn't feel right, is it better to use another tool instead to bundle it? My goal is the final app being able to use all imports easily (with no subpath exports, index, aliases, ...).

You can follow a few steps to stop using Babel and use an alternative:

  1. In your package.json, add the following key:

    {
      "type": "module"
    }
    

    With this, also change require() to import, and module.exports to export. For example:

    // Before...
    const foo = require("@myorg/foo");
    module.exports = { func };
    
    // After...
    import foo from "@myorg/foo";
    export { func };
    
  2. Instead of importing and exporting everything from one file, you can do that in a simpler way in package.json. You need to just add something like below:

    {
      "exports": {
        ".": "./dist/index.js",
        "./feature": "./dist/feature.js",
      }
    }
    

    For more information, see the documentation.

  3. When someone downloads your module, they will import like this (like Firebase):

    import index from "@myorg/foo"; // index.js
    import features from "@myorg/foo/features"; // features.js
    

Not sure if these fully answered your question, but they might give you a starting point!

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1