npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@khatastroffik/one-ts-for-all

v1.0.0

Published

A PoC demonstrating a Typescript 'library' project with multiple targets (CJS, EMS, CLI...)

Downloads

3

Readme

One Typescript for all

This is a PoC demonstrating a "single source" Typescript library project generating automatically multiple versions of the script (CJS, ESM, TS) and a sample CLI: ONE-FOR-ALL

Overview

one-typescript-for-all Architecture

Objectives

SINGLE TYPESCRIPT INPUT → MULTIPLE OUTPUT

This is the main objective: ONE-FOR-ALL!

  • Implement a library using Typescript exclusively.
  • Use the library with any client which is able to use/run CommonJS, ECMAScript or Typescript modules.

RUN ESM LIBRARIES IN THE BROWSER

A browser app/client may use the ESM library directly. In this case, a modern browser is required. This use case is demonstrated in this PoC.

Older browser would require to adapt the scripts before integration, using a supplemental "transpiler" to output compatible scripts - hence requiring a further implementation step. Such older browsers aren't in the focus of this project.

Requirements

Node.js and NPM (or yarn) should be "globally" installed on your system to ease the installation of the packages and/or source files. Preferably:

  • node: >=13.x
  • npm: >=6.x

Typescript may be globally present as well, thus is not required, since the PoC will use its own (local) version:

  • tsc: >=3.9.5 (earlier version like 3.8.x should be ok - not tested, though)

Project Development versus Package Publication

The PoC is configured (package.json and .gitignore) to separate development and usage of the lib/app: "GitHub" versus "NPM".

  1. The bare sources (typescript only) of the library and application are stored in the Github Repository. use this if you'd like to develop, adapt etc. the library/application

  2. The transpiled i.e. usable library artifact (ESM, CommonJS, Typescript and *.d.ts types declaration files ) is stored in the NPM repository - though without the source files.
    use this if you'd like to use the library/application in your project.

This separation is intended:

  • to reduce the size of the published package to the min possible and
  • to clearly separate the different concerns.

Note: the artifacts i.e the files could be minified and thus reduce the size of the package furthermore. This is not implemented here, though.

How to implement "one-for-all"?

This section summarize the techniques i.e. engineering procedures used to realize the "one-for-all" objective.

Sources

The sources files are all contained in the src folder. No exception.

Typescript compiler (TSC) configuration

The output (multiple modules i.e. CJS, ESM...) of TSC is driven by the different tsconfig.*.jsonfiles and by the package.json file:

  1. There's intentionally NO default tsconfig.json file in this project! Instead, builds are created on purpose i.e specifically through targeting a specific tsconfig.
  2. The tsconfig.common.json is declaring the configuration shared by all targets. Hence, it correspond to a traditional tsconfig.json, though rename on purpose (see above).
  3. The tsconfig.bin.json is targeting the generation/output of the CLI application in the bin folder.
  4. The tsconfig.esm.json is targeting the generation/output of the ESM scripts version in the lib/esm/ folder.
  5. The tsconfig.cjs.json is targeting the generation/output of the ESM scripts version in the lib/esm/ folder.
  6. The tsconfig.types.json is generating the types declaration *.d.ts files for the Typescript scripts version in the lib/ts/ folder. This is required to provide those files in the npm package.

.gitignore file

Since the source code repository should NOT contain the "output" of the compilation/distribution, the .gitignore file excludes the corresponding folders: /lib and /bin.

npm scripts

In order to generate the output i.e to produce the different artifacts (ESJ, ESM, CLI and TS) to be published in a NPM repository easily, the package.json defines some npm scripts. Those scripts can be executed using:

> npm run <name-of-the-script>

The most important npm scripts of the project are described below:

{
  "scripts": {

    // ===== EXECUTE CLI =============================

    // RUN the CLI application using TS-NODE (no artifact is generated)
    "start": "ts-node --project tsconfig.common.json src/application.ts -d",

    // START the COMPILED CLI application (prior build is required)
    "node": "node bin/application.js",

    // ===== BUILD ARTIFACTS ========================

    // BUILD the single artifacts
    "build:bin": "tsc -p tsconfig.bin.json",
    "build:cjs": "tsc -p tsconfig.cjs.json",
    "build:esm": "tsc -p tsconfig.esm.json",
    "build:types": "tsc -p tsconfig.types.json",

    // BUILD ALL artifacts at once
    "build": "npm run build:types && npm run build:bin && npm run build:cjs && npm run build:esm",

    // ===== PACKAGE PUBLICATION======================

    // PREPARE and GENERATE all artifacts for publishing usage
    "prod": "npm run cleanup && npm run build && npm run copyts && npm run test:prod",

    // check the content of the NPM package i.e. the list of artifacts that should be published
    "checkpkg": "pkgfiles",

    // Pre-publishing (this script will be executed by NPM automatically when publishing)
    "prepublishOnly": "npm run prod",

    // ===== DEVELOPMENT ONLY ========================

    // generate the artifacts and link the project in the local npm repository
    "local:publish": "npm run prod && npm link",
    // undo the local npm repository link
    "local:unpublish": "npm unlink && npm run cleanup:nodemodules && npm install",

    // ===== HELPERS =================================

    // delete the folders containing the published artifacts
    "cleanup": "rimraf ./lib ./bin ./coverage",
    // delete the node_modules folder (e.g. when un-linking the project to local npm repository)
    "cleanup:nodemodules": "npx rimraf ./node_modules",
    // copy the Typescript artifacts to be published in the npm package
    "copyts": "copyfiles -u 2 src/lib/**/* -e **/*.spec.ts lib/ts"
  }
}

Note: Using this configuration allows to publish the library on NPM without hassle. Just call > npm publish! The configured npm scripts will do the rest.

The package.json targets

Once the artifacts are produced and published, a client project intending to use the library package will operate a lookup in the package definition to find and use an appropriate library artifact:

this automatic lookup is using the following fields (if available) as defined in the package.sjon file:

{
  // This define the DEFAULT artifact of the package. Here: the TYPESCRIPT version
  "main": "lib/ts/library.ts",

  // Tells the client project where the type declarations are located
  "types": "lib/ts/library.d.ts",

  // Locate the main ESM artifact for an ESM capable environment (e.g. node >= v13.* if configured approprietly)
  "module": "lib/esm/library.js",

  // Locate the main ESM artifact for Browser environment...
  "browser": "lib/esm/library.js",

  // This location is NOT standard, thus included here for documentation purposes.
  // The value could be used in place of the "main" defined above = to publish a CJS-BY-DEFAULT package
  "node": "lib/cjs/library.js",

  // Locate the CLI app artifact. Used when installing the package to register the CLI on the system (localy or globaly). The CLI executable is registered as "ts4all" here.
  "bin": {
    "ts4all": "bin/application.js"
  },
}

Notes: The PoC package is defining the "Typescript artifact" as the default. Instead, the "CJS artifact" could have been declared as default through the key-value "main": "lib/cjs/library.js".

Important !

The "main", "module" and "browser" keys specified in the library (i.e. in the package.json of the library) do impact the binding of the library in any client project: the configuration in the library entails the suitable usage of the import ... from ...; and ... = require(...); statements (including suitable paths) in the client projects!

Thus, it is recommended to never change this specification after the library package has been published. Otherwise, a "BREAKING CHANGE" should be commited and a major version released! (See BREAKING CHANGES in commits)

Project documentation