I recently decided to publish . I wrote it in and went with for bundling. It was my first time publishing a module and my first experience with Rollup, so I’d like to write a tutorial on how to do it, both as a reference for myself and for anyone who may find this useful. Let’s get started! an NPM module TypeScript Rollup Why TypeScript and Rollup I went with TypeScript for several reasons. It’s what I use at work, so I’m not only familiar with it, but it’s always good to hone my skills, especially since I’m not necessarily a TypeScript expert (yet). I’m also a fan of types for a number of reasons, and compile-time errors are invaluable. . I also believe all JS libraries should be authored in TypeScript As for Rollup, I mostly went with it because I had never used it and have heard good things about it. Not only that, but I know that a number of open-source projects use it over Webpack. I also read about the differences between the two and why Rollup is better for building libraries. this great post Prerequisites I’m going to be using , but you can use if you wish! yarn npm First, let’s create our inside the project directory. Fill out everything as you wish, or just hit at every step if you don’t care yet. You can always edit these later. package.json Enter $ yarn init First, let’s install TypeScript and Rollup inside the project directory, as well as a plugin to allow Rollup to compile TypeScript as part of its bundling process. $ yarn --dev add typescript rollup rollup-plugin-typescript2 The original appears to be unmaintained, which is why we’re using this one instead. Note: rollup-plugin-typescript At this point, your should look like this: package.json something {"name": "some-project","version": "1.0.0","main": "index.js","author": "John Doe <jdoe >","license": "MIT","devDependencies": {"rollup": "^0.62.0","rollup-plugin-typescript2": "^0.15.1","typescript": "^2.9.2"}} @example.com Let’s add a few extra lines to the file and replace the default for : main {"name": "some-project","version": "1.0.0", "main": "dist/index.js","module": "dist/index.es.js","files": ["dist"],"types": "dist/index.d.ts","scripts": {"build": "rollup -c","watch": "rollup -cw"}, "author": "John Doe <jdoe >","license": "MIT","devDependencies": {"rollup": "^0.62.0","rollup-plugin-typescript2": "^0.15.1","typescript": "^2.9.2"}} @example.com Here’s what’s going on: and point to the bundled JavaScript so that the library consumer may import the module. is for the CommonJS module, and is for the ES module. You don’t need to understand the details of that for now, though! main module main module lets / know what to publish, or rather what gets installed inside a user’s when they install your module. For now, let’s just do , which will contain our bundled JS. files npm yarn node_modules dist points to our TypeScript declaration file. This will get compiled automatically for us (more on that below). types just has some handy Rollup scripts, which you can use during development. will bundle the module once, while will build it every time a file changes. scripts yarn run build yarn run watch Now we’re ready for some configuration! TypeScript configuration In order to configure TypeScript, we need to create a file. There are , but the following ones will be good enough for now. I encourage you to dive deeper into the options if you find yourself unsatisfied with how something is working! tsconfig.json more options than we can go over Copy the following into in the root directory of your project. tsconfig.json {"compilerOptions": {"declaration": true,"declarationDir": "./dist","module": "es6","noImplicitAny": true,"outDir": "./dist","target": "es5"},"include": ["src/**/*"],"exclude": ["node_modules"]} What’s going on: is there to enable automatic generating of TypeScript’s . These are helpful for TypeScript users who are using your module, since they’ll have access to all the types of your module’s methods, variables, etc. "declaration": true declaration files and specify where the compiled code will go. I’m using , but you may choose another name such as . If you choose a different directory name, make sure to use that name in your as well! declarationDir outDir ./dist ./lib package.json forces us to be a bit stricter with types. By default, TypeScript allows you to get away with not assigning types to variables whose types cannot be . This option makes it so that if we want something to use the type , it must be done explicitly. "noImplicitAny": true inferred any allows us to specify which version of JavaScript to compile our TypeScript to. In this case, I’m choosing ES5. target allows us to specify where TypeScript should look for , , and files to compile. include .ts .d.ts .tsx allows us to specify directories for TypeScript to ignore when it comes to compiling. exclude Rollup configuration Next, we’ll configure Rollup. In the root directory of your project, create a file called . Next, copy this into there: rollup.config.js import typescript from 'rollup-plugin-typescript2' import pkg from './package.json' export default {input: 'src/index.ts',output: [{file: pkg.main,format: 'cjs',},{file: pkg.module,format: 'es',},],external: [...Object.keys(pkg.dependencies || {}),...Object.keys(pkg.peerDependencies || {}),], plugins: [typescript({typescript: require('typescript'),}),],} The first thing to note is that we’re importing . This isn’t necessary, but it’s a handy way to make sure you aren’t duplicating certain information, such as the filename of your bundle. Here’s a breakdown of what’s going on: package.json tells Rollup where to look for code to bundle. This is similar to Webpack’s . input entry is where our bundle gets stored. As stated earlier, we’re going to bundle both CommonJS ( ) and ES ( ) modules. has a pretty good explanation of the differences if you’re interested. output cjs es Rollup’s documentation is what we use to tell Rollup what modules to exclude from our bundle. Since will get installed by the module consumer’s or , and since are expected to be installed by the consumer, we can safely exclude those from the bundle. external pkg.dependencies yarn npm pkg.peerDependencies The section is a bit weird. What we’re doing there is making use the locally-installed TypeScript. By default, it uses a version that likely isn’t up-to-date. There are a bunch of other plugins we could install, but this is fine for now! plugins rollup-plugin-typescript2 Publishing to NPM In order to publish the module, we first need to log into NPM. If you don’t have an account, . You’ll only need to do this once on your machine. For some reason, didn’t work for me, so I’m going to use for this: go create one now yarn login npm login $ npm login Username: yourusernamePassword:Email: (this IS public) Logged in as yourusername on . email@example.com https://registry.npmjs.org/ Next, let’s create a tiny module to publish. Create a directory, and inside there, an file: src index.ts // src/index.ts export const greet = () => console.log('Hello, world!') After that, run the command to compile the TypeScript: build $ yarn run build yarn run v1.3.2$ rollup -c src/index.ts → dist/index.js, dist/index.es.js...created dist/index.js, dist/index.es.js in 522ms✨ Done in 0.91s. You’ll notice a folder was created with three files in it. Feel free to check those out! dist Finally, we can publish the module to NPM: $ yarn publish yarn publish v1.3.2[1/4] Bumping version...info Current version: 0.0.1question New version:[2/4] Logging in...[3/4] Publishing...success Published.[4/4] Revoking token...info Not revoking login token, specified via config file.✨ Done in 1.85s. And that’s it! You’ve successfully published a module to NPM using TypeScript and Rollup. To verify that everything looks good, create another directory somewhere else on your computer and run , then . If you navigate to , you should see the folder with all the compiled files in there! You can then import your module like so: yarn init yarn add your-package-name node_modules/your-package-name dist import { greet } from 'your-package-name' Developing locally As you can imagine, it would be pretty annoying and hacky to publish your package every time you wanted to test it out. While writing automated tests helps a lot in this regard, sometimes you’ll need to actually use your module to make sure that it works properly before publishing it. For this, we can use (or , of course). yarn link npm link First, navigate to your module’s project directory and run the following: $ yarn link Next, navigate to the project where you’d like to consume this module. Make sure that the module is not installed via or , then run: yarn npm $ yarn link your-package-name This will create a to your package folder inside your project’s directory. Essentially, you’ll be able to use the local version of your package the same way you’d be able to use it if you had it published and downloaded/installed via or ! symbolic link node_modules yarn add npm install Thanks for reading If you’ve made it this far, congratulations on publishing something to NPM! I hope you enjoyed this tutorial. If I made any mistakes or if anything needs clarification, please don’t hesitate to . I’d like to contribute more to NPM going forward, so I’ll try to keep this tutorial as up-to-date as I can. reach out