Project Configuration

Below are the required system and file configurations for creating NPM packages.

1. Setting Up Your System

Please ensure your system has the following installations:

  • Git
  • Node 22.13 (or greater)
  • NPM 10.9 (or greater)
An icon of a key1
  • Use the Git tutorial to install, update, or verify Git on your system.
  • Use the package manager tutorial to install, update, or verify Node and NPM on your system.

2. Creating a Project Directory

Create a new folder for your project like so:

Figure 1. Command Line
1 mkdir thank-you-tweet-button-001
An icon of a info-circle1

You may use any name. For example, this tutorial uses thank-you-tweet-button-001.

An icon of a key1
  • Specify a name that is less than or equal to 214 characters.
  • Use lowercase letters only in the name.
  • Your package’s name should not contain “js” or “node”.

Afterward, navigate to your project directory using the command line.

Figure 2. The Syntax to Change to a Different Directory
1 cd path/to/thank-you-tweet-button-001

3. Creating a package.json File

Use NPM to initialize a package.json file for your project.

Figure 3. Command Line
1 npm init -y

Let’s also configure Git.

4. Initializing a Git Repository

Create a .git repo in your project’s root directory:

Figure 4. Command Line
1 git init

You now need to specify the files you want Git to ignore.

5. Specifying the Files Git Should Ignore

Create a .gitignore file in your project’s root directory:

Figure 5. Command Line
1 touch .gitignore

Afterward, open the newly created .gitignore file and write the names of the files, folders, or file types you want Git to ignore.

Here’s an example:

Figure 6. .gitignore
1 /node_modules
2 /dist

The snippet above instructs Git to ignore tracking the current directory’s node_modules and dist folders.

An icon of a info-circle1
  • A current directory is the folder in which you are currently working.
  • A current directory is sometimes called a “current working directory (CWD)” or “working directory.”
  • See the .gitignore file example to learn more about gitignore.

It’s now time to stage and commit your recent changes.

6. Staging and Committing Your Project’s Changes to Git

Enter the following command on your terminal to stage and commit your recent changes.

Figure 7. Command Line
1 git add -A && git commit -m "Initialize project using CodeSweetly's guide"

The command above tells Git to stage and commit all modified and untracked files in the project.

Let’s now configure a remote repository for the project.

7. Configuring a GitHub Remote Repository

  1. Go to the GitHub website and sign in or create an account if you do not have one.
  2. After signing in, create a new GitHub repository. You may use thank-you-tweet-button-001 or another name of your choice.
  3. Once you’ve created a remote repository for your package, link your project’s .git directory (located locally on your system) with the remote repository on GitHub. To connect to the remote repository, go to your package’s root directory via your local terminal and run the git remote add command. Here’s the syntax:
Figure 8. Command Line
1 git remote add origin https://github.com/your-username/remote-repo-name.git
An icon of a info-circle1
  • Replace your-username in the code above with your GitHub username. Likewise, replace remote-repo-name with your remote repository’s name.
  • See GitHub Docs to learn more about creating a GitHub repository.

You can also add the remote repo to your package.json file so that people who want to contribute to your project can easily access it.

Figure 9. package.json: Add repository field (line 4-7)
 1 {
 2   "name": "thank-you-tweet-button-001",
 3   "version": "1.0.0",
 4   "repository": {
 5     "type": "git",
 6     "url": "https://github.com/your-username/app-repo-name.git"
 7   },
 8   "scripts": {
 9     "test": "echo \"Error: no test specified\" && exit 1"
10   }
11 }

Let’s provide the remote repo’s Issues URL as the package’s bug tracker. And an email people can use to report issues:

Figure 10. package.json: Add bugs field (line 8-11)
 1 {
 2   "name": "thank-you-tweet-button-001",
 3   "version": "1.0.0",
 4   "repository": {
 5     "type": "git",
 6     "url": "https://github.com/your-username/app-repo-name.git"
 7   },
 8   "bugs": {
 9     "url": "https://github.com/your-username/app-repo-name/issues",
10     "email": "your-project-email@host.com"
11   },
12   "scripts": {
13     "test": "echo \"Error: no test specified\" && exit 1"
14   }
15 }

Afterward, stage and commit your changes:

Figure 11. Command Line
1 git add -A && git commit -m "Configure project's remote repo"

