Create a new directory for your project and initialize it with npm:
mkdir my-package
cd my-package
npm init -y
We will need a variety of development dependencies for our project. Here's a breakdown of what we need:
- Rollup: Bundler to compile our code into different module formats.
- TypeScript: To write strongly-typed JavaScript.
- Babel: To transpile modern JavaScript for compatibility with older environments.
- Rollup Plugins: To handle TypeScript, Babel, resolving node modules, and cleaning up dist directories.
Install them by running:
npm install --save-dev @babel/core @babel/plugin-transform-runtime @babel/preset-env @rollup/plugin-babel @rollup/plugin-commonjs @rollup/plugin-node-resolve @types/jest @typescript-eslint/parser eslint jest rollup rollup-plugin-clear rollup-plugin-copy rollup-plugin-terser rollup-plugin-typescript2 ts-jest typescript
We will bundle our code in three formats: IIFE (for browsers), CJS (for Node.js), and ESM (for modern JavaScript bundlers). Here’s the configuration:
// [Why use babel with rollup?](https://rollupjs.org/tools/#babel)
import babel from '@rollup/plugin-babel' // Transpiles modern JavaScript code
import { nodeResolve } from '@rollup/plugin-node-resolve' // Allows Rollup to resolve modules from node_modules
import commonjs from '@rollup/plugin-commonjs' // Converts CommonJS modules to ES6, allowing them to be included in the bundle.
import { terser } from 'rollup-plugin-terser' // Minifies the final output
import clear from 'rollup-plugin-clear' // Cleans the `dist` folder before each build
import typescript from 'rollup-plugin-typescript2' // Compiles TypeScript files
import copy from 'rollup-plugin-copy' // Copy essential files
import path from 'path'; // Path declaration
export default [{
// IIFE Bundle Configuration
input: 'src/index.ts', // Entry point of the library
output: [
{
file: 'dist/iife/geo-polyline-tools.js', // Output bundle file
format: 'iife', // Format for browser global usage (Immediately Invoked Function Expression)
name: 'myPackage', // Global variable name for browser usage
sourcemap: true // Enable sourcemap for debugging
}
],
plugins: [
clear({ targets: ['dist/iife'] }), // Clear previous output in the dist/iife folder
nodeResolve(), // Allow bundling third-party modules
commonjs(), // Convert CommonJS modules to ES6
typescript({
tsconfig: path.resolve(__dirname, './tsconfig.json'), // Use TypeScript configuration
}),
babel({
exclude: 'node_modules/**', // Don't transpile node_modules
babelHelpers: 'bundled', // Use bundled babel helpers for efficiency
}),
terser(), // Minify the bundle for the browser
copy({
targets: [
{ src: 'types/index.d.ts', dest: 'dist/iife' } // Copy TypeScript types to output folder
]
})
],
},
{
// CJS & ESM Bundle Configuration
input: 'src/index.ts', // Entry point for CommonJS and ESM builds
output: [
{
dir: 'dist/cjs', // Output directory for CommonJS format
format: 'cjs', // CommonJS format (for Node.js)
preserveModules: true, // Keep the original module structure
exports: 'auto', // Auto-detect export style
sourcemap: true // Enable sourcemap
},
{
dir: 'dist/esm', // Output directory for ESM format
format: 'es', // ES Module format
preserveModules: true, // Keep the original module structure
exports: 'auto', // Auto-detect export style
sourcemap: true // Enable sourcemap
}
],
plugins: [
clear({ targets: ['dist/cjs', 'dist/esm'] }),
nodeResolve(),
commonjs(),
typescript({
tsconfig: path.resolve(__dirname, './tsconfig.json'),
}),
babel({
exclude: 'node_modules/**',
babelHelpers: 'runtime',
plugins: ['@babel/plugin-transform-runtime']
}),
terser(),
copy({
targets: [
{ src: 'types/index.d.ts', dest: 'dist/cjs' }, // Copy TypeScript types to CJS
{ src: 'types/index.d.ts', dest: 'dist/esm' } // Copy TypeScript types to ESM
]
})
]
}
];
{
"compilerOptions": {
"target": "ES5", // Target ECMAScript 5 for compatibility
"module": "ESNext", // Use the latest ECMAScript module system
"declaration": true, // Generate TypeScript declaration files (.d.ts)
"declarationDir": "types/index.d.ts", // Specify where to output type declarations
"rootDir": "src", // Root directory for source files
"strict": true, // Enable strict type checking
"esModuleInterop": true, // Compatibility for ES module imports
"moduleResolution": "node", // Resolve modules like Node.js does
"sourceMap": true, // Generate sourcemap files for debugging
"skipLibCheck": true, // Skip type checking for libraries
"forceConsistentCasingInFileNames": true, // Enforce consistent file name casing
"allowSyntheticDefaultImports": true, // Allow default imports from modules without default exports
"typeRoots": [
"./node_modules/@types", // Look for types in node_modules/@types
"types/index.d.ts" // Look for custom types in the specified folder
]
},
"include": [
"src/**/*.ts", // Include all TypeScript files in the src directory
"types/**/*" // Include custom types from the types folder
],
"exclude": [
"node_modules", // Exclude node_modules from compilation
"dist" // Exclude the dist folder from compilation
]
}
Create index.d.ts
file which contains the TypeScript type definitions for your my-package
library
{
"presets": [
"@babel/preset-env"
]
}
{
"env": {
"browser": true,
"es6": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"parser": "@typescript-eslint/parser",
"plugins": [
"@typescript-eslint"
],
"parserOptions": {
"ecmaVersion": 2020,
"sourceType": "module"
},
"rules": {
"@typescript-eslint/ban-ts-comment": "off",
"indent": [
"error",
4
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"single"
],
"semi": [
"error",
"always"
],
"@typescript-eslint/no-unnecessary-type-constraint": "off"
},
"overrides": [
{
"files": "*.ts",
"rules": {
"@typescript-eslint/no-unused-vars": "warn"
}
}
]
}
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testMatch: ['**/__tests__/**/*.ts', '**/?(*.)+(spec|test).ts'],
};
Create index.test.ts
file inside __test__
directory in your root and write test cases
{
"name": "my-package",
"version": "1.0.0",
"description": "",
"author": "username",
"license": "MIT",
"main": "dist/cjs/index.js", // Entry point for CommonJS modules
"typings": "dist/cjs/index.d.ts", // TypeScript type definitions for CommonJS modules
"module": "dist/esm/index.js", // Entry point for ES modules
"types": "dist/esm/index.d.ts", // TypeScript type definitions for ES modules
"files": [
"src",
"dist",
"README.md"
],
"keywords": ["my-package"],
"repository": {
"type": "git",
"url": "https://github.com/username/my-package.git"
},
"scripts": {
"test": "jest",
"build": "rollup -c",
"lint": "eslint 'src/**/*.{ts}'"
"lint:fix": "eslint 'src/**/*.{ts}' --fix"
},
"devDependencies": {
// List of development dependencies...
}
}
Run the tests using:
npm test
npm run build
This will generate your package in the dist/
folder with the iife
, cjs
, and esm
formats including index.d.ts
file
Finally, to publish your package to npm:
- Log in to your npm account (if not already logged in):
npm login
- Publish the package:
npm publish
Note: Make sure the version
in your package.json
is updated for each new release.