What's your way of publishing Node.js library for the browser? (also, introducing Rollup)
Tags: discuss, webdev, javascript, typescript
Published: 2020-02-23 10:28:18

- Do you attach to `window` object, or is there a better alternative?
  - How many namespaces do you usually attach?
  - How do you maintain both browser version and bundler version?
- Do you require your library users to use a bundler or Node.js, for simplicity's sake?
- If you bundle for library users, which bundler do you use?
- How many percentage of browsers do you support? Which ES version?

BTW, I have just started using Rollup to bundle TypeScript for [`<script type="module">`](https://stackoverflow.com/a/53821485/9023855), so that I don't have to attach to `window` object.

- [Webpack just couldn't target ESM](https://github.com/webpack/webpack/issues/8010)
- Bundled ESM might also be usable in [Deno](https://deno.land/).
- [Output of non-minified Rollup](https://unpkg.com/browse/any-serialize@1.4.12/lib/index.mjs) is readable. Webpack is not, and is full of eval. (Even minified version of Rollup is relative readable as well.)
- `tsconfig.json` uses `"module": "commonjs"` (so that I can run `ts-node`, `ts-mocha` and publish for Node, without [esm](https://www.npmjs.com/package/esm)), but `rollup.config.js` uses `esnext`.
  - I also use `tsc` to build for Node. Rollup just cannot properly do it. And Rollup cannot generate `declaration` and [`declarationMap`](https://stackoverflow.com/questions/58459988/what-is-the-use-case-of-enabling-declaration-and-declarationmap-in-tsconfig-json)

```javascript
// rollup.config.js

import typescript from '@rollup/plugin-typescript'
import minify from 'rollup-plugin-babel-minify'

const getConfig = ({ output, isMinify }) => {
  return {
    input: 'src/index.ts',
    output: {
      file: output,
      format: 'esm',
      sourcemap: true
    },
    plugins: [
      typescript({
        module: 'esnext'
      }),
      ...(isMinify ? [
        minify({
          comments: false
        })
      ] : [])
    ]
  }
}

export default [
  getConfig({ output: 'lib/index.mjs' }),
  getConfig({ output: 'lib/index.min.mjs', isMinify: true })
]
```

- If you wonder about `package.json`, it is

```json
{
  "main": "lib/index.js",
  "module": "lib/index.mjs",
  "unpkg": "lib/index.min.mjs",
  "types": "lib/index.d.ts",
  "files": [
    "lib",
    "src"
  ],
  "scripts": {
    "build": "rimraf lib && rollup -c && yarn tsc",
    "tsc": "tsc -P src/tsconfig.json",
    "prepack": "yarn build && yarn deploy"
  }
}
```

- And `tsconfig.json`

```json
{
  "compilerOptions": {
    "target": "ES2017",
    "module": "commonjs",
    "declaration": true,
    "declarationMap": true,
  }
}
```

- Generated files can be viewed here -- <https://unpkg.com/any-serialize/>. As you can see [index.mjs](https://unpkg.com/browse/any-serialize@1.4.12/lib/index.mjs) is so nice to read. And there is no `require()` or importing from node_modules.

{% github patarapolw/any-serialize no-readme %}

Features are

- Serialize anything.
- Deserialize almost anything, but if you tweak a little, you can make it work with anything as well.
- Hash anything to string.
- Clone anything.
- No external dependencies, and highly customizable.