Let’s now push the local Git repository upstream.

8. Uploading Your Local Git Directory to the Remote Repo

After successfully connecting your local directory to the remote repository, you can begin pushing (uploading) your local project upstream. Here’s how:

Figure 12. Command Line
1 git push -u origin main

The command above instructs Git to push the .git directory of your local main branch to the remote origin branch on GitHub.

An icon of a info-circle1

Refreshing your remote repository’s page should now reflect your upload.

The next step is to set up the project with TypeScript. So, let’s do that now.

9. Installing TypeScript

Install TypeScript as a dev-dependency:

Figure 13. Command Line
1 npm i -D typescript@5.9.3

The command above tells NPM to install typescript as your package’s dev-dependency.

An icon of a info-circle1
  • The typescript package is a library containing TypeScript’s core functionality for type-checking and compiling your TypeScript and JavaScript code to the standard JavaScript version for any browser.
  • i is the shorthand notation for install.
  • The -D flag is the shorthand notation for --save-dev.
  • We installed typescript as dev-dependencies because you only need it for your package’s development and testing purposes. Users do not need it in production.

So, now that you’ve installed TypeScript, we can configure the TypeScript compiler.

10. Configuring the TypeScript Compiler

Developers use a tsconfig.json file to specify a project’s root directory and the options the compiler needs to compile the project’s files.

An icon of a key1

TypeScript treats the folder containing tsconfig.json as your project’s root.

tsconfig.json is the default TypeScript configuration file name, but you may use custom names such as tsconfig.custom.json or codesweetly-type-config.json. This is useful in NPM package development when different configurations are needed for build, test, or IDE purposes.

Navigate to your package’s root directory and create a root configuration file along with four custom configuration files:

Figure 14. Command Line
1 touch tsconfig.json tsconfig.base.json tsconfig.test.json tsconfig.cjs.json tsconfig.esm.json
  • tsconfig.base.json: A base configuration file having universal compiler options that other TypeScript configuration files can inherit through the extends property.
  • tsconfig.json: The project’s root configuration file for IDE tools like VSCode to use to provide IntelliSense and error checking while you work.
  • tsconfig.test.json: The configuration file containing the compiler options for test libraries, like Jest, to use during tests.
  • tsconfig.cjs.json: Used to configure TypeScript to output CommonJS (CJS) Module compilations.
  • tsconfig.esm.json: Used to configure TypeScript to output ECMAScript Module (ESM) compilations.

Open the newly created files and add the following configurations:

tsconfig.base.json

Figure 15. tsconfig.base.json
 1 {
 2   "compilerOptions": {
 3     "target": "es2018",
 4     "rewriteRelativeImportExtensions": true,
 5     "allowSyntheticDefaultImports": true,
 6     "esModuleInterop": true,
 7     "forceConsistentCasingInFileNames": true,
 8     "noEmitOnError": true,
 9     "noImplicitReturns": true,
10     "noUnusedLocals": true,
11     "noUnusedParameters": true,
12     "removeComments": true,
13     "skipLibCheck": true,
14     "strict": true
15   }
16 }
  • compilerOptions: specifies how TypeScript should compile the project.
  • target tells TypeScript the JavaScript version you want to compile your code into.
  • rewriteRelativeImportExtensions: rewrites TypeScript file extensions such as .ts, .tsx, .mts, and .cts in relative import paths to their JavaScript equivalent extensions in output files.
  • allowSyntheticDefaultImports tells TypeScript to allow you to declare default imports like import feature from "package" rather than import * as feature from "package" when the module you are importing does not have a default export.
  • esModuleInterop tells TypeScript to make its compiled code interoperable (compatible) between CommonJS and ES Modules codebases by creating namespace objects for all imports.
  • forceConsistentCasingInFileNames tells TypeScript to throw an error when a program tries to reference a file with a casing different from the file’s name. For instance, referencing a codesweetly.ts file with ./CodeSweetly.ts will throw an error.
  • noEmitOnError specifies that TypeScript should not emit any compiled code if errors exist in the TypeScript project.
  • noImplicitReturns tells TypeScript to issue an error if a function’s code path does not return a value.
  • noUnusedLocals tells TypeScript to issue an error if a codebase contains unused local variables.
  • noUnusedParameters tells TypeScript to issue an error if a function has unused parameters.
  • removeComments tells TypeScript to remove all comments when transpiling TypeScript files to JavaScript.
  • skipLibCheck specifies that TypeScript should not type-check declaration (.d.ts) files.
  • strict tells TypeScript to use “strict mode” to type-check your codebase.

