🚀 A starter project for module publisher! 🚀
Have you written some functions or React component that you're proud of? Do you want to share it as a standalone module on NPM, but find yourself unsure about the publishing process or how to manage the lifecycle of an open-source library?
Look no further - ts-ci is here to jumpstart your journey towards becoming a proficient NPM module author.
Main selling points:
ts-ci
utilizes automation within Github Actions. Simply update your package.json
version number and push. Your new version is automatically published on NPM. import { aSpecificFunction } from "your-module/aSpecificFile"
.https://user-images.githubusercontent.com/6702424/197344513-065246b9-8823-4894-a9a7-6c539da10655.mp4
🗣️ Since a recent GitHub update you need to manually allow GitHub Action to push on your repo.
Fo this reason the initial setup will fail.
You need to enabled permission and re-run failed job: see video
Settings
tab, then Secrets
you will need to add a new secret:
NPM_TOKEN
, you NPM authorization token.package.json
version
field ( 0.0.0
-> 0.0.1
for example) then push changes... that's all !X.Y.Z-rc.U
(example: 1.0.0-rc.32
). On NPM the version will be tagged next
. main
and on the branches that have a PR open on main
(You can publish pre-release from branches this way). package.json
details.#gh-dark-mode-only
syntax.import {...} from "my_module/theFile"
rather than "my_module/dist/theFile". If you dislike this behavior or if you only have an index.ts file and do not intend for users to selectively import from your module, you may remove this action.Contrary to what other guides or project starters may suggest, you don't need to bundle your library (or in other words you don't need to use Vite/Rollup),
nor do you need to fragment your modules into smaller, independently published units on NPM under the packages/
directory for your module
to be tree-shakable (e.g., @your-module/submodule1
, @your-module/submodule2
).
When you bundle your library, you incorporate all your dependencies into the .js
code you distribute. This could potentially lead to duplication of dependencies.
For instance, if your library depends on the classnames package, the entirety of classnames
source code will be included in your bundle. Subsequently, if a user of your library is also directly using classnames
, there will be two copies of classnames
in their final application bundle.
Another disadvantage of bundling is the lack of selective importing. For example, if a user wishes to import only a specific component or functionality from your module, they would be unable to do so. Instead, they are required to import the entire library.
Publishing independent units on NPM under the packages/
directory (e.g., @your-module/submodule1
, @your-module/submodule2
) is a common practice, but it's not necessarily a beneficial one. The first reason against this approach is that once you comprehend the fact that bundling isn't necessary, persisting with this process becomes somewhat pointless. The second reason concerns your users, who are then burdened with the responsibility of individually installing and synchronizing the various components' versions. This could cause potential inconsistencies and compatibility issues, making the user experience less efficient and potentially more troublesome.
The reality is much simpler. The responsibility of bundling lies with the final application; your role involves merely
publishing types declaration (.d.ts
) and the correct flavor of JavaScript files, which are the output of tsc
.
That's all there is to it!
By default your module release in CommonJS (CJS).
You want to avoid this strategy if:
import(...).then(...))
). type: module
mode AND you have some export default
(if you don't have export default it will work just fine).If you want to only release as ESM just set "module": "ES2020"
in your tsconfig.json
, you also probably want to set "target": "ES2017"
.
You can remove the listing of your export in the package.json it's not of any use.
This option has the advantage, if you are publishing a React library, to enable you to import assets file (.svg
, .css
) like for example here (Don't forget to copy your the assets from your src/
to your dist/
though, TypeScript don't do it for you).
You want to avoid this strategy if:
type: module
can't process (files need to have .mjs
extension, exports need to be listed).transpilePackages: ["<your-module>"]
in their next.config.js
file. Example.
This means also that you'd have to tell your users to configure their JEST so that it transpiles your module
using "transformIgnorePatterns": [ "node_modules/(?!@codegouvfr/react-dsfr)" ]
.package.json
has a bin
property) you'll need to transpile your script separately in CJS. tsconfig.json
that targets CSM (as by default): example package.json
, "module"
the condition for bundlers
"default"
is what will be picked up by node. example. You want to avoid this strategy if:
export default
and you want to support node in type: module
mode. import(...).then(...)
) and you want them to be lazy not only on the browser but on node too. Regardless of the scenario you opt for you can always release for Deno using Denoify.
Pursuing a fully compliant CJS + ESM distribution comes with caveats. It only works well if all your dependencies are adherent to the standard, a condition that most modules fail to meet.
This method introduces the risk of your package being simultaneously loaded in both CJS and ESM in a single node application. It also poses a similar risk to your dependencies.
Thus, proceed with this option only if it's necessary for your lazy imports to actually be lazy when your code runs on Node.
js2mjs
to ensure your ESM distribution generated by TypeScript is fully compliant with the standard (An external script should not be required for this!). See Example require
and import
. See Example.If you find your self thinking:
"I don't know man, ESM, CJS, I have no idea, I just want my stuff to work!"
"None of the option above covers all my requirement?"
"Why can't I have a solution that work in every case?"
"Why can't I publish an actual standard compliant ESM distribution?"
Just start a discussion or hit my Twitter DM I'll be happy to provide further guidance.