Project Configuration
The following outlines the necessary system and file configurations for creating NPM packages.
1. Set Up Your System
Ensure your system includes the following installations:
- Git
- Node 22.13 (or greater)
- NPM 10.9 (or greater)
![]() |
|
2. Create a Project Directory
Create a new folder for your project as follows:
1 mkdir thank-you-tweet-button-001
![]() |
You may use any name. For example, this tutorial uses |
![]() |
|
Next, navigate to your project directory using the command line.
1 cd path/to/thank-you-tweet-button-001
3. Create a package.json File
Use NPM to initialize a package.json file for your project.
1 npm init -y
You should also initialize Git at this stage.
4. Initialize a Git Repository
Create a .git repository in your project’s root directory:
1 git init
5. Specify the Files Git Should Ignore
Create a .gitignore file in your project’s root directory:
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:
1 /node_modules
2 /dist
The snippet above instructs Git to ignore tracking the current directory’s node_modules and dist folders.
![]() |
|
Now, stage and commit your recent changes.
6. Stage and Commit Your Project’s Changes to Git
Run the following command in your terminal to stage and commit your recent changes.
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.
Next, configure a remote repository for the project.
7. Configure a GitHub Remote Repository
- Go to the GitHub website and sign in or create an account if you do not have one.
- After signing in, create a new GitHub repository. You may use
thank-you-tweet-button-001or another name of your choice. - Once you’ve created a remote repository for your package, link your project’s
.gitdirectory (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 thegit remote addcommand. Here’s the syntax:
1 git remote add origin https://github.com/your-username/remote-repo-name.git
![]() |
|
You can also add the remote repo to your package.json file for easy access to people who want to contribute to your project.
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:
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:
1 git add -A && git commit -m "Create repository and bugs fields"
Next, push your local Git repository to the remote repository.
8. Push 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 to the remote repository. Here’s how:
1 git push -u origin main
The command above instructs Git to push your local main branch’s .git directory to the remote origin branch on GitHub.
![]() |
If you refresh the main page of your remote repository, you should see your upload. |
Now it’s time to set up your project with React and TypeScript.
9. Install React and TypeScript
Install React and TypeScript as development dependencies:
1 npm i -D react@19.2.3 typescript@5.9.3 @types/react@19.2.13
The command above tells NPM to install react, typescript, and @types/react as your package’s development dependencies.
We installed typescript and @types/react as dev-dependencies because you only need them for your package’s development and testing purposes. Users do not need them in production.
You may wonder why React is installed as a development dependency if users need it in production. The following explains the reasoning.
Why Install React as a Package’s Dev-Dependency?
Installing React as a development dependency prevents users from being required to download React when installing your package.
React requires only one copy of the react package per project. Therefore, specifying React as a dev-dependency prevents users from having to download React when installing your package. If their project already has a React copy, they wouldn’t need to install another one.
One thing to note: your package will only work in projects that already have React installed. But there’s a good workaround:
- Duplicate the
"react"property from your package.json"devDependencies"field into the"peerDependencies"field as shown:
1 {
2 "devDependencies": {
3 "react": "^19.2.3"
4 },
5 "peerDependencies": {
6 "react": "^19.2.3"
7 }
8 }
Specifying React as a peer dependency tells package managers to check whether the app installing your package includes the listed peerDependencies. If so, the application has the dependencies your package needs to work.
If the package manager cannot find the peerDependencies, some NPM versions (such as 7 and 11) will install them automatically. Other versions (such as 3-6) will display a warning that informs the user to install the dependencies manually.
Stage and commit your changes:
1 git add -A && git commit -m "Install react and typescript"
After installing React and TypeScript, proceed to configure the TypeScript compiler.
10. Configure 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.
![]() |
TypeScript treats the folder containing |
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:
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 theextendsproperty.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
1 {
2 "compilerOptions": {
3 "jsx": "react-jsx",
4 "target": "es2018",
5 "rewriteRelativeImportExtensions": true,
6 "allowSyntheticDefaultImports": true,
7 "esModuleInterop": true,
8 "forceConsistentCasingInFileNames": true,
9 "noEmitOnError": true,
10 "noImplicitReturns": true,
11 "noUnusedLocals": true,
12 "noUnusedParameters": true,
13 "removeComments": true,
14 "skipLibCheck": true,
15 "strict": true
16 }
17 }
compilerOptions: specifies how TypeScript should compile the project.jsx: specifies how TypeScript should compile the JSX syntax in.tsxfiles to plain JavaScript. (The “react-jsx” value means TypeScript should change JSX syntaxes to_jsxcalls that are optimized for production. This allows you to use JSX without explicitly includingimport React from "react"in every file.)targettells TypeScript the JavaScript version you want to compile your code into.rewriteRelativeImportExtensions: rewrites TypeScript file extensions such as.ts,.tsx,.mts, and.ctsin relativeimportpaths to their JavaScript equivalent extensions in output files.allowSyntheticDefaultImportstells TypeScript to allow you to declare default imports likeimport Feature from "package"rather thanimport * as Feature from "package"when the module you are importing does not have a default export.esModuleInteroptells TypeScript to make its compiled code interoperable (compatible) between CommonJS and ES Modules codebases by creating namespace objects for all imports.forceConsistentCasingInFileNamestells 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 acodesweetly.tsfile with./CodeSweetly.tswill throw an error.noEmitOnErrorspecifies that TypeScript should not emit any compiled code if errors exist in the TypeScript project.noImplicitReturnstells TypeScript to issue an error if a function’s code path does not return a value.noUnusedLocalstells TypeScript to issue an error if a codebase contains unused local variables.noUnusedParameterstells TypeScript to issue an error if a function has unused parameters.removeCommentstells TypeScript to remove all comments when transpiling TypeScript files to JavaScript.skipLibCheckspecifies that TypeScript should not type-check declaration (.d.ts) files.stricttells TypeScript to use “strict mode” to type-check your codebase.
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.jsonfile.module: specifies that TypeScript should use the file’s extension or thetypefield in the nearestpackage.jsonfile to determine the syntax of the compiled file (.mtsormodulesfor ESM output and.ctsorcommonjsfor 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
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.jsonfile.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
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.jsonfile.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 thedist/cjsfolder.declaration: prevents TypeScript from generatingd.tstype declaration files.
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.jsonfile.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. Thebundlermode 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 thedist/esmfolder.declaration: tells TypeScript to generated.tstype declaration files from your package’s TypeScript and JavaScript files.declarationDir: tells TypeScript to emit itsd.tstype declaration files into thedist/esmfolder.
Stage and commit your changes:
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.