tsconfig.json

Figure 16. tsconfig.json
1 {
2   "extends": "./tsconfig.base.json",
3   "compilerOptions": {
4     "module": "nodenext",
5     "moduleResolution": "nodenext",
6     "noEmit": true
7   }
8 }
  • extends: informs TypeScript to inherit the configurations in the ./tsconfig.base.json file.
  • module: specifies that TypeScript should use the file’s extension or the type field in the nearest package.json file to determine the syntax of the compiled file (.mts or modules for ESM output and .cts or commonjs for CJS output).
  • moduleResolution: tells TypeScript to use the latest Node.js module resolution strategy to resolve (locate) the modules you import into your TypeScript files.
  • noEmit: tells TypeScript not to output any file. It should only type check and report errors.

tsconfig.test.json

Figure 17. tsconfig.test.json
1 {
2   "extends": "./tsconfig.base.json",
3   "compilerOptions": {
4     "module": "commonjs",
5     "moduleResolution": "node10",
6     "noEmit": true,
7     "isolatedModules": true
8   }
9 }
  • extends: informs TypeScript to inherit the configurations in the ./tsconfig.base.json file.
  • module: specifies that TypeScript should use the CommonJS module syntax in the compiled file.
  • moduleResolution: tells TypeScript to use the standard (loose) Node.js module resolution strategy of versions greater than 10 to resolve (locate) the modules you import into your TypeScript files. This lets the resolver find files automatically, even when the imports lack file extensions.
  • noEmit: tells TypeScript not to output any file. It should only type check and report errors.
  • isolatedModules: tells TypeScript to transpile each file at a time rather than perform cross-file analysis. This prevents program-wide module resolution conflicts by ensuring TypeScript just transpiles the file and leaves Jest to resolve the module import statements.

tsconfig.cjs.json

Figure 18. tsconfig.cjs.json
1 {
2   "extends": "./tsconfig.base.json",
3   "compilerOptions": {
4     "module": "commonjs",
5     "moduleResolution": "node10",
6     "outDir": "dist/cjs",
7     "declaration": false
8   }
9 }
  • extends: informs TypeScript to inherit the configurations in the ./tsconfig.base.json file.
  • module: specifies that TypeScript should use the CommonJS module syntax in the compiled file.
  • moduleResolution: tells TypeScript to use the standard (loose) Node.js module resolution strategy of versions greater than 10 to resolve (locate) the modules you import into your TypeScript files. This lets the resolver find files automatically, even when the imports lack file extensions.
  • outDir: tells TypeScript to emit its CommonJS transpiled files into the dist/cjs folder.
  • declaration: prevents TypeScript from generating d.ts type declaration files.

tsconfig.esm.json

Figure 19. tsconfig.esm.json
 1 {
 2   "extends": "./tsconfig.base.json",
 3   "compilerOptions": {
 4     "module": "es2020",
 5     "moduleResolution": "bundler",
 6     "outDir": "dist/esm",
 7     "declaration": true,
 8     "declarationDir": "dist/esm"
 9   }
10 }
  • extends: informs TypeScript to inherit the configurations in the ./tsconfig.base.json file.
  • module: specifies that TypeScript should use the ES2020 module syntax in the compiled file.
  • moduleResolution: tells TypeScript to use the bundler-compatible module resolution strategy to resolve (locate) the modules you import into your TypeScript files. The bundler mode is best for frontend libraries that bundlers like Vite, Webpack, and Rollup will consume.
  • outDir: tells TypeScript to emit its ECMAScript Module (ESM) transpiled files into the dist/esm folder.
  • declaration: tells TypeScript to generate d.ts type declaration files from your package’s TypeScript and JavaScript files.
  • declarationDir: tells TypeScript to emit its d.ts type declaration files into the dist/esm folder.

Stage and commit your changes:

Figure 20. Command Line
1 git add -A && git commit -m "Configure the typescript compiler"

After configuring the TypeScript compiler, continue to the next chapter to learn how to write a test case for your component.